Some checks failed
release / build-release (push) Has been cancelled
- IChannel: creators -> sub-channels -> video posts (public listing API, search mapped) - IRequiresMediaInfoCallback -> signed proxy URLs; stream controller rewrites HLS so the AES-128 key is fetched server-side with the session cookie, segments stay on the CDN - delivery/info cached per token lifetime and throttled (~2/min) - config page: paste sails.sid + validate, extra creators, quality, search test - scripts/package.sh -> plugin folder + zip + md5 + manifest.json; Gitea release workflow - research docs, HAR analysis (HAR itself gitignored), install-pi5.sh Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
117 lines
3.7 KiB
Kotlin
117 lines
3.7 KiB
Kotlin
package com.coulterpeterson.floatnative.data
|
|
|
|
import android.content.Context
|
|
import androidx.security.crypto.EncryptedSharedPreferences
|
|
import androidx.security.crypto.MasterKey
|
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
import kotlinx.coroutines.flow.asStateFlow
|
|
|
|
class TokenManager(context: Context) {
|
|
|
|
private val masterKey = MasterKey.Builder(context)
|
|
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
|
|
.build()
|
|
|
|
private val prefs = EncryptedSharedPreferences.create(
|
|
context,
|
|
"floatnative_secure_prefs",
|
|
masterKey,
|
|
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
|
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
|
)
|
|
|
|
companion object {
|
|
private const val KEY_ACCESS_TOKEN = "access_token"
|
|
private const val KEY_REFRESH_TOKEN = "refresh_token"
|
|
private const val KEY_AUTH_COOKIE = "sails.sid"
|
|
private const val KEY_TOKEN_EXPIRY = "token_expiry"
|
|
private const val KEY_USER_ID = "user_id"
|
|
private const val KEY_COMPANION_API_KEY = "companion_api_key"
|
|
}
|
|
|
|
// Auth State Flow
|
|
private val _authStateFlow = MutableStateFlow(retrieve(KEY_ACCESS_TOKEN))
|
|
val authStateFlow = _authStateFlow.asStateFlow()
|
|
|
|
var accessToken: String?
|
|
get() = retrieve(KEY_ACCESS_TOKEN)
|
|
set(value) {
|
|
save(KEY_ACCESS_TOKEN, value)
|
|
_authStateFlow.value = value
|
|
}
|
|
|
|
var refreshToken: String?
|
|
get() = retrieve(KEY_REFRESH_TOKEN)
|
|
set(value) = save(KEY_REFRESH_TOKEN, value)
|
|
|
|
var authCookie: String?
|
|
get() = retrieve(KEY_AUTH_COOKIE)
|
|
set(value) = save(KEY_AUTH_COOKIE, value)
|
|
|
|
var tokenExpiry: Long
|
|
get() = prefs.getLong(KEY_TOKEN_EXPIRY, 0)
|
|
set(value) = prefs.edit().putLong(KEY_TOKEN_EXPIRY, value).apply()
|
|
|
|
var userId: String?
|
|
get() = retrieve(KEY_USER_ID)
|
|
set(value) = save(KEY_USER_ID, value)
|
|
|
|
var companionApiKey: String?
|
|
get() = retrieve(KEY_COMPANION_API_KEY)
|
|
set(value) = save(KEY_COMPANION_API_KEY, value)
|
|
|
|
var codeVerifier: String?
|
|
get() = retrieve("pkce_verifier")
|
|
set(value) = save("pkce_verifier", value)
|
|
|
|
fun clearAll() {
|
|
prefs.edit().clear().apply()
|
|
_authStateFlow.value = null
|
|
}
|
|
|
|
private fun save(key: String, value: String?) {
|
|
if (value == null) {
|
|
prefs.edit().remove(key).apply()
|
|
} else {
|
|
prefs.edit().putString(key, value).apply()
|
|
}
|
|
}
|
|
|
|
fun retrieve(key: String): String? {
|
|
return prefs.getString(key, null)
|
|
}
|
|
|
|
// Settings
|
|
private val _themeFlow = kotlinx.coroutines.flow.MutableStateFlow(prefs.getString("theme_mode", "dark") ?: "dark")
|
|
val themeFlow = _themeFlow.asStateFlow()
|
|
|
|
var themeMode: String
|
|
get() = prefs.getString("theme_mode", "dark") ?: "dark"
|
|
set(value) {
|
|
prefs.edit().putString("theme_mode", value).apply()
|
|
_themeFlow.value = value
|
|
}
|
|
|
|
var enhancedLttSearchEnabled: Boolean
|
|
get() = prefs.getBoolean("enhanced_ltt_search_enabled", false)
|
|
set(value) {
|
|
prefs.edit().putBoolean("enhanced_ltt_search_enabled", value).apply()
|
|
}
|
|
|
|
var fakeLiveStreamEnabled: Boolean
|
|
get() = prefs.getBoolean("fake_live_stream_enabled", false)
|
|
set(value) {
|
|
prefs.edit().putBoolean("fake_live_stream_enabled", value).apply()
|
|
}
|
|
|
|
var downloadLocationUri: String?
|
|
get() = prefs.getString("download_location_uri", null)
|
|
set(value) {
|
|
if (value == null) {
|
|
prefs.edit().remove("download_location_uri").apply()
|
|
} else {
|
|
prefs.edit().putString("download_location_uri", value).apply()
|
|
}
|
|
}
|
|
}
|