change-password.tsx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import { t } from "i18next";
  2. import { useEffect, useState } from "react";
  3. import {
  4. generateSRPClient,
  5. generateSRPSetupAttributes,
  6. } from "@ente/accounts/services/srp";
  7. import {
  8. generateAndSaveIntermediateKeyAttributes,
  9. generateLoginSubKey,
  10. saveKeyInSessionStore,
  11. } from "@ente/shared/crypto/helpers";
  12. import { LS_KEYS, getData, setData } from "@ente/shared/storage/localStorage";
  13. import { startSRPSetup, updateSRPAndKeys } from "@ente/accounts/api/srp";
  14. import SetPasswordForm, {
  15. SetPasswordFormProps,
  16. } from "@ente/accounts/components/SetPasswordForm";
  17. import { PAGES } from "@ente/accounts/constants/pages";
  18. import { UpdatedKey } from "@ente/accounts/types/user";
  19. import { SESSION_KEYS } from "@ente/shared/storage/sessionStorage";
  20. import { getActualKey } from "@ente/shared/user";
  21. import { KEK, KeyAttributes, User } from "@ente/shared/user/types";
  22. import {
  23. convertBase64ToBuffer,
  24. convertBufferToBase64,
  25. } from "@ente/accounts/utils";
  26. import { APP_HOMES } from "@ente/shared/apps/constants";
  27. import { PageProps } from "@ente/shared/apps/types";
  28. import { VerticallyCentered } from "@ente/shared/components/Container";
  29. import FormPaper from "@ente/shared/components/Form/FormPaper";
  30. import FormPaperFooter from "@ente/shared/components/Form/FormPaper/Footer";
  31. import FormPaperTitle from "@ente/shared/components/Form/FormPaper/Title";
  32. import LinkButton from "@ente/shared/components/LinkButton";
  33. import ComlinkCryptoWorker from "@ente/shared/crypto";
  34. import InMemoryStore, { MS_KEYS } from "@ente/shared/storage/InMemoryStore";
  35. export default function ChangePassword({ appName, router }: PageProps) {
  36. const [token, setToken] = useState<string>();
  37. const [user, setUser] = useState<User>();
  38. useEffect(() => {
  39. const user = getData(LS_KEYS.USER);
  40. setUser(user);
  41. if (!user?.token) {
  42. InMemoryStore.set(MS_KEYS.REDIRECT_URL, PAGES.CHANGE_PASSWORD);
  43. router.push(PAGES.ROOT);
  44. } else {
  45. setToken(user.token);
  46. }
  47. }, []);
  48. const onSubmit: SetPasswordFormProps["callback"] = async (
  49. passphrase,
  50. setFieldError,
  51. ) => {
  52. const cryptoWorker = await ComlinkCryptoWorker.getInstance();
  53. const key = await getActualKey();
  54. const keyAttributes: KeyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
  55. const kekSalt = await cryptoWorker.generateSaltToDeriveKey();
  56. let kek: KEK;
  57. try {
  58. kek = await cryptoWorker.deriveSensitiveKey(passphrase, kekSalt);
  59. } catch (e) {
  60. setFieldError("confirm", t("PASSWORD_GENERATION_FAILED"));
  61. return;
  62. }
  63. const encryptedKeyAttributes = await cryptoWorker.encryptToB64(
  64. key,
  65. kek.key,
  66. );
  67. const updatedKey: UpdatedKey = {
  68. kekSalt,
  69. encryptedKey: encryptedKeyAttributes.encryptedData,
  70. keyDecryptionNonce: encryptedKeyAttributes.nonce,
  71. opsLimit: kek.opsLimit,
  72. memLimit: kek.memLimit,
  73. };
  74. const loginSubKey = await generateLoginSubKey(kek.key);
  75. const { srpUserID, srpSalt, srpVerifier } =
  76. await generateSRPSetupAttributes(loginSubKey);
  77. const srpClient = await generateSRPClient(
  78. srpSalt,
  79. srpUserID,
  80. loginSubKey,
  81. );
  82. const srpA = convertBufferToBase64(srpClient.computeA());
  83. const { setupID, srpB } = await startSRPSetup(token, {
  84. srpUserID,
  85. srpSalt,
  86. srpVerifier,
  87. srpA,
  88. });
  89. srpClient.setB(convertBase64ToBuffer(srpB));
  90. const srpM1 = convertBufferToBase64(srpClient.computeM1());
  91. await updateSRPAndKeys(token, {
  92. setupID,
  93. srpM1,
  94. updatedKeyAttr: updatedKey,
  95. });
  96. const updatedKeyAttributes = Object.assign(keyAttributes, updatedKey);
  97. await generateAndSaveIntermediateKeyAttributes(
  98. passphrase,
  99. updatedKeyAttributes,
  100. key,
  101. );
  102. await saveKeyInSessionStore(SESSION_KEYS.ENCRYPTION_KEY, key);
  103. redirectToAppHome();
  104. };
  105. const redirectToAppHome = () => {
  106. setData(LS_KEYS.SHOW_BACK_BUTTON, { value: true });
  107. router.push(APP_HOMES.get(appName));
  108. };
  109. return (
  110. <VerticallyCentered>
  111. <FormPaper>
  112. <FormPaperTitle>{t("CHANGE_PASSWORD")}</FormPaperTitle>
  113. <SetPasswordForm
  114. userEmail={user?.email}
  115. callback={onSubmit}
  116. buttonText={t("CHANGE_PASSWORD")}
  117. />
  118. {(getData(LS_KEYS.SHOW_BACK_BUTTON)?.value ?? true) && (
  119. <FormPaperFooter>
  120. <LinkButton onClick={router.back}>
  121. {t("GO_BACK")}
  122. </LinkButton>
  123. </FormPaperFooter>
  124. )}
  125. </FormPaper>
  126. </VerticallyCentered>
  127. );
  128. }