146 lines
5.1 KiB
JavaScript
146 lines
5.1 KiB
JavaScript
'use strict';
|
|
|
|
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const jwt = require('jsonwebtoken');
|
|
const presaleRouter = require('../src/api/presaleExternal');
|
|
const autoListingRouter = require('../src/api/planningSelectionFissionExternal');
|
|
const alibaba1688Router = require('../src/api/alibaba1688ProductExternal');
|
|
const {
|
|
requireDesktopPageAccess,
|
|
requireExternalAutomationApiKey,
|
|
} = require('../src/services/externalAutomationAuth');
|
|
|
|
function getRouteMiddleware(router, path) {
|
|
const layer = router.stack.find((item) => item.route?.path === path);
|
|
return layer?.route?.stack?.[0]?.handle;
|
|
}
|
|
|
|
function createResponseRecorder() {
|
|
return {
|
|
statusCode: 200,
|
|
payload: null,
|
|
status(code) {
|
|
this.statusCode = code;
|
|
return this;
|
|
},
|
|
json(payload) {
|
|
this.payload = payload;
|
|
return this;
|
|
},
|
|
};
|
|
}
|
|
|
|
test('presale and auto-listing external APIs use the same request key middleware', () => {
|
|
assert.equal(getRouteMiddleware(presaleRouter, '/tasks'), requireExternalAutomationApiKey);
|
|
assert.equal(getRouteMiddleware(autoListingRouter, '/tasks/claim'), requireExternalAutomationApiKey);
|
|
assert.equal(getRouteMiddleware(alibaba1688Router, '/:productId'), requireExternalAutomationApiKey);
|
|
});
|
|
|
|
test('shared external auth accepts a valid desktop JWT without an API key', async () => {
|
|
const previousSecret = process.env.CUBEJS_SECRET;
|
|
process.env.CUBEJS_SECRET = 'desktop-session-test-secret';
|
|
try {
|
|
const accessToken = jwt.sign({ sub: '42', name: '陆南亭', authSource: 'dingtalk' }, process.env.CUBEJS_SECRET);
|
|
const req = {
|
|
ip: '127.0.0.1',
|
|
query: {},
|
|
get(name) {
|
|
return name.toLowerCase() === 'authorization' ? `Bearer ${accessToken}` : '';
|
|
},
|
|
};
|
|
const res = createResponseRecorder();
|
|
let nextCalled = false;
|
|
|
|
await requireExternalAutomationApiKey(req, res, () => { nextCalled = true; });
|
|
|
|
assert.equal(nextCalled, true);
|
|
assert.equal(req.user.name, '陆南亭');
|
|
assert.equal(req.externalApiKey.authType, 'jwt');
|
|
assert.equal(req.externalApiKey.name, '桌面端登录会话');
|
|
} finally {
|
|
if (previousSecret === undefined) delete process.env.CUBEJS_SECRET;
|
|
else process.env.CUBEJS_SECRET = previousSecret;
|
|
}
|
|
});
|
|
|
|
test('shared external auth rejects an invalid desktop JWT', async () => {
|
|
const previousSecret = process.env.CUBEJS_SECRET;
|
|
process.env.CUBEJS_SECRET = 'desktop-session-test-secret';
|
|
try {
|
|
const accessToken = jwt.sign({ sub: '42', name: '陆南亭' }, 'wrong-secret');
|
|
const req = {
|
|
ip: '127.0.0.1',
|
|
query: {},
|
|
get(name) {
|
|
return name.toLowerCase() === 'authorization' ? `Bearer ${accessToken}` : '';
|
|
},
|
|
};
|
|
const res = createResponseRecorder();
|
|
let nextCalled = false;
|
|
|
|
await requireExternalAutomationApiKey(req, res, () => { nextCalled = true; });
|
|
|
|
assert.equal(nextCalled, false);
|
|
assert.equal(res.statusCode, 401);
|
|
assert.equal(res.payload.code, 'AUTH_TOKEN_INVALID');
|
|
} finally {
|
|
if (previousSecret === undefined) delete process.env.CUBEJS_SECRET;
|
|
else process.env.CUBEJS_SECRET = previousSecret;
|
|
}
|
|
});
|
|
|
|
test('shared external auth rejects a desktop SSO session token on business APIs', async () => {
|
|
const previousSecret = process.env.CUBEJS_SECRET;
|
|
process.env.CUBEJS_SECRET = 'desktop-session-test-secret';
|
|
try {
|
|
const accessToken = jwt.sign(
|
|
{ sub: '42', name: '陆南亭', tokenType: 'desktop-session' },
|
|
process.env.CUBEJS_SECRET
|
|
);
|
|
const req = {
|
|
ip: '127.0.0.1',
|
|
query: {},
|
|
get(name) {
|
|
return name.toLowerCase() === 'authorization' ? `Bearer ${accessToken}` : '';
|
|
},
|
|
};
|
|
const res = createResponseRecorder();
|
|
let nextCalled = false;
|
|
|
|
await requireExternalAutomationApiKey(req, res, () => { nextCalled = true; });
|
|
|
|
assert.equal(nextCalled, false);
|
|
assert.equal(res.statusCode, 401);
|
|
assert.equal(res.payload.code, 'AUTH_TOKEN_SCOPE_INVALID');
|
|
} finally {
|
|
if (previousSecret === undefined) delete process.env.CUBEJS_SECRET;
|
|
else process.env.CUBEJS_SECRET = previousSecret;
|
|
}
|
|
});
|
|
|
|
test('desktop page access enforces JWT permissions and preserves API key compatibility', () => {
|
|
const middleware = requireDesktopPageAccess('planning_upload', 'market_insight');
|
|
const deniedResponse = createResponseRecorder();
|
|
let deniedNextCalled = false;
|
|
|
|
middleware({
|
|
externalApiKey: { authType: 'jwt' },
|
|
user: { role: 'user', allowedPageKeys: ['dashboard'] },
|
|
}, deniedResponse, () => { deniedNextCalled = true; });
|
|
|
|
assert.equal(deniedNextCalled, false);
|
|
assert.equal(deniedResponse.statusCode, 403);
|
|
assert.equal(deniedResponse.payload.code, 'DESKTOP_PAGE_ACCESS_DENIED');
|
|
|
|
for (const req of [
|
|
{ externalApiKey: { authType: 'jwt' }, user: { role: 'user', allowedPageKeys: ['market_insight'] } },
|
|
{ externalApiKey: { authType: 'jwt' }, user: { role: 'admin', allowedPageKeys: [] } },
|
|
{ externalApiKey: { authType: 'api-key' }, user: null },
|
|
]) {
|
|
let nextCalled = false;
|
|
middleware(req, createResponseRecorder(), () => { nextCalled = true; });
|
|
assert.equal(nextCalled, true);
|
|
}
|
|
});
|