This commit is contained in:
Manav Rathi 2024-12-30 16:34:13 +05:30
parent a4e09a40e8
commit 64a47694d0
No known key found for this signature in database
5 changed files with 76 additions and 47 deletions

View File

@ -1,7 +1,7 @@
import type { TwoFactorAuthorizationResponse } from "@/accounts/services/user";
import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator";
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
import log from "@/base/log";
import type { TwoFactorAuthorizationResponse } from "@/base/types/credentials";
import { nullToUndefined } from "@/utils/transform";
import { VerticallyCentered } from "@ente/shared/components/Container";
import InfoIcon from "@mui/icons-material/Info";

View File

@ -1,3 +1,4 @@
import type { TwoFactorAuthorizationResponse } from "@/accounts/services/user";
import { clientPackageName } from "@/base/app";
import {
fromB64URLSafeNoPadding,
@ -7,7 +8,6 @@ import {
import { isDevBuild } from "@/base/env";
import { ensureOk, HTTPError, publicRequestHeaders } from "@/base/http";
import { apiURL } from "@/base/origins";
import { TwoFactorAuthorizationResponse } from "@/base/types/credentials";
import { nullToUndefined } from "@/utils/transform";
import { z } from "zod";

View File

@ -9,7 +9,7 @@ import {
} from "@/base/http";
import log from "@/base/log";
import { accountsAppOrigin, apiURL } from "@/base/origins";
import { TwoFactorAuthorizationResponse } from "@/base/types/credentials";
import type { TwoFactorAuthorizationResponse } from "@/accounts/services/user";
import { nullToUndefined } from "@/utils/transform";
import { getRecoveryKey } from "@ente/shared/crypto/helpers";
import HTTPService from "@ente/shared/network/HTTPService";

View File

@ -5,9 +5,11 @@ import {
publicRequestHeaders,
} from "@/base/http";
import { apiURL } from "@/base/origins";
import { nullToUndefined } from "@/utils/transform";
import HTTPService from "@ente/shared/network/HTTPService";
import { getToken } from "@ente/shared/storage/localStorage/helpers";
import type { KeyAttributes } from "@ente/shared/user/types";
import { z } from "zod";
export interface UserVerificationResponse {
id: number;
@ -107,6 +109,77 @@ export const verifyEmail = async (
});
};
/**
* Zod schema for {@link KeyAttributes}.
*/
const RemoteKeyAttributes = z.object({
kekSalt: z.string(),
encryptedKey: z.string(),
keyDecryptionNonce: z.string(),
publicKey: z.string(),
encryptedSecretKey: z.string(),
secretKeyDecryptionNonce: z.string(),
memLimit: z.number(),
opsLimit: z.number(),
masterKeyEncryptedWithRecoveryKey: z
.string()
.nullish()
.transform(nullToUndefined),
masterKeyDecryptionNonce: z.string().nullish().transform(nullToUndefined),
recoveryKeyEncryptedWithMasterKey: z
.string()
.nullish()
.transform(nullToUndefined),
recoveryKeyDecryptionNonce: z.string().nullish().transform(nullToUndefined),
});
/**
* Zod schema for response from remote on a successful user verification, either
* via {@link verifyEmail} or {@link verifySRPSession}.
*
* If a second factor is enabled than one of the two factor session IDs
* (`passkeySessionID`, `twoFactorSessionID` / `twoFactorSessionIDV2`) will be
* set. Otherwise `keyAttributes` and `encryptedToken` will be set.
*/
export const RemoteUserVerificationResponse = z.object({
id: z.number(),
keyAttributes: RemoteKeyAttributes.nullish().transform(nullToUndefined),
encryptedToken: z.string().nullish().transform(nullToUndefined),
token: z.string().nullish().transform(nullToUndefined),
passkeySessionID: z.string().nullish().transform(nullToUndefined),
// The baseURL of the accounts app, where we should redirect to for passkey
// validation.
accountsUrl: z.string().nullish().transform(nullToUndefined),
twoFactorSessionID: z.string().nullish().transform(nullToUndefined),
// TwoFactorSessionIDV2 is only set if user has both passkey and two factor
// enabled. This is to ensure older clients keep using passkey flow when
// both are set. It is intended to be removed once all clients starts
// surfacing both options for performing 2FA.
//
// See `useSecondFactorChoiceIfNeeded`.
twoFactorSessionIDV2: z.string().nullish().transform(nullToUndefined),
// srpM2 is sent only if the user is logging via SRP. It is is the SRP M2
// value aka the proof that the server has the verifier.
srpM2: z.string().nullish().transform(nullToUndefined),
});
/**
* The result of a successful two factor verification (totp or passkey).
*/
const TwoFactorAuthorizationResponse = z.object({
id: z.number(),
/** TODO: keyAttributes is guaranteed to be returned by museum, update the
* types to reflect that. */
keyAttributes: RemoteKeyAttributes.nullish().transform(nullToUndefined),
/** TODO: encryptedToken is guaranteed to be returned by museum, update the
* types to reflect that. */
encryptedToken: z.string().nullish().transform(nullToUndefined),
});
export type TwoFactorAuthorizationResponse = z.infer<
typeof TwoFactorAuthorizationResponse
>;
export const putAttributes = async (
token: string,
keyAttributes: KeyAttributes,

View File

@ -1,44 +0,0 @@
import { nullToUndefined } from "@/utils/transform";
import { z } from "zod";
// TODO: Provide types
/**
* Zod schema for {@link KeyAttributes}.
*/
export const KeyAttributes = z.object({
kekSalt: z.string(),
encryptedKey: z.string(),
keyDecryptionNonce: z.string(),
publicKey: z.string(),
encryptedSecretKey: z.string(),
secretKeyDecryptionNonce: z.string(),
memLimit: z.number(),
opsLimit: z.number(),
masterKeyEncryptedWithRecoveryKey: z
.string()
.nullish()
.transform(nullToUndefined),
masterKeyDecryptionNonce: z.string().nullish().transform(nullToUndefined),
recoveryKeyEncryptedWithMasterKey: z
.string()
.nullish()
.transform(nullToUndefined),
recoveryKeyDecryptionNonce: z.string().nullish().transform(nullToUndefined),
});
/**
* The result of a successful two factor verification (totp or passkey).
*/
export const TwoFactorAuthorizationResponse = z.object({
id: z.number(),
/** TODO: keyAttributes is guaranteed to be returned by museum, update the
* types to reflect that. */
keyAttributes: KeyAttributes.nullish().transform(nullToUndefined),
/** TODO: encryptedToken is guaranteed to be returned by museum, update the
* types to reflect that. */
encryptedToken: z.string().nullish().transform(nullToUndefined),
});
export type TwoFactorAuthorizationResponse = z.infer<
typeof TwoFactorAuthorizationResponse
>;