Preserve H5 flows while adding Taobao identity, native capture, reports and isolated local development. Fix canceled province selection and expired-session logout. Record passing local regressions, two pre-existing H5 assertion failures and pending platform validation.
42 lines
3.1 KiB
JavaScript
42 lines
3.1 KiB
JavaScript
'use strict';
|
|
const { test } = require('node:test'), assert = require('node:assert/strict'), crypto = require('node:crypto');
|
|
const auth = require('../../h5/lib/taobao-auth');
|
|
test('gateway signature covers raw JSON, identity, extra query fields and algorithm; duplicates fail closed', () => {
|
|
const env = { TAOBAO_APP_KEY: 'app', TAOBAO_APP_SECRET: 'secret' }, body = '{"consent":true,"challenge":"nonce"}';
|
|
const params = { app_key: 'app', open_id: 'open-account', sign_method: 'md5', env: 'online' };
|
|
const expected = crypto.createHash('md5').update('secretapp_keyappenvonlineopen_idopen-accountsign_methodmd5' + body + 'secret').digest('hex').toUpperCase();
|
|
assert.equal(auth.signature(params, body, env.TAOBAO_APP_SECRET), expected);
|
|
const url = '/api/taobao/session?' + new URLSearchParams({ ...params, sign: expected });
|
|
assert(auth.verify(url, body, env));
|
|
assert.equal(auth.verify(url, body + ' ', env), null);
|
|
assert.equal(auth.verify(url.replace('open-account', 'forged-account'), body, env), null);
|
|
assert.equal(auth.verify(url + '&open_id=open-account', body, env), null);
|
|
assert.equal(auth.verify(url, body, {}), null);
|
|
});
|
|
test('photo chunks are ordered, bounded, deduplicated, owner-bound, expiring and consumed once', async () => {
|
|
let now = 0;
|
|
const req = { headers: {}, owner: 'alice' }, other = { headers: {}, owner: 'bob' };
|
|
const runtime = require('../../h5/lib/taobao-session')({ now: () => now, session: request => ({ id: request.owner, kind: 'taobao' }) });
|
|
const piece = { view: 'front', upload_id: 'test-upload-id', index: 0, total: 2, data: 'AAAA' };
|
|
assert.equal(runtime.upload(req, { ...piece, index: 1 }).status, 409);
|
|
assert.equal(runtime.upload(req, piece).complete, false);
|
|
assert.equal(runtime.upload(req, piece).complete, false, 'repeated identical chunk is idempotent');
|
|
assert.equal(runtime.upload(req, { ...piece, data: 'BBBB' }).status, 409);
|
|
assert.equal(runtime.upload(req, { ...piece, data: 'A'.repeat(65537) }).status, 400);
|
|
assert.equal(runtime.upload(req, { ...piece, index: 1 }).complete, true);
|
|
assert.equal(runtime.takePhotos(other, { front: piece.upload_id }), null);
|
|
for (const view of ['left', 'right']) assert.equal(runtime.upload(req, { ...piece, view, total: 1 }).status, 200);
|
|
const refs = { front: piece.upload_id, left: piece.upload_id, right: piece.upload_id };
|
|
assert(runtime.takePhotos(req, refs)); assert.equal(runtime.takePhotos(req, refs), null);
|
|
assert.equal(runtime.upload(req, piece).status, 409);
|
|
let complete;
|
|
const job = runtime.start(req, () => new Promise(resolve => { complete = resolve; }), true);
|
|
await new Promise(resolve => setImmediate(resolve));
|
|
assert.equal(runtime.result(other, job), null); assert.equal(runtime.result(req, job).status, 'running');
|
|
complete({ ok: true }); await new Promise(resolve => setImmediate(resolve));
|
|
assert.equal(runtime.result(req, job).status, 'complete');
|
|
assert.equal(runtime.upload(req, piece).status, 200);
|
|
now = 5 * 60000 + 1; assert.equal(runtime.takePhotos(req, refs), null);
|
|
const challenge = runtime.challenge('local'); assert(runtime.consume(challenge)); assert(!runtime.consume(challenge));
|
|
});
|