46 lines
1.4 KiB
JavaScript
46 lines
1.4 KiB
JavaScript
|
|
// Journey: login with TOTP MFA — enroll → login (mfa_required) → login/mfa → /me
|
||
|
|
//
|
||
|
|
// Endpoints:
|
||
|
|
// POST /api/v1/auth/register/confirm path (via registerAndConfirm)
|
||
|
|
// POST /api/v1/members/me/totp/enroll-start + enroll-confirm
|
||
|
|
// POST /api/v1/auth/login
|
||
|
|
// POST /api/v1/auth/login/mfa
|
||
|
|
// GET /api/v1/members/me
|
||
|
|
import { get, checkEnvelope } from '../lib/http.js';
|
||
|
|
import { registerAndConfirm, loginExpectMFA, loginMfaConfirm } from '../lib/auth.js';
|
||
|
|
import { enrollTOTP } from '../lib/member.js';
|
||
|
|
import { generateTOTP } from '../lib/totp.js';
|
||
|
|
|
||
|
|
export const options = {
|
||
|
|
vus: 1,
|
||
|
|
iterations: 1,
|
||
|
|
thresholds: { checks: ['rate==1.0'] },
|
||
|
|
};
|
||
|
|
|
||
|
|
export default function () {
|
||
|
|
const { identity, tokens } = registerAndConfirm();
|
||
|
|
const bearer = { Authorization: `Bearer ${tokens.access_token}` };
|
||
|
|
const { otpauthUrl } = enrollTOTP(bearer);
|
||
|
|
|
||
|
|
const mfa = loginExpectMFA({
|
||
|
|
email: identity.email,
|
||
|
|
password: identity.password,
|
||
|
|
});
|
||
|
|
const totpCode = generateTOTP(otpauthUrl);
|
||
|
|
const session = loginMfaConfirm({
|
||
|
|
challengeId: mfa.mfa_challenge_id,
|
||
|
|
code: totpCode,
|
||
|
|
});
|
||
|
|
if (!session.access_token) {
|
||
|
|
throw new Error('login/mfa journey: missing access_token');
|
||
|
|
}
|
||
|
|
|
||
|
|
const me = checkEnvelope(
|
||
|
|
get('/api/v1/members/me', { Authorization: `Bearer ${session.access_token}` }),
|
||
|
|
'GET /members/me (after login/mfa)',
|
||
|
|
).data;
|
||
|
|
if (me.uid !== session.uid) {
|
||
|
|
throw new Error('login/mfa journey: uid mismatch');
|
||
|
|
}
|
||
|
|
}
|