From 1458ba438e9040409799e62be97f0fa26880b140 Mon Sep 17 00:00:00 2001 From: enos Date: Wed, 18 Mar 2026 14:09:49 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20Add=20BCrypt=20hashing=20transformer=20?= =?UTF-8?q?Adds=20a=20BCryptTransformer=20tool=20to=20the=20cryptography?= =?UTF-8?q?=20group,=20allowing=20users=20to=20hash=20passwords=20with=20a?= =?UTF-8?q?=20configurable=20cost=20factor=20(4=E2=80=9320)=20via=20the=20?= =?UTF-8?q?BCrypt=20library=20already=20present=20in=20the=20build.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle/libs.versions.toml | 2 + modules/tools/ui/build.gradle.kts | 1 + .../tool/ui/transformer/BCryptTransformer.kt | 73 +++++++++++++++++++ src/main/resources/META-INF/plugin.xml | 4 + 4 files changed, 80 insertions(+) create mode 100644 modules/tools/ui/src/main/kotlin/dev/turingcomplete/intellijdevelopertoolsplugin/tool/ui/transformer/BCryptTransformer.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index aa8dad3..891b7f1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,6 @@ [versions] assertj = "3.27.3" +bcrypt = "0.10.2" changelog = "2.2.1" commons-codec = "1.18.0" commons-compress = "1.27.1" @@ -31,6 +32,7 @@ zxing = "3.5.3" [libraries] assertj-core = { module = "org.assertj:assertj-core", version.ref = "assertj" } +bcrypt = { module = "at.favre.lib:bcrypt", version.ref = "bcrypt" } commons-codec = { module = "commons-codec:commons-codec", version.ref = "commons-codec" } commons-compress = { module = "org.apache.commons:commons-compress", version.ref = "commons-compress" } commons-csv = { module = "org.apache.commons:commons-csv", version.ref = "commons-csv" } diff --git a/modules/tools/ui/build.gradle.kts b/modules/tools/ui/build.gradle.kts index 3490731..7ed07f8 100644 --- a/modules/tools/ui/build.gradle.kts +++ b/modules/tools/ui/build.gradle.kts @@ -30,6 +30,7 @@ dependencies { implementation(libs.jnanoid) implementation(libs.uuid.generator) implementation(libs.cronutils) + implementation(libs.bcrypt) testImplementation(libs.assertj.core) testImplementation(libs.bundles.junit.implementation) diff --git a/modules/tools/ui/src/main/kotlin/dev/turingcomplete/intellijdevelopertoolsplugin/tool/ui/transformer/BCryptTransformer.kt b/modules/tools/ui/src/main/kotlin/dev/turingcomplete/intellijdevelopertoolsplugin/tool/ui/transformer/BCryptTransformer.kt new file mode 100644 index 0000000..379981b --- /dev/null +++ b/modules/tools/ui/src/main/kotlin/dev/turingcomplete/intellijdevelopertoolsplugin/tool/ui/transformer/BCryptTransformer.kt @@ -0,0 +1,73 @@ +package dev.turingcomplete.intellijdevelopertoolsplugin.tool.ui.transformer + +import at.favre.lib.crypto.bcrypt.BCrypt +import com.intellij.openapi.Disposable +import com.intellij.openapi.project.Project +import com.intellij.ui.dsl.builder.Panel +import com.intellij.ui.dsl.builder.bindItem +import dev.turingcomplete.intellijdevelopertoolsplugin.settings.DeveloperToolConfiguration +import dev.turingcomplete.intellijdevelopertoolsplugin.tool.ui.base.DeveloperUiToolContext +import dev.turingcomplete.intellijdevelopertoolsplugin.tool.ui.base.DeveloperUiToolFactory +import dev.turingcomplete.intellijdevelopertoolsplugin.tool.ui.base.DeveloperUiToolPresentation +import dev.turingcomplete.intellijdevelopertoolsplugin.tool.ui.converter.base.UndirectionalConverter + +class BCryptTransformer( + context: DeveloperUiToolContext, + configuration: DeveloperToolConfiguration, + parentDisposable: Disposable, + project: Project?, +) : + UndirectionalConverter( + context = context, + configuration = configuration, + parentDisposable = parentDisposable, + project = project, + title = "BCrypt", + sourceTitle = "Password", + targetTitle = "Hash", + toTargetTitle = "Generate", + ) { + // -- Properties ---------------------------------------------------------- // + + private val selectedCost = configuration.register("cost", DEFAULT_COST) + + // -- Initialization ------------------------------------------------------ // + // -- Exposed Methods ----------------------------------------------------- // + + override fun requestLiveConversion() {} + + override fun doConvertToTarget(source: ByteArray): ByteArray { + val password = String(source, Charsets.UTF_8).toCharArray() + return BCrypt.withDefaults() + .hashToString(selectedCost.get(), password) + .toByteArray(Charsets.UTF_8) + } + + override fun Panel.buildSourceTopConfigurationUi() { + row { comboBox(COST_RANGE.toList()).label("Cost:").bindItem(selectedCost) } + } + + // -- Private Methods ----------------------------------------------------- // + // -- Inner Type ---------------------------------------------------------- // + + class Factory : DeveloperUiToolFactory { + + override fun getDeveloperUiToolPresentation() = + DeveloperUiToolPresentation(menuTitle = "BCrypt", contentTitle = "BCrypt Transformer") + + override fun getDeveloperUiToolCreator( + project: Project?, + parentDisposable: Disposable, + context: DeveloperUiToolContext, + ): ((DeveloperToolConfiguration) -> BCryptTransformer) = { configuration -> + BCryptTransformer(context, configuration, parentDisposable, project) + } + } + + // -- Companion Object ---------------------------------------------------- // + + companion object { + private const val DEFAULT_COST = 12 + private val COST_RANGE = 4..20 + } +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 2b9b468..64e3ce0 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -219,6 +219,10 @@ id="hmac-transformer" groupId="cryptography" implementationClass="dev.turingcomplete.intellijdevelopertoolsplugin.tool.ui.transformer.HmacTransformer$Factory"/> +