Merge: fix dual-2FA login against real server (empty-string fields)
This commit is contained in:
@@ -76,8 +76,12 @@ const srpHandshake = async (
|
||||
// twoFactorSessionIDV2 is set (instead of twoFactorSessionID) when the
|
||||
// account has BOTH passkeys and TOTP. Prefer TOTP: a CLI cannot perform
|
||||
// a WebAuthn ceremony, and the user has a TOTP secret enrolled.
|
||||
//
|
||||
// The server marshals these fields without `omitempty`, so unset fields
|
||||
// arrive as "" rather than being absent. Use || (not ??) so empty
|
||||
// strings are treated as not-set.
|
||||
const totpSessionID =
|
||||
verifyResponse.twoFactorSessionID ??
|
||||
verifyResponse.twoFactorSessionID ||
|
||||
verifyResponse.twoFactorSessionIDV2;
|
||||
if (totpSessionID) {
|
||||
return { kind: "totp", sessionID: totpSessionID };
|
||||
|
||||
@@ -200,11 +200,25 @@ const buildMockFetch = (
|
||||
srpServer.checkM1(Buffer.from(body.srpM1, "base64"));
|
||||
const M2 = srpServer.computeM2();
|
||||
|
||||
// IMPORTANT: the museum server's EmailAuthorizationResponse
|
||||
// (server/ente/user.go) declares passkeySessionID, accountsUrl,
|
||||
// twoFactorSessionID, and twoFactorSessionIDV2 WITHOUT the
|
||||
// `omitempty` JSON tag. Go therefore always serializes them,
|
||||
// sending "" (empty string, NOT null/absent) for any that do
|
||||
// not apply. These mocks must reproduce that faithfully: a
|
||||
// client that distinguishes fields with `??` instead of `||`
|
||||
// passes against an omitting mock but breaks against the real
|
||||
// server.
|
||||
|
||||
if (opts?.requireTOTP) {
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
id: 42,
|
||||
srpM2: M2.toString("base64"),
|
||||
passkeySessionID: "",
|
||||
accountsUrl: "",
|
||||
twoFactorSessionID: "totp-session-999",
|
||||
twoFactorSessionIDV2: "",
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
@@ -218,11 +232,14 @@ const buildMockFetch = (
|
||||
// server sets passkeySessionID + twoFactorSessionIDV2 (not
|
||||
// twoFactorSessionID -- that's deliberate, so old clients
|
||||
// that only know the V1 field keep using the passkey flow).
|
||||
// The V1 field is still present on the wire as "".
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
id: 42,
|
||||
srpM2: M2.toString("base64"),
|
||||
passkeySessionID: "passkey-session-123",
|
||||
accountsUrl: "https://accounts.ente.io",
|
||||
twoFactorSessionID: "",
|
||||
twoFactorSessionIDV2: "totp-session-v2-456",
|
||||
}),
|
||||
{
|
||||
@@ -238,6 +255,10 @@ const buildMockFetch = (
|
||||
id: 42,
|
||||
keyAttributes: fixture.keyAttributes,
|
||||
encryptedToken: fixture.encryptedToken,
|
||||
passkeySessionID: "",
|
||||
accountsUrl: "",
|
||||
twoFactorSessionID: "",
|
||||
twoFactorSessionIDV2: "",
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
|
||||
Reference in New Issue
Block a user