feat: enforce per-user module access in Makelore

This commit is contained in:
brother7 committed 2026-08-17 08:51:15 +08:00
1 parent f7171a471a
commit d16922f18c
12 files changed
+457 -35

No files matched your search

+82
View File
@@ -63,6 +63,88 @@ describe('auth host api routes', () => {
providerServiceMock.deleteAccountApiKey.mockResolvedValue(true);
});
it('projects the current user module access without exposing the upstream profile', async () => {
storeWorksSquareSession({
accessToken: 'main-access-token',
refreshToken: 'main-refresh-token',
expiresAt: Date.now() + 60_000,
lastActiveAt: Date.now(),
});
const fetchMock = vi.fn().mockResolvedValueOnce(
new Response(JSON.stringify({
id: 42,
username: 'student',
one_api_token_key: 'must-not-reach-renderer',
module_access: {
programming: false,
design: true,
learning: false,
robot: true,
},
}), { status: 200 }),
);
vi.stubGlobal('fetch', fetchMock);
const response = createResponse();
const handled = await handleAuthRoutes(
createRequest('GET'),
response.res,
new URL('http://127.0.0.1:13210/api/auth/me'),
{} as never,
);
expect(handled).toBe(true);
expect(response.statusCode).toBe(200);
expect(response.json()).toEqual({
success: true,
moduleAccess: {
programming: false,
design: true,
learning: false,
robot: true,
},
});
expect(JSON.stringify(response.json())).not.toContain('must-not-reach-renderer');
expect(fetchMock).toHaveBeenCalledWith(
'https://square.nianxx.cn/api/auth/me',
{
method: 'GET',
headers: { Authorization: 'Bearer main-access-token' },
},
);
});
it('keeps module access enabled when an older profile omits the policy', async () => {
storeWorksSquareSession({
accessToken: 'main-access-token',
refreshToken: 'main-refresh-token',
expiresAt: Date.now() + 60_000,
lastActiveAt: Date.now(),
});
vi.stubGlobal('fetch', vi.fn().mockResolvedValueOnce(
new Response(JSON.stringify({ username: 'student' }), { status: 200 }),
));
const response = createResponse();
await handleAuthRoutes(
createRequest('GET'),
response.res,
new URL('http://127.0.0.1:13210/api/auth/me'),
{} as never,
);
expect(response.statusCode).toBe(200);
expect(response.json()).toEqual({
success: true,
moduleAccess: {
programming: true,
design: true,
learning: true,
robot: true,
},
});
});
it('exchanges username and AES-encrypted password through the app SSO token endpoint', async () => {
const fetchMock = vi.fn().mockResolvedValueOnce(
new Response(JSON.stringify({