64 lines
2.9 KiB
JavaScript
64 lines
2.9 KiB
JavaScript
/**
|
|||
|
|
* Live end-to-end check of the D20 master OTP against a running API.
|
||
|
|
* All Persian text is a literal in this file, never a shell argument (D15).
|
||
|
|
*/
|
||
|
|
const { PrismaClient } = require('@prisma/client');
|
||
|
|
const prisma = new PrismaClient();
|
||
|
|
const API = 'http://localhost:3000/api';
|
||
|
|
let pass = 0, fail = 0;
|
||
|
|
const chk = (c, m) => { c ? pass++ : fail++; console.log((c ? ' PASS ' : ' FAIL ') + m); };
|
||
|
|
|
||
|
|
const MASTER = '778899';
|
||
|
|
|
||
|
|
(async () => {
|
||
|
|
const c = await prisma.customer.findFirst({
|
||
|
|
where: { isActive: true, isArchived: false }, select: { id: true, mobile: true, fullName: true },
|
||
|
|
});
|
||
|
|
if (!c) { console.log('no active customer to test with'); process.exit(1); }
|
||
|
|
console.log(`Testing against customer ${c.fullName} (${c.mobile})\n`);
|
||
|
|
|
||
|
|
const verify = async (mobile, code) => {
|
||
|
|
const r = await fetch(API + '/customer/auth/verify-otp', {
|
||
|
|
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||
|
|
body: JSON.stringify({ username: mobile, password: code }),
|
||
|
|
});
|
||
|
|
return { status: r.status, body: await r.json().catch(() => ({})) };
|
||
|
|
};
|
||
|
|
|
||
|
|
console.log('CASE 1 — the master code signs an active customer in');
|
||
|
|
const a = await verify(c.mobile, MASTER);
|
||
|
|
chk(a.status === 200 || a.status === 201, `HTTP ${a.status}`);
|
||
|
|
chk(typeof a.body.token === 'string' && a.body.token.length > 20, 'a JWT came back');
|
||
|
|
chk(a.body.customer?.mobile === c.mobile, 'it is THIS customer, not another');
|
||
|
|
|
||
|
|
console.log('\n the token actually works on a protected customer route');
|
||
|
|
const me = await fetch(API + '/customer/me', { headers: { Authorization: 'Bearer ' + a.body.token } });
|
||
|
|
chk(me.status === 200, `GET customer/me -> ${me.status}`);
|
||
|
|
|
||
|
|
console.log('\nCASE 1b — Persian digits for the same master code');
|
||
|
|
const p = await verify(c.mobile, '۷۷۸۸۹۹');
|
||
|
|
chk(p.status === 200 || p.status === 201, `HTTP ${p.status} — faToEn applied to the code`);
|
||
|
|
|
||
|
|
console.log('\nCASE 2 — NEGATIVE: a near-miss code is still rejected');
|
||
|
|
const bad = await verify(c.mobile, '778898');
|
||
|
|
chk(bad.status === 401, `HTTP ${bad.status} (expected 401)`);
|
||
|
|
chk(!bad.body.token, 'no token issued');
|
||
|
|
|
||
|
|
console.log('\nCASE 2b — NEGATIVE: an unknown mobile is rejected even with the master code');
|
||
|
|
const unknown = await verify('09999999999', MASTER);
|
||
|
|
chk(unknown.status === 401, `HTTP ${unknown.status} (expected 401)`);
|
||
|
|
|
||
|
|
console.log('\nCASE 2c — NEGATIVE: an INACTIVE customer is rejected even with the master code');
|
||
|
|
const inactive = await prisma.customer.findFirst({ where: { isActive: false }, select: { mobile: true } });
|
||
|
|
if (inactive) {
|
||
|
|
const r = await verify(inactive.mobile, MASTER);
|
||
|
|
chk(r.status === 401, `HTTP ${r.status} (expected 401)`);
|
||
|
|
} else {
|
||
|
|
console.log(' (skipped — no inactive customer in the DB)');
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(`\npassed: ${pass} failed: ${fail}`);
|
||
|
|
await prisma.$disconnect();
|
||
|
|
process.exit(fail ? 1 : 0);
|
||
|
|
})().catch(async (e) => { console.error(e); await prisma.$disconnect(); process.exit(1); });
|