Extract the operational Model Delivery PWA

This commit is contained in:
tomchukk committed 2026-09-07 19:34:48 +03:00
commit 958f8d5ff1
46 files changed
+6446

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
// Only used against model_delivery_test. This is not a default application account.
export const testAccount = { username: 'test.admin', password: 'Test-only-password-932!', displayName: 'משתמש בדיקה' };
+55
View File
@@ -0,0 +1,55 @@
// Test-only identity provider. Never imported or started by application code.
import { createServer } from 'node:http';
import { createHash, randomBytes } from 'node:crypto';
import { pathToFileURL } from 'node:url';
import { generateKeyPair, exportJWK, SignJWT } from 'jose';
export async function startMockOidc(port = 0) {
const { privateKey, publicKey } = await generateKeyPair('RS256');
const jwk = { ...await exportJWK(publicKey), kid: 'test-key', use: 'sig', alg: 'RS256' };
const codes = new Map(), refreshTokens = new Set(), accessTokens = new Set();
const controls = { badNonce: false, denyRefresh: false, refreshCount: 0, omitName: false, omitRefreshToken: false, subject: 'synology-test-user', groups: ['model-delivery-users'] };
let issuer = '';
const server = createServer(async (req, res) => {
const profile = { sub: controls.subject, username: 'test.sso', ...(controls.omitName ? {} : { name: 'טום בדיקה' }), email: 'test@example.invalid', groups: controls.groups };
const json = (data, status = 200) => { res.writeHead(status, { 'content-type': 'application/json', 'cache-control': 'no-store' }); res.end(JSON.stringify(data)); };
const url = new URL(req.url, issuer);
try {
if (url.pathname === '/.well-known/openid-configuration') return json({ issuer, authorization_endpoint: `${issuer}/authorize`, token_endpoint: `${issuer}/token`, userinfo_endpoint: `${issuer}/userinfo`, jwks_uri: `${issuer}/jwks`, response_types_supported: ['code'], grant_types_supported: ['authorization_code', 'refresh_token'], subject_types_supported: ['public'], id_token_signing_alg_values_supported: ['RS256'], token_endpoint_auth_methods_supported: ['client_secret_post'], scopes_supported: ['openid', 'profile', 'email', 'groups', 'offline_access'], claims_supported: ['sub', 'username', 'name', 'email', 'groups'], code_challenge_methods_supported: ['S256'] });
if (url.pathname === '/jwks') return json({ keys: [jwk] });
if (url.pathname === '/authorize') {
const values = Object.fromEntries(url.searchParams);
if (values.client_id !== 'model-test' || values.redirect_uri !== 'http://localhost:4174/api/auth/callback' || values.code_challenge_method !== 'S256' || !values.code_challenge || !values.state || !values.nonce) return json({ error: 'invalid_request' }, 400);
const code = randomBytes(24).toString('hex'); codes.set(code, values);
const redirect = new URL(values.redirect_uri); redirect.searchParams.set('code', code); redirect.searchParams.set('state', values.state);
res.writeHead(302, { location: redirect.href }); return res.end();
}
if (url.pathname === '/token' && req.method === 'POST') {
let raw = ''; for await (const chunk of req) raw += chunk;
const fields = new URLSearchParams(raw);
if (fields.get('client_id') !== 'model-test' || fields.get('client_secret') !== 'mock-test-secret') return json({ error: 'invalid_client' }, 401);
let values;
if (fields.get('grant_type') === 'authorization_code') {
values = codes.get(fields.get('code')); codes.delete(fields.get('code'));
if (!values || values.redirect_uri !== fields.get('redirect_uri') || createHash('sha256').update(fields.get('code_verifier') ?? '').digest('base64url') !== values.code_challenge) return json({ error: 'invalid_grant' }, 400);
} else if (fields.get('grant_type') === 'refresh_token') {
if (controls.denyRefresh || !refreshTokens.delete(fields.get('refresh_token'))) return json({ error: 'invalid_grant' }, 400);
controls.refreshCount++;
} else return json({ error: 'unsupported_grant_type' }, 400);
const access_token = randomBytes(32).toString('hex'), refresh_token = randomBytes(32).toString('hex');
accessTokens.add(access_token); refreshTokens.add(refresh_token);
const id_token = values ? await new SignJWT({ ...profile, nonce: controls.badNonce ? 'wrong-nonce' : values.nonce }).setProtectedHeader({ alg: 'RS256', kid: jwk.kid }).setIssuer(issuer).setAudience('model-test').setIssuedAt().setExpirationTime('1h').sign(privateKey) : undefined;
return json({ access_token, ...(!controls.omitRefreshToken ? { refresh_token } : {}), id_token, token_type: 'Bearer', expires_in: 3600, scope: 'openid profile email groups offline_access' });
}
if (url.pathname === '/userinfo' && accessTokens.has(req.headers.authorization?.replace(/^Bearer /, ''))) return json(profile);
return json({ error: 'not_found' }, 404);
} catch { return json({ error: 'server_error' }, 500); }
});
await new Promise(resolve => server.listen(port, '127.0.0.1', resolve));
issuer = `http://localhost:${server.address().port}`;
return { issuer, controls, close: () => new Promise((resolve, reject) => server.close(error => error ? reject(error) : resolve())) };
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
const provider = await startMockOidc(4005);
console.log(`Test OIDC provider ready at ${provider.issuer}`);
}