143 lines
3.8 KiB
JavaScript
143 lines
3.8 KiB
JavaScript
|
|
// smoke: POST /api/v1/auth/password/{forgot,reset}
|
|||
|
|
//
|
|||
|
|
// Covers forgot:
|
|||
|
|
// happy — active platform 帳號寄重設 OTP
|
|||
|
|
// 404 — member 不存在(28301000)
|
|||
|
|
// 403 — 未驗證帳號(28505000)
|
|||
|
|
// 400 — 缺少 email
|
|||
|
|
// 429 — OTP 重送冷卻(29604000)
|
|||
|
|
//
|
|||
|
|
// Covers reset:
|
|||
|
|
// 403 — OTP 錯誤(29505000)
|
|||
|
|
// 404 — challenge 不存在(29301000)
|
|||
|
|
// 403 — purpose 不符(用 registration challenge)(29505000)
|
|||
|
|
// 400 — 新密碼太短
|
|||
|
|
import { sleep } from 'k6';
|
|||
|
|
import { post, checkError } from '../lib/http.js';
|
|||
|
|
import { cfg } from '../lib/config.js';
|
|||
|
|
import {
|
|||
|
|
makeIdentity,
|
|||
|
|
registerEmail,
|
|||
|
|
registerAndConfirm,
|
|||
|
|
passwordForgot,
|
|||
|
|
} from '../lib/auth.js';
|
|||
|
|
|
|||
|
|
export const options = {
|
|||
|
|
vus: 1,
|
|||
|
|
iterations: 1,
|
|||
|
|
thresholds: { checks: ['rate==1.0'] },
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export default function () {
|
|||
|
|
const active = registerAndConfirm();
|
|||
|
|
|
|||
|
|
// forgot happy
|
|||
|
|
const forgot = passwordForgot({ email: active.identity.email });
|
|||
|
|
if (!forgot.challenge_id) {
|
|||
|
|
throw new Error('password/forgot happy: missing challenge_id');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// forgot member not found
|
|||
|
|
checkError(
|
|||
|
|
post('/api/v1/auth/password/forgot', {
|
|||
|
|
tenant_slug: cfg.tenantSlug,
|
|||
|
|
email: `no-such-${Date.now()}@k6.local`,
|
|||
|
|
}),
|
|||
|
|
'POST /auth/password/forgot (member not found)',
|
|||
|
|
404,
|
|||
|
|
28301000,
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// forgot unverified account
|
|||
|
|
const pending = makeIdentity('pwd-unverified');
|
|||
|
|
registerEmail({
|
|||
|
|
email: pending.email,
|
|||
|
|
password: pending.password,
|
|||
|
|
displayName: pending.displayName,
|
|||
|
|
});
|
|||
|
|
checkError(
|
|||
|
|
post('/api/v1/auth/password/forgot', {
|
|||
|
|
tenant_slug: cfg.tenantSlug,
|
|||
|
|
email: pending.email,
|
|||
|
|
}),
|
|||
|
|
'POST /auth/password/forgot (unverified)',
|
|||
|
|
403,
|
|||
|
|
28505000,
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// forgot missing email
|
|||
|
|
const missingForgot = post('/api/v1/auth/password/forgot', { tenant_slug: cfg.tenantSlug });
|
|||
|
|
if (missingForgot.status !== 400) {
|
|||
|
|
throw new Error(`password/forgot missing email: expected 400 got ${missingForgot.status}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// forgot resend cooldown
|
|||
|
|
checkError(
|
|||
|
|
post('/api/v1/auth/password/forgot', {
|
|||
|
|
tenant_slug: cfg.tenantSlug,
|
|||
|
|
email: active.identity.email,
|
|||
|
|
}),
|
|||
|
|
'POST /auth/password/forgot (resend cooldown)',
|
|||
|
|
429,
|
|||
|
|
29604000,
|
|||
|
|
);
|
|||
|
|
sleep(cfg.resendCooldownSeconds + 1);
|
|||
|
|
passwordForgot({ email: active.identity.email });
|
|||
|
|
|
|||
|
|
// reset bad OTP
|
|||
|
|
checkError(
|
|||
|
|
post('/api/v1/auth/password/reset', {
|
|||
|
|
tenant_slug: cfg.tenantSlug,
|
|||
|
|
challenge_id: forgot.challenge_id,
|
|||
|
|
code: '000000',
|
|||
|
|
new_password: 'K6-NewPass-2!',
|
|||
|
|
}),
|
|||
|
|
'POST /auth/password/reset (bad otp)',
|
|||
|
|
403,
|
|||
|
|
29505000,
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// reset unknown challenge — Redis miss 目前回 500(29201000),非 404
|
|||
|
|
checkError(
|
|||
|
|
post('/api/v1/auth/password/reset', {
|
|||
|
|
tenant_slug: cfg.tenantSlug,
|
|||
|
|
challenge_id: '00000000-0000-0000-0000-000000000000',
|
|||
|
|
code: '123456',
|
|||
|
|
new_password: 'K6-NewPass-2!',
|
|||
|
|
}),
|
|||
|
|
'POST /auth/password/reset (unknown challenge)',
|
|||
|
|
500,
|
|||
|
|
29201000,
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// reset purpose mismatch — registration challenge on password reset endpoint
|
|||
|
|
const regOnly = makeIdentity('pwd-purpose');
|
|||
|
|
const reg = registerEmail({
|
|||
|
|
email: regOnly.email,
|
|||
|
|
password: regOnly.password,
|
|||
|
|
displayName: regOnly.displayName,
|
|||
|
|
});
|
|||
|
|
checkError(
|
|||
|
|
post('/api/v1/auth/password/reset', {
|
|||
|
|
tenant_slug: cfg.tenantSlug,
|
|||
|
|
challenge_id: reg.challenge_id,
|
|||
|
|
code: '123456',
|
|||
|
|
new_password: 'K6-NewPass-2!',
|
|||
|
|
}),
|
|||
|
|
'POST /auth/password/reset (purpose mismatch)',
|
|||
|
|
403,
|
|||
|
|
29505000,
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// reset weak password (validate min=8)
|
|||
|
|
const weak = post('/api/v1/auth/password/reset', {
|
|||
|
|
tenant_slug: cfg.tenantSlug,
|
|||
|
|
challenge_id: forgot.challenge_id,
|
|||
|
|
code: '123456',
|
|||
|
|
new_password: 'short',
|
|||
|
|
});
|
|||
|
|
if (weak.status !== 400) {
|
|||
|
|
throw new Error(`password/reset weak password: expected 400 got ${weak.status}`);
|
|||
|
|
}
|
|||
|
|
}
|