2024-10-01 13:49:18 +02:00
|
|
|
import * as plugins from './plugins.js';
|
|
|
|
|
import * as paths from './paths.js';
|
|
|
|
|
import { Reception } from './reception/classes.reception.js';
|
2024-09-29 13:56:38 +02:00
|
|
|
|
2026-05-07 15:35:37 +00:00
|
|
|
const manifestIconPng = Uint8Array.from(Buffer.from(
|
|
|
|
|
'iVBORw0KGgoAAAANSUhEUgAAAJAAAACQCAYAAADnRuK4AAABzklEQVR4nO3OMQ0AMAzAsEIc3aHrOOyJIuXw75lzN/mGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB+KGB6L2AK5GkZ1Ln/HeAAAAAElFTkSuQmCC',
|
|
|
|
|
'base64'
|
|
|
|
|
));
|
|
|
|
|
const createManifestResponse = () => new Response(JSON.stringify({
|
|
|
|
|
name: 'idp.global',
|
|
|
|
|
short_name: 'idp.global',
|
|
|
|
|
start_url: '/',
|
|
|
|
|
display: 'standalone',
|
|
|
|
|
orientation: 'any',
|
|
|
|
|
background_color: '#000000',
|
|
|
|
|
theme_color: '#000000',
|
|
|
|
|
icons: [],
|
|
|
|
|
related_applications: [],
|
|
|
|
|
scope: '/',
|
|
|
|
|
lang: 'en',
|
|
|
|
|
display_override: ['window-controls-overlay'],
|
|
|
|
|
}), {
|
|
|
|
|
headers: {
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
'Cache-Control': 'no-store',
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const createManifestIconResponse = () => new Response(manifestIconPng.slice(), {
|
|
|
|
|
headers: {
|
|
|
|
|
'Content-Type': 'image/png',
|
|
|
|
|
'Content-Length': String(manifestIconPng.byteLength),
|
|
|
|
|
'Cache-Control': 'public, max-age=86400',
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
2024-09-29 13:56:38 +02:00
|
|
|
export const runCli = async () => {
|
|
|
|
|
const serviceQenv = new plugins.qenv.Qenv('./', './.nogit', false);
|
2025-12-15 19:45:57 +00:00
|
|
|
|
|
|
|
|
// Create reception first so we can reference it in routes
|
|
|
|
|
let reception: Reception;
|
|
|
|
|
|
2024-09-29 13:56:38 +02:00
|
|
|
const websiteServer = new plugins.typedserver.utilityservers.UtilityWebsiteServer({
|
|
|
|
|
feedMetadata: null,
|
|
|
|
|
domain: 'idp.global',
|
|
|
|
|
serveDir: paths.distWebDir,
|
2025-12-07 20:45:30 +00:00
|
|
|
securityHeaders: {
|
|
|
|
|
csp: {
|
|
|
|
|
defaultSrc: "'self'",
|
|
|
|
|
scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'", "https://cdn.paddle.com", "https://public.profitwell.com"],
|
|
|
|
|
styleSrc: ["'self'", "'unsafe-inline'", "https://cdn.paddle.com", "https://assetbroker.lossless.one"],
|
|
|
|
|
imgSrc: ["'self'", "data:", "https:"],
|
2026-05-07 15:35:37 +00:00
|
|
|
fontSrc: ["'self'", "data:", "https://assetbroker.lossless.one"],
|
2025-12-07 20:45:30 +00:00
|
|
|
connectSrc: ["'self'", "https://*.paddle.com", "https://buy.paddle.com", "https://checkout.paddle.com", "https://checkout-service.paddle.com", "https://cdn.paddle.com", "https://*.sentry.io", "https://public.profitwell.com", "wss:"],
|
|
|
|
|
frameSrc: ["https://buy.paddle.com", "https://checkout.paddle.com", "https://*.paddle.com"],
|
|
|
|
|
},
|
|
|
|
|
},
|
2025-12-04 18:06:49 +00:00
|
|
|
addCustomRoutes: async (typedserver) => {
|
|
|
|
|
// Enable SPA fallback - serves index.html for non-file routes (e.g., /login, /dashboard)
|
|
|
|
|
typedserver.options.spaFallback = true;
|
2025-12-15 19:45:57 +00:00
|
|
|
|
|
|
|
|
// OIDC Discovery endpoint
|
2025-12-22 15:56:20 +00:00
|
|
|
typedserver.addRoute('/.well-known/openid-configuration', 'GET', async (ctx) => {
|
2025-12-15 19:45:57 +00:00
|
|
|
return new Response(JSON.stringify(reception.oidcManager.getDiscoveryDocument()), {
|
|
|
|
|
headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// JWKS endpoint
|
2025-12-22 15:56:20 +00:00
|
|
|
typedserver.addRoute('/.well-known/jwks.json', 'GET', async (ctx) => {
|
2025-12-15 19:45:57 +00:00
|
|
|
return new Response(JSON.stringify(reception.oidcManager.getJwks()), {
|
|
|
|
|
headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2026-05-07 15:35:37 +00:00
|
|
|
typedserver.addRoute('/manifest.json', 'GET', async () => createManifestResponse());
|
|
|
|
|
typedserver.addRoute('/manifest.json', 'HEAD', async () => createManifestResponse());
|
|
|
|
|
typedserver.addRoute('/idp-manifest.json', 'GET', async () => createManifestResponse());
|
|
|
|
|
typedserver.addRoute('/idp-manifest.json', 'HEAD', async () => createManifestResponse());
|
|
|
|
|
typedserver.addRoute('/assetbroker/manifest/favicon.png', 'GET', async () => createManifestIconResponse());
|
|
|
|
|
typedserver.addRoute('/assetbroker/manifest/icon-144x144.png', 'GET', async () => createManifestIconResponse());
|
|
|
|
|
typedserver.addRoute('/assetbroker/manifest/icon-512x512.png', 'GET', async () => createManifestIconResponse());
|
|
|
|
|
typedserver.addRoute('/assetbroker/manifest/icon-large.png', 'GET', async () => createManifestIconResponse());
|
|
|
|
|
typedserver.addRoute('/assetbroker/manifest/favicon.png', 'HEAD', async () => createManifestIconResponse());
|
|
|
|
|
typedserver.addRoute('/assetbroker/manifest/icon-144x144.png', 'HEAD', async () => createManifestIconResponse());
|
|
|
|
|
typedserver.addRoute('/assetbroker/manifest/icon-512x512.png', 'HEAD', async () => createManifestIconResponse());
|
|
|
|
|
typedserver.addRoute('/assetbroker/manifest/icon-large.png', 'HEAD', async () => createManifestIconResponse());
|
|
|
|
|
|
2025-12-15 19:45:57 +00:00
|
|
|
// OAuth Authorization endpoint
|
2025-12-22 15:56:20 +00:00
|
|
|
typedserver.addRoute('/oauth/authorize', 'GET', async (ctx) => {
|
|
|
|
|
return reception.oidcManager.handleAuthorize(ctx);
|
2025-12-15 19:45:57 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// OAuth Token endpoint
|
2025-12-22 15:56:20 +00:00
|
|
|
typedserver.addRoute('/oauth/token', 'POST', async (ctx) => {
|
|
|
|
|
return reception.oidcManager.handleToken(ctx);
|
2025-12-15 19:45:57 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// OAuth UserInfo endpoint (GET and POST)
|
2025-12-22 15:56:20 +00:00
|
|
|
typedserver.addRoute('/oauth/userinfo', 'GET', async (ctx) => {
|
|
|
|
|
return reception.oidcManager.handleUserInfo(ctx);
|
2025-12-15 19:45:57 +00:00
|
|
|
});
|
2025-12-22 15:56:20 +00:00
|
|
|
typedserver.addRoute('/oauth/userinfo', 'POST', async (ctx) => {
|
|
|
|
|
return reception.oidcManager.handleUserInfo(ctx);
|
2025-12-15 19:45:57 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// OAuth Revocation endpoint
|
2025-12-22 15:56:20 +00:00
|
|
|
typedserver.addRoute('/oauth/revoke', 'POST', async (ctx) => {
|
|
|
|
|
return reception.oidcManager.handleRevoke(ctx);
|
2025-12-15 19:45:57 +00:00
|
|
|
});
|
2025-12-04 18:06:49 +00:00
|
|
|
},
|
2024-09-29 13:56:38 +02:00
|
|
|
});
|
2024-10-01 13:49:18 +02:00
|
|
|
|
|
|
|
|
// lets add the reception routes
|
2025-12-15 19:45:57 +00:00
|
|
|
reception = new Reception({
|
2024-10-01 13:49:18 +02:00
|
|
|
name: (await serviceQenv.getEnvVarOnDemand('INSTANCE_NAME')) || 'idp.global',
|
|
|
|
|
mongoDescriptor: {
|
2025-11-30 23:09:40 +00:00
|
|
|
mongoDbUrl: await serviceQenv.getEnvVarOnDemand('MONGODB_URL'),
|
2024-10-01 13:49:18 +02:00
|
|
|
},
|
|
|
|
|
websiteServer: websiteServer,
|
2024-10-04 15:43:36 +02:00
|
|
|
baseUrl: await serviceQenv.getEnvVarOnDemand('IDP_BASEURL'),
|
2024-10-01 13:49:18 +02:00
|
|
|
});
|
|
|
|
|
await reception.start();
|
|
|
|
|
|
2025-12-14 10:58:46 +00:00
|
|
|
await websiteServer.start(2999);
|
2024-09-29 13:56:38 +02:00
|
|
|
};
|