package com.bitcointxoko.gudariwallet.security import android.util.Log import androidx.datastore.core.CorruptionException import androidx.datastore.core.Serializer import com.google.crypto.tink.StreamingAead import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.io.InputStream import java.io.OutputStream class CredentialsSerializer( private val streamingAead: StreamingAead ) : Serializer { private val TAG = "CredentialsSerializer" override val defaultValue: Credentials = Credentials.getDefaultInstance() override suspend fun readFrom(input: InputStream): Credentials = withContext(Dispatchers.IO) { try { val result = Credentials.parseFrom( streamingAead.newDecryptingStream(input, AAD) ) Log.d(TAG, "Credentials decrypted successfully — isOnboarded: ${result.isOnboarded}") result } catch (e: Exception) { Log.e(TAG, "Decryption failed — DataStore may be corrupt or key rotated", e) throw CorruptionException("Cannot read/decrypt credentials DataStore", e) } } override suspend fun writeTo(t: Credentials, output: OutputStream): Unit = withContext(Dispatchers.IO) { try { val encryptingStream = streamingAead.newEncryptingStream(output, AAD) t.writeTo(encryptingStream) // returns Int — discarded by Unit return type encryptingStream.close() Log.d(TAG, "Credentials encrypted and written — isOnboarded: ${t.isOnboarded}, " + "hasInvoiceKey: ${t.invoiceKey.isNotBlank()}, " + "hasAdminKey: ${t.adminKey.isNotBlank()}, " + "hasBaseUrl: ${t.baseUrl.isNotBlank()}") } catch (e: Exception) { Log.e(TAG, "Encryption/write failed", e) throw e } } companion object { private val AAD = "credentials_store".toByteArray(Charsets.UTF_8) } }