Skip to content

Commit

Permalink
forgot password
Browse files Browse the repository at this point in the history
  • Loading branch information
17Amir17 committed Sep 26, 2024
1 parent 44d840f commit b1fa189
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import {
} from "@pcd/eddsa-ticket-pcd";
import { Spacer } from "@pcd/passport-ui";
import { PCD } from "@pcd/pcd-types";
import {
PODTicketPCD,
PODTicketPCDTypeName,
isPODTicketPCD
} from "@pcd/pod-ticket-pcd";
import {
ReactElement,
useEffect,
Expand All @@ -17,17 +22,12 @@ import {
import { useNavigate } from "react-router-dom";
import styled, { FlattenSimpleInterpolation, css } from "styled-components";
import { AppContainer } from "../../../components/shared/AppContainer";
import { CardBody } from "../../../components/shared/PCDCard";
import { usePCDs, useSelf } from "../../../src/appHooks";
import { useSyncE2EEStorage } from "../../../src/useSyncE2EEStorage";
import { FloatingMenu } from "../../shared/FloatingMenu";
import { CardBody } from "../../../components/shared/PCDCard";
import { TicketCard } from "../../shared/TicketCard";
import { NewModals } from "../../shared/Modals/NewModals";
import {
PODTicketPCD,
PODTicketPCDTypeName,
isPODTicketPCD
} from "@pcd/pod-ticket-pcd";
import { TicketCard } from "../../shared/TicketCard";
import { Typography } from "../../shared/Typography";

const GAP = 4;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,9 @@ export const NewAlreadyRegisteredScreen: React.FC = () => {
useEffect(() => {
if (self || !email || !identityCommitment) {
if (hasPendingRequest()) {
window.location.hash = "#/login-interstitial";
window.location.hash = "#/new/login-interstitial";
} else {
window.location.hash = "#/";
window.location.hash = "#/new";
}
}
}, [self, email, identityCommitment]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,188 @@
export const NewCreatePasswordScreen = (): JSX.Element => {
return <></>;
import { requestVerifyToken } from "@pcd/passport-interface";
import { sleep, validateEmail } from "@pcd/util";
import { useCallback, useEffect, useState } from "react";
import { AppContainer } from "../../../components/shared/AppContainer";
import { appConfig } from "../../../src/appConfig";
import { useDispatch, useQuery, useSelf } from "../../../src/appHooks";
import { hasPendingRequest } from "../../../src/sessionStorage";
import {
LoginContainer,
LoginTitleContainer
} from "../../shared/Login/LoginComponents";
import { NewPasswordForm2 } from "../../shared/Login/NewPasswordForm2";
import { Typography } from "../../shared/Typography";

export const NewCreatePasswordScreen = (): JSX.Element | null => {
const dispatch = useDispatch();
const self = useSelf();
const query = useQuery();
const email = query?.get("email");
const token = query?.get("token");
const autoRegister = query?.get("autoRegister") === "true";
const targetFolder = query?.get("targetFolder");
const [error, setError] = useState<string | undefined>();
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [revealPassword, setRevealPassword] = useState(false);
const [settingPassword, setSettingPassword] = useState(false);
const [skipConfirm, setSkipConfirm] = useState(false);

const redirectToLoginPageWithError = useCallback((e: Error | string) => {
console.error(e);
window.location.hash = "#/login";
window.location.reload();
}, []);

const onSkipPassword = useCallback(async () => {
try {
// If email or token are undefined, we will already have redirected to
// login, so this is just for type-checking
if (email && token) {
setSettingPassword(true);
await sleep();
await dispatch({
type: "create-user-skip-password",
email,
token,
targetFolder,
autoRegister,
newUi: true
});
}
} finally {
setSettingPassword(false);
if (autoRegister) {
window.location.href = "#/new";
}
}
}, [dispatch, email, token, targetFolder, autoRegister]);

const checkIfShouldRedirect = useCallback(async () => {
// Redirect to home if already logged in
if (self) {
// Present alert if we had tried to auto-register with a different
// email than the currently logged-in email.
if (autoRegister && !self.emails.includes(email as string)) {
alert(
`You are already logged in as ${
self.emails.length === 1
? self.emails?.[0]
: "an account that owns the following email addresses: " +
self.emails.join(", ")
}. Please log out and try navigating to the link again.`
);
}

if (hasPendingRequest()) {
window.location.hash = "#/new/login-interstitial";
} else {
window.location.hash = "#/new";
}
return;
}
if (!email || !validateEmail(email) || !token) {
return redirectToLoginPageWithError(
"Invalid email or token, redirecting to login"
);
}

if (autoRegister) {
await onSkipPassword();
} else {
const verifyTokenResult = await requestVerifyToken(
appConfig.zupassServer,
email,
token
);

if (!verifyTokenResult.success) {
return redirectToLoginPageWithError(
"Invalid email or token, redirecting to login"
);
}
}
}, [
self,
email,
redirectToLoginPageWithError,
token,
autoRegister,
onSkipPassword
]);

useEffect(() => {
checkIfShouldRedirect();
}, [checkIfShouldRedirect]);

const onSetPassword = useCallback(async () => {
try {
// If email or token are undefined, we will already have redirected to
// login, so this is just for type-checking
if (email && token) {
setSettingPassword(true);
await sleep();
await dispatch({
type: "login",
email,
token,
password,
newUi: true
});
}
} finally {
setSettingPassword(false);
}
}, [dispatch, email, password, token]);

const onCancelClick = useCallback(() => {
window.location.href = "#/new";
}, []);

// If either email or token are undefined, we will already have redirected
if (!email || !token) {
return null;
}

return (
<AppContainer bg="gray" fullscreen>
<LoginContainer>
<LoginTitleContainer>
<Typography fontSize={24} fontWeight={800} color="#1E2C50">
ADD PASSWORD
</Typography>
<Typography
fontSize={16}
fontWeight={400}
color="#1E2C50"
family="Rubik"
>
Make sure that your password is secure, unique, and memorable. If
you forget your password, you'll have to reset your account, and you
will lose access to all your PCDs.
</Typography>
</LoginTitleContainer>
<NewPasswordForm2
loading={settingPassword}
autoFocus
error={error}
setError={setError}
emails={[email]}
revealPassword={revealPassword}
setRevealPassword={setRevealPassword}
submitButtonText={settingPassword ? "Confirming..." : "Confirm"}
password={password}
confirmPassword={confirmPassword}
setPassword={setPassword}
setConfirmPassword={setConfirmPassword}
onSuccess={onSetPassword}
onCancel={onCancelClick}
// showSkipConfirm={!skipConfirm}
// onSkipConfirm={(): void => {
// onSkipPassword();
// }}
style={{ width: "100%", marginBottom: 24 }}
/>
</LoginContainer>
</AppContainer>
);
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Dispatch, SetStateAction, UIEvent, useRef } from "react";
import styled from "styled-components";
import { useDispatch } from "../../../src/appHooks";
import {
PASSWORD_MINIMUM_LENGTH,
checkPasswordStrength
Expand All @@ -18,11 +17,15 @@ interface NewPasswordForm {
revealPassword: boolean;
setRevealPassword: Dispatch<SetStateAction<boolean>>;
onSuccess: () => void;
onCancel: () => void;
submitButtonText: string;
passwordInputPlaceholder?: string; // Override placeholder on the first input
autoFocus?: boolean;
setError: Dispatch<SetStateAction<string | undefined>>;
error?: string;
showSkipConfirm?: boolean;
onSkipConfirm?: () => void;
style?: React.CSSProperties;
}

export const NewPasswordForm2 = ({
Expand All @@ -35,13 +38,16 @@ export const NewPasswordForm2 = ({
revealPassword,
setRevealPassword,
onSuccess,
onCancel,
submitButtonText,
passwordInputPlaceholder,
autoFocus,
setError,
error
error,
showSkipConfirm,
onSkipConfirm,
style
}: NewPasswordForm): JSX.Element => {
const dispatch = useDispatch();
const confirmPasswordRef = useRef<HTMLInputElement>(null);

const checkPasswordAndSubmit = (e: UIEvent): void => {
Expand Down Expand Up @@ -87,7 +93,7 @@ export const NewPasswordForm2 = ({
};

return (
<PasswordForm>
<PasswordForm style={style}>
{/* For password manager autofill */}
<input hidden readOnly value={emails[0]} />
<InputsContainer>
Expand Down Expand Up @@ -125,19 +131,14 @@ export const NewPasswordForm2 = ({
<Button2 onClick={checkPasswordAndSubmit} disabled={!!error || loading}>
{submitButtonText}
</Button2>
<Button2
onClick={() => {
dispatch({
type: "set-bottom-modal",
modal: {
modalType: "settings"
}
});
}}
variant="secondary"
>
<Button2 onClick={onCancel} variant="secondary">
Back
</Button2>
{showSkipConfirm && (
<Button2 onClick={onSkipConfirm} variant="danger">
Skip for now
</Button2>
)}
</InputsContainer>
</PasswordForm>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@ export const ChangePasswordModal = (): JSX.Element | null => {
setPassword={setNewPassword}
setConfirmPassword={setConfirmPassword}
onSuccess={onChangePassword}
onCancel={() => {
dispatch({
type: "set-bottom-modal",
modal: {
modalType: "settings"
}
});
}}
/>
</Container>
</BottomModal>
Expand Down
15 changes: 12 additions & 3 deletions apps/passport-client/src/dispatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export type Action =
email: string;
password: string;
token: string;
newUi?: boolean;
}
| {
type: "one-click-login";
Expand Down Expand Up @@ -234,7 +235,8 @@ export async function dispatch(
action.token,
action.password,
state,
update
update,
action.newUi
);
case "one-click-login":
return oneClickLogin(
Expand Down Expand Up @@ -520,7 +522,8 @@ async function createNewUserWithPassword(
token: string,
password: string,
state: AppState,
update: ZuUpdate
update: ZuUpdate,
newUi = false
): Promise<void> {
const crypto = await PCDCrypto.newInstance();
const { salt: newSalt, key: encryptionKey } =
Expand All @@ -544,7 +547,13 @@ async function createNewUserWithPassword(
);

if (newUserResult.success) {
return finishAccountCreation(newUserResult.value, state, update);
return finishAccountCreation(
newUserResult.value,
state,
update,
undefined,
newUi
);
}

update({
Expand Down

0 comments on commit b1fa189

Please sign in to comment.