From 85ea7dc2ad861ba12fc9682de8ac829fd126ff11 Mon Sep 17 00:00:00 2001 From: Benjamin AIMONE Date: Tue, 27 Sep 2022 15:48:27 +0200 Subject: [PATCH] Fix JNI conversion for key names --- CHANGELOG.md | 5 + build.gradle.kts | 7 +- settings.gradle.kts | 2 +- .../com/klaxit/hiddensecrets/CodeGenerator.kt | 2 +- .../hiddensecrets/HiddenSecretsPlugin.kt | 8 +- .../kotlin/com/klaxit/hiddensecrets/Utils.kt | 6 +- src/test/kotlin/IntegrationTest.kt | 108 ++++++++++++++++++ src/test/kotlin/UtilsTest.kt | 8 +- 8 files changed, 131 insertions(+), 15 deletions(-) create mode 100644 src/test/kotlin/IntegrationTest.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index bea4b9f..01812d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 0.2.1 +### Fixes +* Convert key names to C++ style to avoid `No implementation found` error +#### Contributors +@pratclot # 0.2.0 ### Improvements * Ability to re-generate secrets from .properties file diff --git a/build.gradle.kts b/build.gradle.kts index 4df9ad1..bf3b402 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("com.gradle.plugin-publish") version "0.21.0" + id("com.gradle.plugin-publish") version "1.0.0" id("io.gitlab.arturbosch.detekt") version "1.19.0" `kotlin-dsl` `maven-publish` @@ -14,8 +14,9 @@ repositories { dependencies { implementation("com.android.tools.build:gradle:4.2.2") - testImplementation("io.kotest:kotest-runner-junit5-jvm:5.2.2") - testImplementation("io.kotest:kotest-assertions-core-jvm:5.2.2") + testImplementation("io.kotest:kotest-runner-junit5-jvm:5.4.2") + testImplementation("io.kotest:kotest-assertions-core-jvm:5.4.2") + testImplementation("io.kotest:kotest-framework-datatest-jvm:5.4.2") testImplementation("junit:junit:4.13.2") } diff --git a/settings.gradle.kts b/settings.gradle.kts index e2236bb..379eb4c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,5 +2,5 @@ rootProject.name = "HiddenSecretsPlugin" gradle.allprojects { group = "com.klaxit.hiddensecrets" - version = "0.2.0" + version = "0.2.1" } \ No newline at end of file diff --git a/src/main/kotlin/com/klaxit/hiddensecrets/CodeGenerator.kt b/src/main/kotlin/com/klaxit/hiddensecrets/CodeGenerator.kt index 1ab7ff8..eb36ae7 100644 --- a/src/main/kotlin/com/klaxit/hiddensecrets/CodeGenerator.kt +++ b/src/main/kotlin/com/klaxit/hiddensecrets/CodeGenerator.kt @@ -12,7 +12,7 @@ object CodeGenerator { return "\nextern \"C\"\n" + "JNIEXPORT jstring JNICALL\n" + - "Java_" + Utils.getCppPackageName(packageName) + "_Secrets_get$keyName(\n" + + "Java_" + Utils.getCppName(packageName) + "_Secrets_get$keyName(\n" + " JNIEnv* pEnv,\n" + " jobject pThis,\n" + " jstring packageName) {\n" + diff --git a/src/main/kotlin/com/klaxit/hiddensecrets/HiddenSecretsPlugin.kt b/src/main/kotlin/com/klaxit/hiddensecrets/HiddenSecretsPlugin.kt index c94e5db..fe2ab3b 100644 --- a/src/main/kotlin/com/klaxit/hiddensecrets/HiddenSecretsPlugin.kt +++ b/src/main/kotlin/com/klaxit/hiddensecrets/HiddenSecretsPlugin.kt @@ -295,18 +295,20 @@ open class HiddenSecretsPlugin : Plugin { if (text.contains(obfuscatedKey)) { println("⚠️ Key already added in C++ !") } + // Escape required characters + val cppKeyName = Utils.getCppName(keyName) if (text.contains(KEY_PLACEHOLDER)) { // Edit placeholder key // Replace package name - text = text.replace(PACKAGE_PLACEHOLDER, Utils.getCppPackageName(kotlinPackage)) + text = text.replace(PACKAGE_PLACEHOLDER, Utils.getCppName(kotlinPackage)) // Replace key name - text = text.replace("YOUR_KEY_NAME_GOES_HERE", keyName) + text = text.replace("YOUR_KEY_NAME_GOES_HERE", cppKeyName) // Replace demo key text = text.replace(KEY_PLACEHOLDER, obfuscatedKey) secretsCpp.writeText(text) } else { // Add new key - text += CodeGenerator.getCppCode(kotlinPackage, keyName, obfuscatedKey) + text += CodeGenerator.getCppCode(kotlinPackage, cppKeyName, obfuscatedKey) secretsCpp.writeText(text) } } else { diff --git a/src/main/kotlin/com/klaxit/hiddensecrets/Utils.kt b/src/main/kotlin/com/klaxit/hiddensecrets/Utils.kt index 418d7ae..1c5fdb5 100644 --- a/src/main/kotlin/com/klaxit/hiddensecrets/Utils.kt +++ b/src/main/kotlin/com/klaxit/hiddensecrets/Utils.kt @@ -10,11 +10,11 @@ import kotlin.experimental.xor object Utils { /** - * Transform package name com.klaxit.hidden to com_klaxit_hidden to ingrate in C++ code - * Java package name needs to escape some characters to call the NDK + * Transform names like com.klaxit.hidden to com_klaxit_hidden to ingrate in C++ code. + * Java package name and key names needs to escape some characters to call the NDK. * From https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#resolving_native_method_names */ - fun getCppPackageName(packageName: String): String { + fun getCppName(packageName: String): String { return packageName .replace("_", "_1") .replace(";", "_2") diff --git a/src/test/kotlin/IntegrationTest.kt b/src/test/kotlin/IntegrationTest.kt new file mode 100644 index 0000000..fabf808 --- /dev/null +++ b/src/test/kotlin/IntegrationTest.kt @@ -0,0 +1,108 @@ +import com.klaxit.hiddensecrets.HiddenSecretsPlugin +import io.kotest.core.spec.style.WordSpec +import io.kotest.data.Row4 +import io.kotest.datatest.withData +import io.kotest.matchers.shouldBe +import org.gradle.testkit.runner.GradleRunner +import org.junit.rules.TemporaryFolder +import java.io.File + +/** + * Test that correct names of keys are present in java and cpp files. + * + * From @pratclot + * https://github.com/klaxit/hidden-secrets-gradle-plugin/pull/64 + */ +class IntegrationTest : WordSpec({ + + "Apply the plugin" should { + val testProjectDir = TemporaryFolder() + testProjectDir.create() + val buildFile = testProjectDir.newFile("build.gradle") + buildFile.appendText( + """ + plugins { + id 'com.klaxit.hiddensecrets' + id 'com.android.application' + } + android { + compileSdkVersion 29 + } + """.trimIndent() + ) + + val gradleRunner = GradleRunner.create() + .withPluginClasspath() + .withProjectDir(testProjectDir.root) + .withTestKitDir(testProjectDir.newFolder()) + + val test = this + "Make command ${HiddenSecretsPlugin.TASK_HIDE_SECRET} succeed" { + test.withData( + Row4("thisIsATestKey", "thisIsATestKeyName", "thisIsATestKeyName", "com.package.test"), + Row4( + "this_is_a_test_key", + "this_is_a_test_key_name", + "this_1is_1a_1test_1key_1name", + "com.package.test" + ), + ) { (key, keyName, cppKeyName, packageName) -> + testProjectDir.run { + val packagePath = packageName.replace('.', '/') + val packageDirJava = newFolder("src/main/java/$packagePath") + val packageDirCpp = newFolder("src/main/cpp/") + + val fileJava = File(packageDirJava, "Secrets.kt") + val fileCpp = File(packageDirCpp, "secrets.cpp") + + var inputStream = javaClass.classLoader.getResourceAsStream("kotlin/Secrets.kt") + inputStream?.bufferedReader()?.lines()?.forEach { + fileJava.appendText(it + "\n") + } + inputStream?.close() + + inputStream = javaClass.classLoader.getResourceAsStream("cpp/secrets.cpp") + inputStream?.bufferedReader()?.forEachLine { + fileCpp.appendText(it + "\n") + } + inputStream?.close() + + gradleRunner.withArguments() + val result = gradleRunner + .withArguments( + HiddenSecretsPlugin.TASK_HIDE_SECRET, + "-Pkey=$key", + "-PkeyName=$keyName", + "-Ppackage=$packageName" + ) + .build() + println(result.output) + + // Search key name in java + var javaCorrectNameFound = false + fileJava.bufferedReader().forEachLine { + if (it.contains(keyName)) { + javaCorrectNameFound = true + } + } + javaCorrectNameFound shouldBe true + // Search function name in ccp + val expectedCppFunctionName = "Java_${packageName.replace('.', '_')}_Secrets_get$cppKeyName(" + println("expectedFunctionName: $expectedCppFunctionName") + var cppCorrectNameFound = false + fileCpp.bufferedReader().forEachLine { + if (it.contains(expectedCppFunctionName)) { + cppCorrectNameFound = true + } + } + cppCorrectNameFound shouldBe true + + fileJava.delete() + fileCpp.delete() + packageDirJava.delete() + packageDirCpp.delete() + } + } + } + } +}) diff --git a/src/test/kotlin/UtilsTest.kt b/src/test/kotlin/UtilsTest.kt index 8f4b2e1..b96d293 100644 --- a/src/test/kotlin/UtilsTest.kt +++ b/src/test/kotlin/UtilsTest.kt @@ -10,15 +10,15 @@ class UtilsTest : WordSpec({ val packageName = "com.klaxit.test" - "Using getCppPackageName()" should { + "Using getCppName()" should { "transform package separator" { - Utils.getCppPackageName(packageName) shouldBe "com_klaxit_test" + Utils.getCppName(packageName) shouldBe "com_klaxit_test" } "transform package with underscore" { - Utils.getCppPackageName("com.klaxit.test_with_underscore") shouldBe "com_klaxit_test_1with_1underscore" + Utils.getCppName("com.klaxit.test_with_underscore") shouldBe "com_klaxit_test_1with_1underscore" } "transform package with escaping characters" { - Utils.getCppPackageName("com[test.klaxit;test.test_with_underscore") shouldBe "com_3test_klaxit_2test_test_1with_1underscore" + Utils.getCppName("com[test.klaxit;test.test_with_underscore") shouldBe "com_3test_klaxit_2test_test_1with_1underscore" } }