Merge branch 'main' into download-album

This commit is contained in:
Abhinav 2023-09-04 21:10:49 +05:30
commit 22b170399f
6 changed files with 88 additions and 45 deletions

View file

@ -16,9 +16,9 @@ export interface VerifyMasterPasswordFormProps {
keyAttributes: KeyAttributes;
callback: (
key: string,
passphrase: string,
kek: string,
keyAttributes: KeyAttributes
keyAttributes: KeyAttributes,
passphrase?: string
) => void;
buttonText: string;
submitButtonProps?: ButtonProps;
@ -74,12 +74,17 @@ export default function VerifyMasterPasswordForm({
keyAttributes.keyDecryptionNonce,
kek
);
callback(key, passphrase, kek, keyAttributes);
callback(key, kek, keyAttributes, passphrase);
} catch (e) {
logError(e, 'user entered a wrong password');
throw Error(CustomError.INCORRECT_PASSWORD);
}
} catch (e) {
if (e.message === CustomError.TWO_FACTOR_ENABLED) {
// two factor enabled, user has been redirected to two factor page
return;
}
logError(e, 'failed to verify passphrase');
switch (e.message) {
case CustomError.WEAK_DEVICE:
setFieldError(t('WEAK_DEVICE'));

View file

@ -10,7 +10,12 @@ import {
} from 'utils/storage/localStorage';
import { useRouter } from 'next/router';
import { PAGES } from 'constants/pages';
import { SESSION_KEYS, getKey, setKey } from 'utils/storage/sessionStorage';
import {
SESSION_KEYS,
getKey,
removeKey,
setKey,
} from 'utils/storage/sessionStorage';
import {
decryptAndStoreToken,
generateAndSaveIntermediateKeyAttributes,
@ -42,6 +47,7 @@ import { APPS, getAppName } from 'constants/apps';
import { addLocalLog } from 'utils/logging';
import ComlinkCryptoWorker from 'utils/comlink/ComlinkCryptoWorker';
import { B64EncryptionResult } from 'types/crypto';
import { CustomError } from 'utils/error';
export default function Credentials() {
const router = useRouter();
@ -79,6 +85,7 @@ export default function Credentials() {
LS_KEYS.KEY_ATTRIBUTES
);
if (kekEncryptedAttributes && keyAttributes) {
removeKey(SESSION_KEYS.KEY_ENCRYPTION_KEY);
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
const kek = await cryptoWorker.decryptB64(
kekEncryptedAttributes.encryptedData,
@ -90,8 +97,7 @@ export default function Credentials() {
keyAttributes.keyDecryptionNonce,
kek
);
await saveKeyInSessionStore(SESSION_KEYS.ENCRYPTION_KEY, key);
router.push(PAGES.GALLERY);
useMasterPassword(key, kek, keyAttributes, kek);
return;
}
@ -122,45 +128,61 @@ export default function Credentials() {
appContext.showNavBar(true);
}, []);
const getKeyAttributes = async (kek: string) => {
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
const { keyAttributes, encryptedToken, token, id, twoFactorSessionID } =
await loginViaSRP(srpAttributes, kek);
setData(LS_KEYS.KEY_ATTRIBUTES, keyAttributes);
if (twoFactorSessionID) {
const sessionKeyAttributes =
await cryptoWorker.generateKeyAndEncryptToB64(kek);
setKey(SESSION_KEYS.KEY_ENCRYPTION_KEY, sessionKeyAttributes);
const user = getData(LS_KEYS.USER);
setData(LS_KEYS.USER, {
...user,
twoFactorSessionID,
isTwoFactorEnabled: true,
});
setIsFirstLogin(true);
router.push(PAGES.TWO_FACTOR_VERIFY);
return null;
} else {
const user = getData(LS_KEYS.USER);
setData(LS_KEYS.USER, {
...user,
token,
encryptedToken,
id,
isTwoFactorEnabled: false,
});
return keyAttributes;
}
};
const getKeyAttributes: VerifyMasterPasswordFormProps['getKeyAttributes'] =
async (kek: string) => {
try {
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
const {
keyAttributes,
encryptedToken,
token,
id,
twoFactorSessionID,
} = await loginViaSRP(srpAttributes, kek);
setData(LS_KEYS.KEY_ATTRIBUTES, keyAttributes);
if (twoFactorSessionID) {
const sessionKeyAttributes =
await cryptoWorker.generateKeyAndEncryptToB64(kek);
setKey(
SESSION_KEYS.KEY_ENCRYPTION_KEY,
sessionKeyAttributes
);
const user = getData(LS_KEYS.USER);
setData(LS_KEYS.USER, {
...user,
twoFactorSessionID,
isTwoFactorEnabled: true,
});
setIsFirstLogin(true);
router.push(PAGES.TWO_FACTOR_VERIFY);
throw Error(CustomError.TWO_FACTOR_ENABLED);
} else {
const user = getData(LS_KEYS.USER);
setData(LS_KEYS.USER, {
...user,
token,
encryptedToken,
id,
isTwoFactorEnabled: false,
});
return keyAttributes;
}
} catch (e) {
if (e.message !== CustomError.TWO_FACTOR_ENABLED) {
logError(e, 'getKeyAttributes failed');
}
throw e;
}
};
const useMasterPassword: VerifyMasterPasswordFormProps['callback'] = async (
key,
passphrase,
kek,
keyAttributes
keyAttributes,
passphrase
) => {
try {
if (isFirstLogin()) {
if (isFirstLogin() && passphrase) {
await generateAndSaveIntermediateKeyAttributes(
passphrase,
keyAttributes,

View file

@ -202,7 +202,7 @@ export async function generateKeyAndEncryptToB64(data: string) {
}
export async function encryptUTF8(data: string, key: string) {
const b64Data = await toB64(await fromString(data));
const b64Data = await toB64(await fromUTF8(data));
return await encryptToB64(b64Data, key);
}
@ -281,7 +281,7 @@ export async function deriveKey(
return await toB64(
sodium.crypto_pwhash(
sodium.crypto_secretbox_KEYBYTES,
await fromString(passphrase),
await fromUTF8(passphrase),
await fromB64(salt),
opsLimit,
memLimit,
@ -315,7 +315,7 @@ export async function deriveInteractiveKey(passphrase: string, salt: string) {
const key = await toB64(
sodium.crypto_pwhash(
sodium.crypto_secretbox_KEYBYTES,
await fromString(passphrase),
await fromUTF8(passphrase),
await fromB64(salt),
sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,
sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,
@ -402,10 +402,15 @@ export async function toURLSafeB64(input: Uint8Array) {
return sodium.to_base64(input, sodium.base64_variants.URLSAFE);
}
export async function fromString(input: string) {
export async function fromUTF8(input: string) {
await sodium.ready;
return sodium.from_string(input);
}
export async function toUTF8(input: string) {
await sodium.ready;
return sodium.to_string(await fromB64(input));
}
export async function toHex(input: string) {
await sodium.ready;
return sodium.to_hex(await fromB64(input));

View file

@ -71,6 +71,7 @@ export const CustomError = {
NON_PREVIEWABLE_FILE: 'non previewable file',
PROCESSING_FAILED: 'processing failed',
EXPORT_RECORD_JSON_PARSING_FAILED: 'export record json parsing failed',
TWO_FACTOR_ENABLED: 'two factor enabled',
};
export function parseUploadErrorCodes(error) {

View file

@ -17,6 +17,13 @@ export const getKey = (key: SESSION_KEYS) => {
return JSON.parse(sessionStorage.getItem(key));
};
export const removeKey = (key: SESSION_KEYS) => {
if (typeof sessionStorage === 'undefined') {
return null;
}
sessionStorage.removeItem(key);
};
export const clearKeys = () => {
if (typeof sessionStorage === 'undefined') {
return null;

View file

@ -151,8 +151,11 @@ export class DedicatedCryptoWorker {
return libsodium.generateSubKey(key, subKeyLength, subKeyID, context);
}
async fromString(string: string) {
return libsodium.fromString(string);
async fromUTF8(string: string) {
return libsodium.fromUTF8(string);
}
async toUTF8(data: string) {
return libsodium.toUTF8(data);
}
async toB64(data: Uint8Array) {