Files
Docmost-App/app/src/main/java/com/docmost/app/data/SessionManager.kt
Nino 7be826f9ba v1.0.3: Fix TipTap JSON content conversion for editor display
- Replace all TypeToken usage with JsonParser/gson.fromJson (fixes R8/ProGuard crash)
- Add parseJsonArray/parseJsonObject helpers for API response parsing
- Fix contentToMarkdown to properly convert TipTap JSON objects to Markdown
  using tiptapToMarkdown instead of returning raw JSON
- Fix API endpoints to handle unwrapped response formats
- Add ProGuard rules for Gson TypeToken preservation
- Redirect build dir to /tmp for Samba compatibility
2026-07-27 17:25:40 -06:00

141 lines
4.7 KiB
Kotlin

package com.docmost.app.data
import android.content.Context
import android.content.SharedPreferences
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKeys
import com.google.gson.Gson
import com.google.gson.JsonParser
data class Credentials(
val url: String,
val email: String,
val password: String,
val authToken: String = "",
val avatarUrl: String? = null
)
class SessionManager(private val context: Context) {
private val gson = Gson()
private val prefs: SharedPreferences by lazy {
createEncryptedPrefs(context, PREFS_NAME)
}
private val savedAccountsPrefs: SharedPreferences by lazy {
createEncryptedPrefs(context, SAVED_ACCOUNTS_PREFS)
}
private fun createEncryptedPrefs(context: Context, prefsName: String): SharedPreferences {
val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
return try {
EncryptedSharedPreferences.create(
prefsName,
masterKeyAlias,
context,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
} catch (e: Exception) {
context.getSharedPreferences(prefsName, Context.MODE_PRIVATE).edit().clear().apply()
EncryptedSharedPreferences.create(
prefsName,
masterKeyAlias,
context,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
}
}
fun saveCredentials(credentials: Credentials) {
try {
val json = gson.toJson(credentials)
prefs.edit().putString(KEY_CREDENTIALS, json).apply()
} catch (e: Exception) {
clear()
}
}
fun getCredentials(): Credentials? {
val json = try {
prefs.getString(KEY_CREDENTIALS, null)
} catch (e: Exception) {
clear()
null
} ?: return null
return try {
gson.fromJson(json, Credentials::class.java)
} catch (e: Exception) {
null
}
}
fun saveAuthToken(token: String) {
val current = getCredentials() ?: return
saveCredentials(current.copy(authToken = token))
}
fun clear() {
try {
prefs.edit().clear().apply()
} catch (_: Exception) {}
}
fun hasSession(): Boolean {
val creds = getCredentials() ?: return false
return creds.url.isNotBlank() && creds.email.isNotBlank() && creds.authToken.isNotBlank()
}
fun saveAccount(credentials: Credentials) {
try {
val accounts = getSavedAccounts().toMutableList()
accounts.removeAll { it.email == credentials.email && it.url == credentials.url }
accounts.add(credentials)
val json = gson.toJson(accounts)
savedAccountsPrefs.edit().putString(KEY_SAVED_ACCOUNTS, json).apply()
} catch (e: Exception) {
context.getSharedPreferences(SAVED_ACCOUNTS_PREFS, Context.MODE_PRIVATE).edit().clear().commit()
val json = gson.toJson(listOf(credentials))
savedAccountsPrefs.edit().putString(KEY_SAVED_ACCOUNTS, json).commit()
}
}
fun getSavedAccounts(): List<Credentials> {
val json = try {
savedAccountsPrefs.getString(KEY_SAVED_ACCOUNTS, null)
} catch (e: Exception) {
context.getSharedPreferences(SAVED_ACCOUNTS_PREFS, Context.MODE_PRIVATE).edit().clear().commit()
null
} ?: return emptyList()
return try {
val array = JsonParser.parseString(json).asJsonArray
array.map { gson.fromJson(it, Credentials::class.java) }
} catch (e: Exception) {
emptyList()
}
}
fun removeAccount(email: String, url: String) {
try {
val accounts = getSavedAccounts().toMutableList()
accounts.removeAll { it.email == email && it.url == url }
val json = gson.toJson(accounts)
savedAccountsPrefs.edit().putString(KEY_SAVED_ACCOUNTS, json).apply()
} catch (_: Exception) {}
}
fun hasAccount(email: String, url: String): Boolean {
return getSavedAccounts().any { it.email == email && it.url == url }
}
companion object {
private const val PREFS_NAME = "docmost_session"
private const val KEY_CREDENTIALS = "credentials"
private const val SAVED_ACCOUNTS_PREFS = "docmost_saved_accounts"
private const val KEY_SAVED_ACCOUNTS = "saved_accounts"
}
}