Secure actor-owned game API routes

This commit is contained in:
2026-07-25 08:50:41 +00:00
parent 6889c463fd
commit a9d6541c18
13 changed files with 301 additions and 118 deletions
+36 -1
View File
@@ -8,6 +8,7 @@ import { createGatewayApiContext } from '../src/context.js';
import { InMemoryProfileStatusService } from '../src/lobby/profileStatusService.js';
import { appRouter } from '../src/router.js';
import type { GatewayPrismaClient } from '@sammo-ts/infra';
import { decryptGameSessionToken } from '@sammo-ts/common/auth/gameToken';
const buildCaller = () => {
const users = createInMemoryUserRepository();
@@ -87,13 +88,47 @@ const buildCaller = () => {
orchestrator,
profileStatus,
requestHeaders: {},
prisma: {} as unknown as GatewayPrismaClient,
prisma: {
appUser: {
findFirst: async () => null,
},
} as unknown as GatewayPrismaClient,
})
);
return { caller, oauthSessions };
};
describe('gateway auth flow', () => {
it('carries the bootstrap superuser role into game sessions', async () => {
const previousToken = process.env.GATEWAY_BOOTSTRAP_TOKEN;
process.env.GATEWAY_BOOTSTRAP_TOKEN = 'bootstrap-test-token';
try {
const { caller } = buildCaller();
const bootstrap = await caller.auth.bootstrapLocal({
token: 'bootstrap-test-token',
username: 'admin',
password: 'secretpass',
displayName: 'Admin',
});
expect(bootstrap.user.roles).toEqual(['superuser']);
const issued = await caller.auth.issueGameSession({
sessionToken: bootstrap.sessionToken,
profile: 'che:default',
});
const payload = decryptGameSessionToken(issued.gameToken, 'test-secret');
expect(payload?.user.roles).toEqual(['superuser']);
} finally {
if (previousToken === undefined) {
delete process.env.GATEWAY_BOOTSTRAP_TOKEN;
} else {
process.env.GATEWAY_BOOTSTRAP_TOKEN = previousToken;
}
}
});
it('registers and issues a game session', async () => {
const { caller, oauthSessions } = buildCaller();
const oauthSession = await oauthSessions.createSession({