// Copyright (c) 2020-2021 Drew Lemmy // This file is part of KristWeb 2 under GPL-3.0. // Full details: https://github.com/tmpim/KristWeb2/blob/master/LICENSE.txt import { toHex } from "@utils"; import { aesGcmEncrypt, aesGcmDecrypt } from "@utils/crypto"; import { store } from "@app"; import * as actions from "@actions/MasterPasswordActions"; import { TranslatedError } from "@utils/i18n"; /** Verifies that the given master password is correct, and dispatches the * auth action to the Redux store. */ export async function authMasterPassword( salt: string | undefined, tester: string | undefined, password: string ): Promise<void> { if (!password) throw new TranslatedError("masterPassword.errorPasswordRequired"); if (!salt || !tester) throw new TranslatedError("masterPassword.errorPasswordUnset"); try { // Attempt to decrypt the tester with the given password const testerDec = await aesGcmDecrypt(tester, password); // Verify that the decrypted tester is equal to the salt, if not, the // provided master password is incorrect. if (testerDec !== salt) throw new TranslatedError("masterPassword.errorPasswordIncorrect"); } catch (e) { // OperationError usually means decryption failure if (e.name === "OperationError") throw new TranslatedError("masterPassword.errorPasswordIncorrect"); else throw e; } // Dispatch the auth state changes to the Redux store store.dispatch(actions.authMasterPassword(password)); } /** Generates a salt and tester, sets the master password, and dispatches the * action to the Redux store. */ export async function setMasterPassword(password: string): Promise<void> { if (!password) throw new TranslatedError("masterPassword.errorPasswordRequired"); // Generate the salt (to be encrypted with the master password) const salt = window.crypto.getRandomValues(new Uint8Array(32)); const saltHex = toHex(salt); // Generate the encryption tester const tester = await aesGcmEncrypt(saltHex, password); // Store them in local storage localStorage.setItem("salt", saltHex); localStorage.setItem("tester", tester); // Dispatch the auth state changes to the Redux store store.dispatch(actions.setMasterPassword(saltHex, tester, password)); }