Skip to content

Commit

Permalink
Update StorageManager and VDCCollection API usage (#81)
Browse files Browse the repository at this point in the history
Signed-off-by: Tiago Nascimento <[email protected]>
Co-authored-by: Gregorio <[email protected]>
  • Loading branch information
theosirian and w4ll3 authored Jan 14, 2025
1 parent e0ba60a commit 9567043
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 39 deletions.
2 changes: 1 addition & 1 deletion MobileSdk/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ android {
}

dependencies {
api("com.spruceid.mobile.sdk.rs:mobilesdkrs:0.4.3")
api("com.spruceid.mobile.sdk.rs:mobilesdkrs:0.5.1")
//noinspection GradleCompatible
implementation("com.android.support:appcompat-v7:28.0.0")
/* Begin UI dependencies */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ class CredentialPack {
* it will be skipped without updating.
*/
@Throws(SavingException::class)
fun save(storage: StorageManagerInterface) {
suspend fun save(storage: StorageManagerInterface) {
val vdcCollection = VdcCollection(storage)
try {
list().forEach {
Expand Down Expand Up @@ -243,7 +243,7 @@ class CredentialPack {
* Credentials that are in this pack __are__ removed from the VdcCollection.
*/
@Throws(SavingException::class)
fun remove(storage: StorageManagerInterface) {
suspend fun remove(storage: StorageManagerInterface) {
intoContents().remove(storage)
}

Expand All @@ -254,7 +254,7 @@ class CredentialPack {
/**
* Clears all stored CredentialPacks.
*/
fun clearPacks(storage: StorageManagerInterface) {
suspend fun clearPacks(storage: StorageManagerInterface) {
try {
storage.list()
.filter { it.startsWith(CredentialPackContents.STORAGE_PREFIX) }
Expand All @@ -270,7 +270,7 @@ class CredentialPack {
* These can then be individually loaded. For eager loading of all packs, see `loadPacks`.
*/
@Throws(LoadingException::class)
fun listPacks(storage: StorageManagerInterface): List<CredentialPackContents> {
suspend fun listPacks(storage: StorageManagerInterface): List<CredentialPackContents> {
val contents: Iterable<CredentialPackContents>
try {
contents =
Expand All @@ -287,7 +287,7 @@ class CredentialPack {
/**
* Loads all CredentialPacks.
*/
fun loadPacks(storage: StorageManagerInterface): List<CredentialPack> {
suspend fun loadPacks(storage: StorageManagerInterface): List<CredentialPack> {
val vdcCollection = VdcCollection(storage)
return listPacks(storage)
.map { it.load(vdcCollection) }
Expand Down Expand Up @@ -339,7 +339,7 @@ class CredentialPackContents {
* Loads all of the credentials from the VdcCollection into a CredentialPack.
*/
@Throws(LoadingException::class)
fun load(vdcCollection: VdcCollection): CredentialPack {
suspend fun load(vdcCollection: VdcCollection): CredentialPack {
val credentials =
credentials
.mapNotNull {
Expand Down Expand Up @@ -378,7 +378,7 @@ class CredentialPackContents {
}

@Throws(SavingException::class)
internal fun save(storage: StorageManagerInterface) {
internal suspend fun save(storage: StorageManagerInterface) {
try {
storage.add(storageKey(), toBytes())
} catch (e: Exception) {
Expand All @@ -387,7 +387,7 @@ class CredentialPackContents {
}

@Throws(SavingException::class)
internal fun remove(storage: StorageManagerInterface) {
internal suspend fun remove(storage: StorageManagerInterface) {
val vdcCollection = VdcCollection(storage)
credentials.forEach {
try {
Expand Down
51 changes: 29 additions & 22 deletions MobileSdk/src/main/java/com/spruceid/mobile/sdk/StorageManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import com.spruceid.mobile.sdk.KeyManager
import com.spruceid.mobile.sdk.rs.StorageManagerInterface
import java.io.File
import java.io.FileNotFoundException
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

class StorageManager(val context: Context) : StorageManagerInterface {
/// Function: add
Expand All @@ -14,7 +16,7 @@ class StorageManager(val context: Context) : StorageManagerInterface {
/// Arguments:
/// key - The key to add
/// value - The value to add under the key
override fun add(key: String, value: ByteArray) =
override suspend fun add(key: String, value: ByteArray) =
context.openFileOutput(filename(key), 0).use {
it.write(encrypt(value))
it.close()
Expand All @@ -27,7 +29,7 @@ class StorageManager(val context: Context) : StorageManagerInterface {
///
/// Arguments:
/// key - The key to retrieve
override fun get(key: String): ByteArray? {
override suspend fun get(key: String): ByteArray? {
var bytes: ByteArray
try {
context.openFileInput(filename(key)).use {
Expand All @@ -46,15 +48,15 @@ class StorageManager(val context: Context) : StorageManagerInterface {
///
/// Arguments:
/// key - The key to remove
override fun remove(key: String) {
override suspend fun remove(key: String) {
File(context.filesDir, filename(key)).delete()
}


/// Function: list
///
/// Lists all key-value pair in storage
override fun list(): List<String> {
override suspend fun list(): List<String> {
val list = context.filesDir.list() ?: throw Exception("cannot list stored objects")

return list.mapNotNull {
Expand All @@ -77,16 +79,18 @@ class StorageManager(val context: Context) : StorageManagerInterface {
///
/// Arguments:
/// value - The string value to be encrypted
private fun encrypt(value: ByteArray): ByteArray {
val keyManager = KeyManager()
if (!keyManager.keyExists(KEY_NAME)) {
keyManager.generateEncryptionKey(KEY_NAME)
private suspend fun encrypt(value: ByteArray): ByteArray {
return suspendCoroutine { continuation ->
val keyManager = KeyManager()
if (!keyManager.keyExists(KEY_NAME)) {
keyManager.generateEncryptionKey(KEY_NAME)
}
val encrypted = keyManager.encryptPayload(KEY_NAME, value)
val iv = Base64.encodeToString(encrypted.first, B64_FLAGS)
val bytes = Base64.encodeToString(encrypted.second, B64_FLAGS)
val res = "$iv;$bytes".toByteArray()
continuation.resume(res)
}
val encrypted = keyManager.encryptPayload(KEY_NAME, value)
val iv = Base64.encodeToString(encrypted.first, B64_FLAGS)
val bytes = Base64.encodeToString(encrypted.second, B64_FLAGS)
val res = "$iv;$bytes".toByteArray()
return res
}

/// Function: decrypt
Expand All @@ -95,16 +99,19 @@ class StorageManager(val context: Context) : StorageManagerInterface {
///
/// Arguments:
/// value - The byte array to be decrypted
private fun decrypt(value: ByteArray): ByteArray {
val keyManager = KeyManager()
if (!keyManager.keyExists(KEY_NAME)) {
throw Exception("Cannot retrieve values before creating encryption keys")
private suspend fun decrypt(value: ByteArray): ByteArray {
return suspendCoroutine { continuation ->
val keyManager = KeyManager()
if (!keyManager.keyExists(KEY_NAME)) {
throw Exception("Cannot retrieve values before creating encryption keys")
}
val decoded = value.decodeToString().split(";")
assert(decoded.size == 2)
val iv = Base64.decode(decoded.first(), B64_FLAGS)
val encrypted = Base64.decode(decoded.last(), B64_FLAGS)
val decrypted = keyManager.decryptPayload(KEY_NAME, iv, encrypted)
continuation.resume(decrypted)
}
val decoded = value.decodeToString().split(";")
assert(decoded.size == 2)
val iv = Base64.decode(decoded.first(), B64_FLAGS)
val encrypted = Base64.decode(decoded.last(), B64_FLAGS)
return keyManager.decryptPayload(KEY_NAME, iv, encrypted)
}

private const val FILENAME_PREFIX = "sprucekit:datastore"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,22 @@ class CredentialPacksViewModel(application: Application) : AndroidViewModel(appl
}
}

fun saveCredentialPack(credentialPack: CredentialPack) {
suspend fun saveCredentialPack(credentialPack: CredentialPack) {
credentialPack.save(storageManager)
val tmpCredentialPacksList = _credentialPacks.value.toMutableStateList()
tmpCredentialPacksList.add(credentialPack)
_credentialPacks.value = tmpCredentialPacksList
}

fun deleteAllCredentialPacks(onDeleteCredentialPack: ((CredentialPack) -> Unit)? = null) {
suspend fun deleteAllCredentialPacks(onDeleteCredentialPack: (suspend (CredentialPack) -> Unit)? = null) {
_credentialPacks.value.forEach { credentialPack ->
credentialPack.remove(storageManager)
onDeleteCredentialPack?.invoke(credentialPack)
}
_credentialPacks.value = emptyList()
}

fun deleteCredentialPack(credentialPack: CredentialPack) {
suspend fun deleteCredentialPack(credentialPack: CredentialPack) {
credentialPack.remove(storageManager)
val tmpCredentialPacksList = _credentialPacks.value.toMutableStateList()
tmpCredentialPacksList.remove(credentialPack)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ fun WalletHomeBody(
credentialPack = credentialPack,
statusListViewModel = statusListViewModel,
onDelete = {
credentialPacksViewModel.deleteCredentialPack(credentialPack)
scope.launch {
credentialPacksViewModel.deleteCredentialPack(credentialPack)
credentialPack.list().forEach { credential ->
val credentialInfo =
getCredentialIdTitleAndIssuer(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ fun WalletSettingsHomeBody(
Spacer(Modifier.weight(1f))
Button(
onClick = {
credentialPacksViewModel.deleteAllCredentialPacks(onDeleteCredentialPack = { credentialPack ->
GlobalScope.launch {
GlobalScope.launch {
credentialPacksViewModel.deleteAllCredentialPacks(onDeleteCredentialPack = { credentialPack ->
credentialPack.list().forEach { credential ->
val credentialInfo =
getCredentialIdTitleAndIssuer(
Expand All @@ -189,8 +189,8 @@ fun WalletSettingsHomeBody(
)
)
}
}
})
})
}
},
shape = RoundedCornerShape(5.dp),
colors = ButtonDefaults.buttonColors(
Expand Down

0 comments on commit 9567043

Please sign in to comment.