1 import { api } from '@proton/pass/lib/api/api';
2 import { type OfflineComponents, getOfflineKeyDerivation } from '@proton/pass/lib/cache/crypto';
3 import { decryptData, importSymmetricKey } from '@proton/pass/lib/crypto/utils/crypto-helpers';
4 import { PassEncryptionTag } from '@proton/pass/types';
5 import { queryUnlock } from '@proton/shared/lib/api/user';
6 import { stringToUint8Array } from '@proton/shared/lib/helpers/encoding';
7 import { srpAuth, srpGetVerify } from '@proton/shared/lib/srp';
8 import { getSrp } from '@proton/srp/lib';
9 import type { AuthInfo } from '@proton/srp/lib/interface';
11 import type { AuthStore } from './store';
13 export enum PasswordVerification {
19 export type PasswordCredentials = { password: string };
20 export type PasswordConfirmDTO = PasswordCredentials & { mode?: PasswordVerification };
21 export type ExtraPasswordDTO = PasswordCredentials & { enabled: boolean };
23 export const getPasswordVerification = (authStore: AuthStore) => {
24 const offlineConfig = authStore.getOfflineConfig();
25 const offlineVerifier = authStore.getOfflineVerifier();
26 const extraPassword = authStore.getExtraPassword();
27 const localVerification = offlineConfig && offlineVerifier;
29 if (localVerification) return PasswordVerification.LOCAL;
30 if (extraPassword) return PasswordVerification.EXTRA_PASSWORD;
31 return PasswordVerification.SRP;
34 export const registerExtraPassword = async (credentials: PasswordCredentials) => {
35 const { Auth } = await srpGetVerify({ api, credentials });
38 url: 'pass/v1/user/srp',
41 SrpModulusID: Auth.ModulusID,
42 SrpVerifier: Auth.Verifier,
48 export const removeExtraPassword = async () => api({ url: 'pass/v1/user/srp', method: 'delete' });
50 /** Checks that the given password can be verified against the `offlineVerifier`.
51 * If we can successfully decrypt the `offlineVerifier`, then password is correct */
52 export const verifyOfflinePassword = async (
54 { offlineVerifier, offlineConfig: { salt, params } }: Omit<OfflineComponents, 'offlineKD'>
55 ): Promise<boolean> => {
56 const offlineKD = await getOfflineKeyDerivation(password, stringToUint8Array(salt), params);
57 const offlineKey = await importSymmetricKey(offlineKD);
58 await decryptData(offlineKey, stringToUint8Array(offlineVerifier), PassEncryptionTag.Offline);
63 /** Verifies a proton user's encryption password via SRP */
64 export const verifyPassword = async (credentials: PasswordCredentials): Promise<boolean> => {
65 await srpAuth({ api, credentials, config: { ...queryUnlock(), silence: true } });
69 /** Verifies the pass specific extra-password via SRP */
70 export const verifyExtraPassword = async (credentials: PasswordCredentials): Promise<boolean> => {
71 const info = (await api({ url: 'pass/v1/user/srp/info', method: 'get' })).SRPData!;
73 const { Version, SrpSalt: Salt, Modulus, ServerEphemeral } = info;
74 const authInfo: AuthInfo = { ServerEphemeral, Modulus, Version, Salt };
76 const srp = await getSrp(authInfo, credentials, Version);
79 url: 'pass/v1/user/srp/auth',
82 ClientEphemeral: srp.clientEphemeral,
83 ClientProof: srp.clientProof,
84 SrpSessionID: info.SrpSessionID,