[ad_1]
I made a easy analog of the account supervisor for iOS utilizing Apple Keychain:
@Serializable
information class Account(
val identify: String,
val password: String,
val accessToken: String,
val refreshToken: String,
)
precise class AccountManagerGateway : IAccountManagerGateway {
non-public val json = Json { encodeDefaults = true }
override enjoyable addAccount(account: Account) = updateAccount(account)
override enjoyable updateAccount(account: Account) {
val information = json.encodeToString(account)
if (!saveData(information)) {
throw AccountException("Account not saved")
}
}
override enjoyable getAccount(): Account? = this.getData()?.let {
json.decodeFromString(it)
}
override enjoyable deleteAccount() {
deleteData()
}
non-public enjoyable getData(): String? {
memScoped {
val question = question(
kSecClass to kSecClassGenericPassword,
kSecAttrService to SERVICE.toCFDict(),
kSecAttrAccount to ACCOUNT_TYPE.toCFDict(),
)
val consequence = alloc<CFTypeRefVar>()
val standing = SecItemCopyMatching(question, consequence.ptr)
if (standing == errSecSuccess && consequence.worth != null) {
val worth = CFBridgingRelease(consequence.worth) as? NSData
return worth?.stringValue
}
return null
}
}
non-public enjoyable deleteData(): Boolean {
memScoped standing == errSecItemNotFound
}
non-public enjoyable saveData(worth: String): Boolean {
memScoped {
val question = question(
kSecClass to kSecClassGenericPassword,
kSecAttrService to SERVICE.toCFDict(),
kSecAttrAccount to ACCOUNT_TYPE.toCFDict(),
kSecValueData to worth.toCFDict(),
)
var standing = SecItemAdd(question, null)
if (standing == errSecDuplicateItem) {
SecItemDelete(question)
standing = SecItemAdd(question, null)
}
return standing == errSecSuccess
}
}
non-public enjoyable question(vararg pairs: Pair<CValuesRef<*>?, CValuesRef<*>?>): CFMutableDictionaryRef? {
memScoped {
val dict = CFDictionaryCreateMutable(null, pairs.dimension.toLong(), null, null)
pairs.forEach {
CFDictionaryAddValue(dict, it.first, it.second)
}
return dict
}
}
non-public enjoyable String.toCFDict(): CFTypeRef? {
memScoped {
return CFBridgingRetain(
NSData.dataWithBytes(
bytes = this@toCFDict.cstr.ptr,
size = this@toCFDict.size.toULong()
)
)
}
}
non-public val NSData.stringValue: String?
get() = NSString.create(this, NSUTF8StringEncoding) as String?
companion object {
const val ACCOUNT_TYPE = "com.myapp"
const val SERVICE = "www.myapp.com"
}
}
The supervisor saves accounts appropriately, not less than I feel so cuz on the second name I get the errSecDuplicateItem standing. Nonetheless, once I name getAccount it at all times returns null.
What’s the issue with my code?
UPD
I’ve improved getData() a little bit:
non-public enjoyable getData(): String? {
memScoped {
val question = question(
kSecClass to kSecClassGenericPassword,
kSecAttrService to SERVICE.toCFDict(),
kSecAttrAccount to ACCOUNT_TYPE.toCFDict(),
)
val consequence = alloc<CFTypeRefVar>()
val standing = SecItemCopyMatching(question, consequence.ptr)
when (standing) {
errSecSuccess -> {
if (consequence.worth != null) {
val worth = CFBridgingRelease(consequence.worth) as? NSData
return worth?.stringValue
} else {
throw AccountException(
"Error whereas looking for an account, result's null"
)
}
}
errSecItemNotFound -> return null
}
throw AccountException("Error whereas looking for an account, standing: `$standing`")
}
}
It crashes with exception: Error whereas looking for an account, result's null, i.e. the search is profitable however the result’s null though saveData() finds duplicates… I do not simply perceive already…
[ad_2]
