1 import { revoke } from '@proton/shared/lib/api/auth';
2 import { getSettings, upgradePassword } from '@proton/shared/lib/api/settings';
3 import { maybeResumeSessionByUser, persistSession } from '@proton/shared/lib/authentication/persistedSessionHelper';
4 import { APPS } from '@proton/shared/lib/constants';
5 import type { UserSettings } from '@proton/shared/lib/interfaces';
6 import { getDecryptedUserKeysHelper } from '@proton/shared/lib/keys';
9 getIsDeviceRecoveryAvailable,
12 } from '@proton/shared/lib/recoveryFile/deviceRecovery';
13 import { srpVerify } from '@proton/shared/lib/srp';
14 import { AUTH_VERSION } from '@proton/srp';
15 import noop from '@proton/utils/noop';
17 import type { AuthActionResponse, AuthCacheResult } from './interface';
18 import { AuthStep } from './interface';
19 import { syncAddresses, syncUser } from './syncCache';
22 * Finalize login can be called without a key password in these cases:
24 * 2) Users who have no keys but are in 2-password mode
26 export const finalizeLogin = async ({
33 cache: AuthCacheResult;
34 loginPassword: string;
36 clearKeyPassword?: string;
37 attemptResume?: boolean;
38 }): Promise<AuthActionResponse> => {
39 const { authResponse, authVersion, api, persistent, appName, preAuthKTVerifier } = cache;
41 if (authVersion < AUTH_VERSION) {
44 credentials: { password: loginPassword },
45 config: upgradePassword(),
49 if (appName !== APPS.PROTONACCOUNT) {
50 const user = cache.data.user || (await syncUser(cache));
51 const trusted = false;
53 const { clientKey, offlineKey } = await persistSession({
55 clearKeyPassword: clearKeyPassword || '',
79 let [user, addresses] = await Promise.all([
80 cache.data.user || syncUser(cache),
81 cache.data.addresses || syncAddresses(cache),
84 const validatedSession = attemptResume ? await maybeResumeSessionByUser(api, user) : null;
85 if (validatedSession) {
86 await api(revoke()).catch(noop);
89 session: { ...validatedSession, loginPassword, flow: 'login' },
95 const numberOfReactivatedKeys = await attemptDeviceRecovery({
100 preAuthKTVerify: preAuthKTVerifier.preAuthKTVerify,
103 if (numberOfReactivatedKeys !== undefined && numberOfReactivatedKeys > 0) {
104 cache.data.user = undefined;
105 cache.data.addresses = undefined;
106 [user, addresses] = await Promise.all([syncUser(cache), syncAddresses(cache)]);
109 // Store device recovery information
111 const [userKeys] = await Promise.all([getDecryptedUserKeysHelper(user, keyPassword)]);
112 const isDeviceRecoveryAvailable = getIsDeviceRecoveryAvailable({
119 if (isDeviceRecoveryAvailable) {
120 const userSettings = await api<{ UserSettings: UserSettings }>(getSettings()).then(
121 ({ UserSettings }) => UserSettings
124 if (userSettings.DeviceRecovery) {
125 const deviceRecoveryUpdated = await storeDeviceRecovery({ api, user, userKeys }).catch(noop);
126 if (deviceRecoveryUpdated) {
127 // Storing device recovery (when setting a new recovery secret) modifies the user object
128 cache.data.user = undefined;
129 user = await syncUser(cache);
135 removeDeviceRecovery(user.ID);
139 const { clientKey, offlineKey } = await persistSession({
141 clearKeyPassword: clearKeyPassword || '',
149 await preAuthKTVerifier.preAuthKTCommit(user.ID, api);