package com.sptmobile.voice import android.content.Context import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.preferencesDataStore import java.security.SecureRandom import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map private val Context.voiceDataStore by preferencesDataStore(name = "voice_settings") // [impl->REQ-VOICE-PIPE] /** * The webhook auth token (DESIGN.md §Pebble webhook contract: "a locally * generated token entered into Pebble's webhook headers"). Generated once * with [SecureRandom] on first use, persisted in DataStore; the user copies * it into Pebble's `X-Widget-Token` header config. Regenerating revokes the * old one (the receiver compares against the current value only). */ class VoiceSettings(private val context: Context) { private val tokenKey = stringPreferencesKey("webhook_token") /** Null until [ensureToken] has run once on this install. */ val token: Flow = context.voiceDataStore.data.map { it[tokenKey] } /** Generate-if-missing; returns the current token. */ suspend fun ensureToken(): String { context.voiceDataStore.edit { prefs -> if (prefs[tokenKey].isNullOrEmpty()) prefs[tokenKey] = newToken() } return context.voiceDataStore.data.first()[tokenKey]!! } /** Mint + persist a fresh token, revoking the old one. */ suspend fun regenerate(): String { val fresh = newToken() context.voiceDataStore.edit { it[tokenKey] = fresh } return fresh } private fun newToken(): String { val bytes = ByteArray(16) SecureRandom().nextBytes(bytes) return bytes.joinToString("") { "%02x".format(it) } } }