1 import { decodeUtf8Base64, encodeUtf8Base64 } from '@proton/crypto/lib/utils';
2 import type { OfflineKey } from '@proton/shared/lib/authentication/offlineKey';
4 import { appMode } from '../webpack.constants';
5 import { getBasename, getLocalIDFromPathname, getParsedPathWithoutLocalIDBasename } from './pathnameHelper';
6 import { getPersistedSession } from './persistedSessionStorage';
8 const MAILBOX_PASSWORD_KEY = 'proton:mailbox_pwd';
9 const UID_KEY = 'proton:oauth:UID';
10 const LOCAL_ID_KEY = 'proton:localID';
11 const PERSIST_SESSION_KEY = 'proton:persistSession';
12 const TRUST_SESSION_KEY = 'proton:trustSession';
13 const CLIENT_KEY_KEY = 'proton:clientKey';
14 const OFFLINE_KEY_KEY = 'proton:offlineKey';
16 const getPath = (basename: string | undefined, oldUrl: string, requestedPath?: string) => {
19 `/${getParsedPathWithoutLocalIDBasename(requestedPath || '/') || getParsedPathWithoutLocalIDBasename(oldUrl)}`,
24 UID: string | undefined;
25 localID: number | undefined;
26 basename: string | undefined;
29 const defaultAuthData = {
35 const getInitialState = (mode: 'sso' | 'standalone', oldUID?: string, oldLocalID?: number): AuthData => {
36 if (mode === 'standalone') {
43 const { pathname } = window.location;
44 const localID = getLocalIDFromPathname(pathname);
45 if (localID === undefined) {
46 return defaultAuthData;
48 const persistedSession = getPersistedSession(localID);
49 // Current session is active and actual
50 if (persistedSession && (oldUID === undefined || (persistedSession.UID === oldUID && localID === oldLocalID))) {
52 UID: persistedSession.UID,
54 basename: getBasename(localID),
57 return defaultAuthData;
61 mode?: 'sso' | 'standalone';
62 initialAuth?: boolean;
64 set: (key: string, value: any) => void;
65 get: (key: string) => any;
67 onUID?: (UID: string | undefined) => void;
70 const createAuthenticationStore = ({ mode = appMode, initialAuth, store: { set, get }, onUID }: Arguments) => {
71 const setUID = (UID: string | undefined) => {
75 const getUID = (): string => get(UID_KEY);
77 const setPassword = (password: string | undefined) => {
78 if (password === undefined) {
79 set(MAILBOX_PASSWORD_KEY, password);
82 set(MAILBOX_PASSWORD_KEY, encodeUtf8Base64(password));
84 const getPassword = () => {
85 const value: string | undefined = get(MAILBOX_PASSWORD_KEY);
86 if (value === undefined) {
89 return decodeUtf8Base64(value);
92 const getLocalID = () => get(LOCAL_ID_KEY);
94 const setLocalID = (LocalID: number | undefined) => {
95 set(LOCAL_ID_KEY, LocalID);
98 const hasSession = () => !!getUID();
100 const setPersistent = (persist: boolean | undefined) => set(PERSIST_SESSION_KEY, persist);
101 // Keep old default behavior
102 const getPersistent = () => get(PERSIST_SESSION_KEY) ?? true;
104 const setClientKey = (clientKey: string | undefined) => set(CLIENT_KEY_KEY, clientKey);
105 const getClientKey = () => get(CLIENT_KEY_KEY) ?? undefined;
107 const setOfflineKey = (offlineKey: OfflineKey | undefined) => set(OFFLINE_KEY_KEY, offlineKey);
108 const getOfflineKey = (): OfflineKey | undefined => get(OFFLINE_KEY_KEY) ?? undefined;
110 const setTrusted = (trusted: boolean | undefined) => set(TRUST_SESSION_KEY, trusted);
111 const getTrusted = () => get(TRUST_SESSION_KEY) ?? false;
113 const initialUID = getUID();
114 let initialAuthData: AuthData =
115 initialAuth === false ? defaultAuthData : getInitialState(mode, initialUID, getLocalID());
116 let basename = initialAuthData.basename;
117 // Ensure the store is up-to-date
118 setUID(initialAuthData?.UID);
119 setLocalID(initialAuthData?.localID);
132 keyPassword?: string;
138 offlineKey: OfflineKey | undefined;
141 setPassword(keyPassword);
142 setPersistent(persistent);
144 setClientKey(clientKey);
145 setOfflineKey(offlineKey);
147 if (newLocalID !== undefined && mode === 'sso') {
148 setLocalID(newLocalID);
149 basename = getBasename(newLocalID);
151 setLocalID(undefined);
152 basename = undefined;
155 return getPath(basename, window.location.href, path);
158 const logout = () => {
160 setPassword(undefined);
161 setPersistent(undefined);
162 setLocalID(undefined);
163 setTrusted(undefined);
164 setClientKey(undefined);
165 setOfflineKey(undefined);
166 basename = undefined;
197 get ready(): boolean {
198 return Boolean(initialAuthData.UID && initialUID && getClientKey());
203 export type AuthenticationStore = ReturnType<typeof createAuthenticationStore>;
205 export default createAuthenticationStore;