import 'session.dart'; /// Keychain keys of the session. Names are frozen: installed versions and the /// iOS AppDelegate/NSE read them, so renaming would log every user out. abstract final class SessionKeys { static const username = 'username'; static const password = 'password'; static const appPassword = 'nextcloud_app_password'; static const appPasswordTalk = 'nextcloud_app_password_talk'; static const loginFlow = 'nextcloud_login_flow'; static const demo = 'is_demo'; // Absent on installs from before account kinds — see [decodeSession]. static const kind = 'session_kind'; static const kindCredential = 'credential'; } /// Rebuilds the session from raw keychain values. Installs from before /// account kinds carry no [SessionKeys.kind]; a stored username and password /// then mean a credential session, so existing users stay signed in. Session? decodeSession(Map raw) { final isDemo = raw[SessionKeys.demo] == 'true'; switch (raw[SessionKeys.kind]) { case null: case SessionKeys.kindCredential: final username = raw[SessionKeys.username]; final password = raw[SessionKeys.password]; if (username == null || password == null) return null; return CredentialSession( username: username, password: password, appPassword: raw[SessionKeys.appPassword], appPasswordTalk: raw[SessionKeys.appPasswordTalk], usesLoginFlow: raw[SessionKeys.loginFlow] == 'true', isDemo: isDemo, ); default: // Written by a newer app version; unknown here, treat as signed out. return null; } } /// Keychain values for [session], excluding the group-scoped app passwords /// (written separately so the iOS NSE can read them). `null` = delete. Map encodeSessionFields(Session session) => switch (session) { CredentialSession() => { SessionKeys.kind: SessionKeys.kindCredential, SessionKeys.username: session.username, SessionKeys.password: session.password, SessionKeys.demo: session.isDemo ? 'true' : null, SessionKeys.loginFlow: session.nextcloud.usesLoginFlow ? 'true' : null, }, };