Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / packages / shared / lib / authentication / createAuthenticationStore.ts
blobb7d1404e846a6d168e9b554fa8c8b48e9a478d38
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) => {
17     return [
18         basename || '',
19         `/${getParsedPathWithoutLocalIDBasename(requestedPath || '/') || getParsedPathWithoutLocalIDBasename(oldUrl)}`,
20     ].join('');
23 interface AuthData {
24     UID: string | undefined;
25     localID: number | undefined;
26     basename: string | undefined;
29 const defaultAuthData = {
30     UID: undefined,
31     localID: undefined,
32     basename: undefined,
35 const getInitialState = (mode: 'sso' | 'standalone', oldUID?: string, oldLocalID?: number): AuthData => {
36     if (mode === 'standalone') {
37         return {
38             UID: oldUID,
39             localID: undefined,
40             basename: undefined,
41         };
42     }
43     const { pathname } = window.location;
44     const localID = getLocalIDFromPathname(pathname);
45     if (localID === undefined) {
46         return defaultAuthData;
47     }
48     const persistedSession = getPersistedSession(localID);
49     // Current session is active and actual
50     if (persistedSession && (oldUID === undefined || (persistedSession.UID === oldUID && localID === oldLocalID))) {
51         return {
52             UID: persistedSession.UID,
53             localID,
54             basename: getBasename(localID),
55         };
56     }
57     return defaultAuthData;
60 interface Arguments {
61     mode?: 'sso' | 'standalone';
62     initialAuth?: boolean;
63     store: {
64         set: (key: string, value: any) => void;
65         get: (key: string) => any;
66     };
67     onUID?: (UID: string | undefined) => void;
70 const createAuthenticationStore = ({ mode = appMode, initialAuth, store: { set, get }, onUID }: Arguments) => {
71     const setUID = (UID: string | undefined) => {
72         set(UID_KEY, UID);
73         onUID?.(UID);
74     };
75     const getUID = (): string => get(UID_KEY);
77     const setPassword = (password: string | undefined) => {
78         if (password === undefined) {
79             set(MAILBOX_PASSWORD_KEY, password);
80             return;
81         }
82         set(MAILBOX_PASSWORD_KEY, encodeUtf8Base64(password));
83     };
84     const getPassword = () => {
85         const value: string | undefined = get(MAILBOX_PASSWORD_KEY);
86         if (value === undefined) {
87             return '';
88         }
89         return decodeUtf8Base64(value);
90     };
92     const getLocalID = () => get(LOCAL_ID_KEY);
94     const setLocalID = (LocalID: number | undefined) => {
95         set(LOCAL_ID_KEY, LocalID);
96     };
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);
121     const login = ({
122         UID: newUID,
123         keyPassword,
124         LocalID: newLocalID,
125         persistent,
126         trusted,
127         path,
128         clientKey,
129         offlineKey,
130     }: {
131         UID: string;
132         keyPassword?: string;
133         LocalID: number;
134         persistent: boolean;
135         trusted: boolean;
136         path?: string;
137         clientKey: string;
138         offlineKey: OfflineKey | undefined;
139     }) => {
140         setUID(newUID);
141         setPassword(keyPassword);
142         setPersistent(persistent);
143         setTrusted(trusted);
144         setClientKey(clientKey);
145         setOfflineKey(offlineKey);
147         if (newLocalID !== undefined && mode === 'sso') {
148             setLocalID(newLocalID);
149             basename = getBasename(newLocalID);
150         } else {
151             setLocalID(undefined);
152             basename = undefined;
153         }
155         return getPath(basename, window.location.href, path);
156     };
158     const logout = () => {
159         setUID(undefined);
160         setPassword(undefined);
161         setPersistent(undefined);
162         setLocalID(undefined);
163         setTrusted(undefined);
164         setClientKey(undefined);
165         setOfflineKey(undefined);
166         basename = undefined;
167     };
169     return {
170         getUID,
171         setUID,
172         setLocalID,
173         getLocalID,
174         hasSession,
175         setPassword,
176         getPassword,
177         setPersistent,
178         getPersistent,
179         setClientKey,
180         getClientKey,
181         setOfflineKey,
182         getOfflineKey,
183         setTrusted,
184         getTrusted,
185         logout,
186         login,
187         mode,
188         get UID() {
189             return getUID();
190         },
191         get localID() {
192             return getLocalID();
193         },
194         get basename() {
195             return basename;
196         },
197         get ready(): boolean {
198             return Boolean(initialAuthData.UID && initialUID && getClientKey());
199         },
200     };
203 export type AuthenticationStore = ReturnType<typeof createAuthenticationStore>;
205 export default createAuthenticationStore;