diff --git a/build.gradle b/build.gradle index 9bf17ff..dbccb12 100644 --- a/build.gradle +++ b/build.gradle @@ -12,6 +12,8 @@ buildscript { junit : '4.12', mockito : '2.28.2', rxjava : '2.2.12', + kotlin : '1.5.10', + coroutines: '1.5.0' ] repositories { @@ -20,8 +22,9 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.6.2' + classpath 'com.android.tools.build:gradle:4.2.0' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4' + classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.32' } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3a7bb1d..3da65bd 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-all.zip diff --git a/ktx/.gitignore b/ktx/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/ktx/.gitignore @@ -0,0 +1 @@ +/build diff --git a/ktx/bintray.gradle b/ktx/bintray.gradle new file mode 100644 index 0000000..bda7a89 --- /dev/null +++ b/ktx/bintray.gradle @@ -0,0 +1,51 @@ +apply plugin: 'maven-publish' +apply plugin: 'com.jfrog.bintray' + +publishing { + publications { + Publication(MavenPublication) { + artifact("$buildDir/outputs/aar/ktx-release.aar") + groupId 'co.infinum' + artifact sourcesJar + artifact javadocsJar + artifactId 'goldfinger-ktx' + version versions.goldfinger + + pom.withXml { + def root = asNode() + def dependenciesNode = root.appendNode('dependencies') + + configurations.implementation.allDependencies.each { + def dependencyNode = dependenciesNode.appendNode('dependency') + if (it.name == 'core') { + dependencyNode.appendNode('groupId', 'co.infinum') + dependencyNode.appendNode('artifactId', 'goldfinger') + dependencyNode.appendNode('version', versions.goldfinger) + } else { + dependencyNode.appendNode('groupId', it.group) + dependencyNode.appendNode('artifactId', it.name) + dependencyNode.appendNode('version', it.version) + } + } + } + } + } +} + +bintray { + user = System.getenv('BINTRAY_USER') + key = System.getenv('BINTRAY_API_KEY') + publish = false + publications = ['Publication'] + + pkg { + repo = 'android' + name = 'goldfinger-ktx' + userOrg = 'infinum' + publicDownloadNumbers = true + + version { + name = versions.goldfinger + } + } +} \ No newline at end of file diff --git a/ktx/build.gradle b/ktx/build.gradle new file mode 100644 index 0000000..6c98fd3 --- /dev/null +++ b/ktx/build.gradle @@ -0,0 +1,24 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion sdk.target + + defaultConfig { + minSdkVersion sdk.min + targetSdkVersion sdk.target + versionName versions.goldfinger + } +} + +dependencies { + implementation project(':core') + implementation "androidx.appcompat:appcompat:${versions.appcompat}" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${versions.kotlin}" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:${versions.coroutines}" + + testImplementation "junit:junit:${versions.junit}" + testImplementation "org.mockito:mockito-core:${versions.mockito}" +} + +apply from: '../tasks.gradle' +apply from: 'bintray.gradle' \ No newline at end of file diff --git a/ktx/src/main/AndroidManifest.xml b/ktx/src/main/AndroidManifest.xml new file mode 100644 index 0000000..c1ac4af --- /dev/null +++ b/ktx/src/main/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ktx/src/main/java/co/infinum/goldfinger/ktx/GoldfingerKtx.kt b/ktx/src/main/java/co/infinum/goldfinger/ktx/GoldfingerKtx.kt new file mode 100644 index 0000000..c4319ca --- /dev/null +++ b/ktx/src/main/java/co/infinum/goldfinger/ktx/GoldfingerKtx.kt @@ -0,0 +1,75 @@ +package co.infinum.goldfinger.ktx + +import android.content.Context +import co.infinum.goldfinger.Goldfinger +import co.infinum.goldfinger.Goldfinger.PromptParams +import co.infinum.goldfinger.crypto.CipherCrypter +import co.infinum.goldfinger.crypto.CipherFactory +import co.infinum.goldfinger.crypto.MacCrypter +import co.infinum.goldfinger.crypto.MacFactory +import co.infinum.goldfinger.crypto.SignatureCrypter +import co.infinum.goldfinger.crypto.SignatureFactory +import kotlinx.coroutines.flow.Flow + +interface GoldfingerKtx { + + fun hasFingerprintHardware(): Boolean + + fun hasEnrolledFingerprint(): Boolean + + fun canAuthenticate(): Boolean + + fun authenticate( + params: PromptParams, + ): Flow + + fun encrypt( + params: PromptParams, + key: String, + value: String, + ): Flow + + fun decrypt( + params: PromptParams, + key: String, + value: String, + ): Flow + + fun cancel() + + class Builder(context: Context) { + + private val baseBuilder: Goldfinger.Builder = Goldfinger.Builder(context) + + fun build(): GoldfingerKtx = + GoldfingerKtxImpl(baseBuilder.build()) + + fun cipherCrypter(cipherCrypter: CipherCrypter?): Builder = apply { + baseBuilder.cipherCrypter(cipherCrypter) + } + + fun cipherFactory(cipherFactory: CipherFactory?): Builder = apply { + baseBuilder.cipherFactory(cipherFactory) + } + + fun logEnabled(logEnabled: Boolean): Builder = apply { + baseBuilder.logEnabled(logEnabled) + } + + fun macCrypter(macCrypter: MacCrypter?): Builder = apply { + baseBuilder.macCrypter(macCrypter) + } + + fun macFactory(macFactory: MacFactory?): Builder = apply { + baseBuilder.macFactory(macFactory) + } + + fun signatureCrypter(signatureCrypter: SignatureCrypter?): Builder = apply { + baseBuilder.signatureCrypter(signatureCrypter) + } + + fun signatureFactory(signatureFactory: SignatureFactory?): Builder = apply { + baseBuilder.signatureFactory(signatureFactory) + } + } +} diff --git a/ktx/src/main/java/co/infinum/goldfinger/ktx/GoldfingerKtxCallback.kt b/ktx/src/main/java/co/infinum/goldfinger/ktx/GoldfingerKtxCallback.kt new file mode 100644 index 0000000..588cdcd --- /dev/null +++ b/ktx/src/main/java/co/infinum/goldfinger/ktx/GoldfingerKtxCallback.kt @@ -0,0 +1,28 @@ +package co.infinum.goldfinger.ktx + +import co.infinum.goldfinger.Goldfinger +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.channels.ProducerScope + +@ExperimentalCoroutinesApi +class GoldfingerKtxCallback( + private val goldfinger: Goldfinger, + private val producerScope: ProducerScope, +) : Goldfinger.Callback { + override fun onResult(result: Goldfinger.Result) { + with(producerScope) { + if (!isClosedForSend) { + channel.trySend(result) + if (result.type() == Goldfinger.Type.SUCCESS || result.type() == Goldfinger.Type.ERROR) { + channel.close() + } + } else { + goldfinger.cancel() + } + } + } + + override fun onError(e: Exception) { + producerScope.channel.close(e) + } +} \ No newline at end of file diff --git a/ktx/src/main/java/co/infinum/goldfinger/ktx/GoldfingerKtxImpl.kt b/ktx/src/main/java/co/infinum/goldfinger/ktx/GoldfingerKtxImpl.kt new file mode 100644 index 0000000..87ac49d --- /dev/null +++ b/ktx/src/main/java/co/infinum/goldfinger/ktx/GoldfingerKtxImpl.kt @@ -0,0 +1,73 @@ +package co.infinum.goldfinger.ktx + +import co.infinum.goldfinger.Goldfinger +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.buffer +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.cancellable + +@ExperimentalCoroutinesApi +class GoldfingerKtxImpl(private val goldfinger: Goldfinger) : GoldfingerKtx { + + private fun inGoldfingerFlow(doWithCallback: (GoldfingerKtxCallback) -> Unit) = + callbackFlow { + doWithCallback( + GoldfingerKtxCallback( + goldfinger, + this, + ) + ) + awaitClose { goldfinger.cancel() } + } + .buffer( + capacity = 1, + onBufferOverflow = BufferOverflow.DROP_OLDEST, + ) + .cancellable() + + override fun hasFingerprintHardware(): Boolean = goldfinger.hasFingerprintHardware() + + override fun hasEnrolledFingerprint(): Boolean = goldfinger.hasEnrolledFingerprint() + + override fun canAuthenticate(): Boolean = goldfinger.canAuthenticate() + + override fun authenticate(params: Goldfinger.PromptParams): Flow = inGoldfingerFlow { callback -> + goldfinger.authenticate( + params, + callback, + ) + } + + override fun encrypt( + params: Goldfinger.PromptParams, + key: String, + value: String, + ): Flow = inGoldfingerFlow { callback -> + goldfinger.encrypt( + params, + key, + value, + callback, + ) + } + + override fun decrypt( + params: Goldfinger.PromptParams, + key: String, + value: String, + ): Flow = inGoldfingerFlow { callback -> + goldfinger.decrypt( + params, + key, + value, + callback, + ) + } + + override fun cancel() { + goldfinger.cancel() + } +} diff --git a/settings.gradle b/settings.gradle index e741f1f..e6db287 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':core', ':example', ':rx' +include ':core', ':example', ':rx', ':ktx'