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'; // Added with guardian accounts. Absent on installs from before — see // [decodeSession]. static const kind = 'session_kind'; static const guardianEmail = 'guardian_email'; static const kindCredential = 'credential'; static const kindGuardian = 'guardian'; } /// Rebuilds the session from raw keychain values. Installs from before /// guardian accounts 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 SessionKeys.kindGuardian: final email = raw[SessionKeys.guardianEmail]; if (email == null || email.isEmpty) return null; return GuardianSession(email: email, isDemo: isDemo); 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, SessionKeys.guardianEmail: null, }, GuardianSession() => { SessionKeys.kind: SessionKeys.kindGuardian, SessionKeys.guardianEmail: session.email, SessionKeys.demo: session.isDemo ? 'true' : null, SessionKeys.username: null, SessionKeys.password: null, SessionKeys.loginFlow: null, }, };