diff --git a/compile-ios.sh b/compile-ios.sh new file mode 100755 index 0000000..94f7a74 --- /dev/null +++ b/compile-ios.sh @@ -0,0 +1,23 @@ + +cd prebuilt + +xcodebuild build -scheme Attributes -configuration Release -arch arm64 -sdk 'iphoneos' \ + BUILD_LIBRARY_FOR_DISTRIBUTION=YES \ + -derivedDataPath './Attributes/build/' \ + -project Attributes/Attributes.xcodeproj +cp Attributes/build/Build/Products/Release-iphoneos/libAttributes.a Attributes/binaries/arm64 +rm -rf Attributes/build + +xcodebuild build -scheme Attributes -configuration Release -arch arm64 -sdk 'iphonesimulator' \ + BUILD_LIBRARY_FOR_DISTRIBUTION=YES \ + -derivedDataPath './Attributes/build/' \ + -project Attributes/Attributes.xcodeproj +cp Attributes/build/Build/Products/Release-iphonesimulator/libAttributes.a Attributes/binaries/arm64-simulator +rm -rf Attributes/build + +xcodebuild build -scheme Attributes -configuration Release -arch x86_64 -sdk 'iphonesimulator' \ + BUILD_LIBRARY_FOR_DISTRIBUTION=YES \ + -derivedDataPath './Attributes/build/' \ + -project Attributes/Attributes.xcodeproj +cp Attributes/build/Build/Products/Release-iphonesimulator/libAttributes.a Attributes/binaries/x64 +rm -rf Attributes/build diff --git a/encryption/build.gradle.kts b/encryption/build.gradle.kts index 50e85b0..d2c37f7 100644 --- a/encryption/build.gradle.kts +++ b/encryption/build.gradle.kts @@ -3,6 +3,7 @@ val kryptoVersion: String by project plugins { kotlin("multiplatform") id("com.android.library") + id("io.github.ttypic.swiftklib") version "0.1.0" } kotlin { @@ -14,8 +15,12 @@ kotlin { iosArm64(), iosSimulatorArm64() ).forEach { - it.binaries.framework { - baseName = "shared" + it.compilations { + val main by getting { + cinterops { + create("Attributes") + } + } } } @@ -61,4 +66,11 @@ android { targetSdk = 32 } namespace = "io.github.landrynorris.encryption" -} \ No newline at end of file +} + +swiftklib { + create("Attributes") { + path = file("src/swift") + packageName("io.github.landrynorris.encryption.swift") + } +} diff --git a/encryption/src/iosMain/kotlin/io.github.landrynorris.encryption/SecureCrypto.kt b/encryption/src/iosMain/kotlin/io.github.landrynorris.encryption/SecureCrypto.kt index aaa68d0..d2d609f 100644 --- a/encryption/src/iosMain/kotlin/io.github.landrynorris.encryption/SecureCrypto.kt +++ b/encryption/src/iosMain/kotlin/io.github.landrynorris.encryption/SecureCrypto.kt @@ -1,8 +1,10 @@ package io.github.landrynorris.encryption +import io.github.landrynorris.encryption.swift.Attributes import kotlinx.cinterop.* import platform.CoreFoundation.* -import platform.Foundation.* +import platform.Foundation.CFBridgingRelease +import platform.Foundation.NSString import platform.Security.* import platform.darwin.OSStatus @@ -16,38 +18,11 @@ actual object SecureCrypto: Crypto { kSecAttrAccessibleWhenUnlockedThisDeviceOnly?.reinterpret(), kSecAccessControlPrivateKeyUsage, null) - val aliasData = (alias as NSString).dataUsingEncoding(NSUTF8StringEncoding) - - val privateKeyProperties = cfDictionaryOf( - mapOf( - kSecAttrIsPermanent to kCFBooleanTrue, - kSecAttrApplicationTag to CFBridgingRetain(aliasData), - kSecAttrAccessControl to access - ) - ) - - val publicKeyProperties = cfDictionaryOf( - mapOf( - kSecAttrIsPermanent to kCFBooleanTrue, - kSecAttrApplicationTag to CFBridgingRetain(aliasData), - kSecAttrAccessControl to access - ) - ) - - val properties = cfDictionaryOf( - mapOf( - kSecAttrKeyType to kSecAttrKeyTypeEC, - kSecAttrKeySizeInBits to CFBridgingRetain(NSNumber(256)), - //kSecAttrTokenID to kSecAttrTokenIDSecureEnclave, - kSecPrivateKeyAttrs to privateKeyProperties, - kSecPublicKeyAttrs to publicKeyProperties - ) - ) - val error = alloc() println("Generating key") - SecKeyCreateRandomKey(properties, error.ptr) + val props = Attributes.keyAttributes(access, ALIAS) + SecKeyCreateRandomKey(props, error.ptr) if(error.value != null) { val errorText = error.value?.errorString() @@ -67,17 +42,7 @@ actual object SecureCrypto: Crypto { private fun loadKey(alias: String): SecKeyRef? = memScoped { println("Loading key") - val aliasData = (alias as NSString).dataUsingEncoding(NSUTF8StringEncoding) - - val query = cfDictionaryOf( - mapOf( - kSecClass to kSecClassKey, - kSecAttrApplicationTag to CFBridgingRetain(aliasData), - kSecAttrKeyType to kSecAttrKeyTypeEC, - kSecMatchLimit to kSecMatchLimitOne, - kSecReturnRef to kCFBooleanTrue - ) - ) + val query = Attributes.keyQuery(alias) val item = alloc() val result = SecItemCopyMatching(query, item.ptr.reinterpret()) @@ -146,13 +111,3 @@ actual object SecureCrypto: Crypto { return nsErrorText as String } } - -internal inline fun MemScope.cfDictionaryOf(map: Map): CFDictionaryRef? { - val size = map.size - val keys = allocArrayOf(*map.keys.toTypedArray()) - val values = allocArrayOf(*map.values.toTypedArray()) - return CFDictionaryCreate(kCFAllocatorDefault, - keys.reinterpret(), values.reinterpret(), - size.convert(), kCFTypeDictionaryKeyCallBacks.ptr, - kCFTypeDictionaryValueCallBacks.ptr) -} diff --git a/encryption/src/swift/Attributes.swift b/encryption/src/swift/Attributes.swift new file mode 100644 index 0000000..69cf6ab --- /dev/null +++ b/encryption/src/swift/Attributes.swift @@ -0,0 +1,31 @@ +import Foundation +import Security + +@objc public class Attributes: NSObject { + @objc public class func test() -> Int { + return 12 + } + + @objc public class func keyAttributes(_ access: SecAccessControl, tag: String) -> CFDictionary { + return [ + kSecAttrKeyType as String : kSecAttrKeyTypeEC, + kSecAttrKeySizeInBits as String : 256, + kSecAttrTokenID as String : kSecAttrTokenIDSecureEnclave, + kSecPrivateKeyAttrs as String : [ + kSecAttrIsPermanent as String : true, + kSecAttrApplicationTag as String : tag, + kSecAttrAccessControl as String : access + ] + ] as CFDictionary + } + + @objc public class func keyQuery(_ tag: String) -> CFDictionary { + return [ + kSecClass as String : kSecClassKey, + kSecAttrApplicationTag as String : tag, + kSecAttrKeyType as String : kSecAttrKeyTypeEC, + kSecMatchLimit as String : kSecMatchLimitOne, + kSecReturnRef as String : true + ] as CFDictionary + } +} \ No newline at end of file diff --git a/mobileapp/build.gradle.kts b/mobileapp/build.gradle.kts index ac37158..e36456a 100644 --- a/mobileapp/build.gradle.kts +++ b/mobileapp/build.gradle.kts @@ -1,10 +1,8 @@ import org.jetbrains.compose.ExperimentalComposeLibrary import org.jetbrains.compose.desktop.application.dsl.TargetFormat import org.jetbrains.kotlin.gradle.plugin.mpp.BitcodeEmbeddingMode -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget import org.jetbrains.kotlin.gradle.plugin.mpp.TestExecutable -import java.io.File import java.util.* val keystoreProperties = diff --git a/mobileapp/src/commonMain/kotlin/io/github/landrynorris/multifactor/compose/CreateOtpDialog.kt b/mobileapp/src/commonMain/kotlin/io/github/landrynorris/multifactor/compose/CreateOtpDialog.kt index 743aca6..de521eb 100644 --- a/mobileapp/src/commonMain/kotlin/io/github/landrynorris/multifactor/compose/CreateOtpDialog.kt +++ b/mobileapp/src/commonMain/kotlin/io/github/landrynorris/multifactor/compose/CreateOtpDialog.kt @@ -7,7 +7,7 @@ import io.github.landrynorris.multifactor.components.CreateOtpLogic import io.github.landrynorris.multifactor.platform.Dialog @Composable -fun CreateOtpDialog(logic: CreateOtpLogic, onDismiss: () -> Unit) { +internal fun CreateOtpDialog(logic: CreateOtpLogic, onDismiss: () -> Unit) { val state by logic.state.collectAsState() Dialog(onDismissRequest = onDismiss) { CreateOtpItem(state, onNameChanged = logic::nameChanged, diff --git a/mobileapp/src/commonMain/kotlin/io/github/landrynorris/multifactor/compose/SwipeToDelete.kt b/mobileapp/src/commonMain/kotlin/io/github/landrynorris/multifactor/compose/SwipeToDelete.kt index 019af01..bc849fd 100644 --- a/mobileapp/src/commonMain/kotlin/io/github/landrynorris/multifactor/compose/SwipeToDelete.kt +++ b/mobileapp/src/commonMain/kotlin/io/github/landrynorris/multifactor/compose/SwipeToDelete.kt @@ -22,7 +22,7 @@ import androidx.compose.ui.unit.dp @OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class) @Composable -fun LazyItemScope.SwipeToDelete(onDelete: () -> Unit, content: @Composable () -> Unit) { +internal fun LazyItemScope.SwipeToDelete(onDelete: () -> Unit, content: @Composable () -> Unit) { val state = rememberDismissState(confirmStateChange = { if(it == DismissValue.DismissedToStart) { onDelete() @@ -38,7 +38,7 @@ fun LazyItemScope.SwipeToDelete(onDelete: () -> Unit, content: @Composable () -> @OptIn(ExperimentalMaterialApi::class) @Composable -fun SwipeBackground(state: DismissState) { +internal fun SwipeBackground(state: DismissState) { val direction = state.dismissDirection ?: return val color by animateColorAsState( when (state.targetValue) { diff --git a/mobileapp/src/iosMain/kotlin/io/github/landrynorris/multifactor/platform/Initialize.ios.kt b/mobileapp/src/iosMain/kotlin/io/github/landrynorris/multifactor/platform/Initialize.ios.kt index d7f78ac..02ead24 100644 --- a/mobileapp/src/iosMain/kotlin/io/github/landrynorris/multifactor/platform/Initialize.ios.kt +++ b/mobileapp/src/iosMain/kotlin/io/github/landrynorris/multifactor/platform/Initialize.ios.kt @@ -1,25 +1,24 @@ package io.github.landrynorris.multifactor.platform -import com.russhwolf.settings.AppleSettings import com.russhwolf.settings.ExperimentalSettingsApi -import com.russhwolf.settings.coroutines.FlowSettings +import com.russhwolf.settings.NSUserDefaultsSettings +import com.russhwolf.settings.coroutines.SuspendSettings import com.russhwolf.settings.coroutines.toFlowSettings import com.squareup.sqldelight.drivers.native.NativeSqliteDriver import io.github.landrynorris.database.AppDatabase import io.github.landrynorris.multifactor.repository.SettingsRepository -import kotlinx.coroutines.ExperimentalCoroutinesApi import org.koin.dsl.module import platform.Foundation.NSUserDefaults -@OptIn(ExperimentalSettingsApi::class, ExperimentalCoroutinesApi::class) +@OptIn(ExperimentalSettingsApi::class) actual val platformModule = module { single { val driver = NativeSqliteDriver(AppDatabase.Schema, "otpdatabase") AppDatabase(driver) } - single { - AppleSettings(NSUserDefaults()).toFlowSettings() + single { + NSUserDefaultsSettings(NSUserDefaults()).toFlowSettings() } single { diff --git a/mobileapp/src/nativeInterop/cinterop/secure.def b/mobileapp/src/nativeInterop/cinterop/secure.def index 5fd492d..5bbfff8 100644 --- a/mobileapp/src/nativeInterop/cinterop/secure.def +++ b/mobileapp/src/nativeInterop/cinterop/secure.def @@ -5,7 +5,3 @@ package=secure #import -@interface Extensions: NSObject {} -+ (CFDataRef) toCFData:(NSData*) data; -@end -