fix(auth): compare credential snapshots by value for web handoff

This commit is contained in:
heggria
2026-10-26 17:36:41 +08:00
parent 99013315cb
commit 63fa0a9960
2 changed files with 28 additions and 1 deletions
+2 -1
View File
@@ -8,6 +8,7 @@ import { createHash, randomUUID } from 'node:crypto';
import dns from 'node:dns';
import http from 'node:http';
import https from 'node:https';
import { isDeepStrictEqual } from 'node:util';
import zlib from 'node:zlib';
import {
@@ -1110,7 +1111,7 @@ export function registerVelaRoutes(app: Express, deps: RegisterVelaRoutesDeps):
if (typeof req.body?.target !== 'string') { res.status(400).json({error:'invalid_target'}); return; }
const revision = readVelaCredentialRevision(env, configuredEnv);
const result = await createVelaWebIntent({...context,consoleOrigin,target:req.body.target});
if (readVelaCredentialRevision(env, configuredEnv) !== revision) { res.status(409).json({error:'account_changed'}); return; }
if (!isDeepStrictEqual(readVelaCredentialRevision(env, configuredEnv), revision)) { res.status(409).json({error:'account_changed'}); return; }
res.json(result);
} catch (error) {
const code = error instanceof Error ? error.message : 'amr_web_intent_unavailable';
@@ -290,6 +290,32 @@ afterEach(async () => {
}
});
describe('POST /api/amr/web-intent', () => {
it.each([false, true])('checks credential content across the upstream request (changed=%s)', async (changed) => {
const previousOrigin = process.env.OD_VELA_WEB_URL;
process.env.OD_VELA_WEB_URL = 'http://localhost:5173';
const upstream = await startWalletApi((req, res) => {
expect(req.url).toBe('/api/v1/auth/intents');
expect(req.headers.authorization).toBe('Bearer ck-seeded-key');
if (changed) seedLogin('local', { apiUrl: upstream.url, controlKey: 'ck-replaced-key' });
res.setHeader('content-type', 'application/json');
res.end(JSON.stringify({ intentId: 'intent-local' }));
});
seedLogin('local', { apiUrl: upstream.url });
try {
const result = await postJson(`${baseUrl}/api/amr/web-intent`, { target: '/dashboard' });
expect(result.status).toBe(changed ? 409 : 200);
expect(result.body).toEqual(changed
? { error: 'account_changed' }
: { url: 'http://localhost:5173/login?intentId=intent-local' });
} finally {
if (previousOrigin === undefined) delete process.env.OD_VELA_WEB_URL;
else process.env.OD_VELA_WEB_URL = previousOrigin;
await upstream.close();
}
});
});
describe('GET /api/integrations/vela/wallet', () => {
it('returns signed_out without reading an upstream wallet API', async () => {
const walletApi = await startWalletApi((_req, res) => {