100 lines
2.9 KiB
JavaScript
100 lines
2.9 KiB
JavaScript
/**
|
||
* MPM Modul-SDK – Authentifizierungs-Helper (Phase 6).
|
||
* CommonJS-Variante (Module laufen als Node-CommonJS-Prozesse).
|
||
*
|
||
* Jedes Modul läuft hinter dem Modul-Gateway der Management-Plattform.
|
||
* Der Gateway authentifiziert den Benutzer zentral und übergibt die
|
||
* Identität über interne Header. Module dürfen diese Header NIE
|
||
* direkt von außen akzeptieren – deshalb stellt dieses SDK sicher,
|
||
* dass die Identität nur aus dem Gateway-Flow stammt.
|
||
*
|
||
* Sicherheitsregeln:
|
||
* - Module lauschen nur auf 127.0.0.1 (nie öffentlich erreichbar)
|
||
* - Der Gateway entfernt das Session-Cookie vor dem Proxy
|
||
* - Identitäts-Header werden vom Gateway gesetzt, nicht vom Client
|
||
*/
|
||
|
||
/** Identitäts-Header, die der Modul-Gateway setzt. */
|
||
const GATEWAY_HEADERS = {
|
||
userId: 'x-user-id',
|
||
username: 'x-user-username',
|
||
displayName: 'x-user-display-name',
|
||
role: 'x-user-role',
|
||
};
|
||
|
||
/** Vom Gateway übergebene Benutzer-Identität. */
|
||
// interface GatewayIdentity {
|
||
// userId: string;
|
||
// username: string;
|
||
// displayName: string;
|
||
// role: 'ADMIN' | 'USER';
|
||
// }
|
||
|
||
/**
|
||
* Extrahiert die Benutzer-Identität aus den Gateway-Headern.
|
||
* @returns Identität oder null, wenn der Request nicht über den
|
||
* Gateway kam (z. B. direkter Aufruf ohne Plattform).
|
||
*/
|
||
function extractIdentity(headers) {
|
||
const userId = readHeader(headers, GATEWAY_HEADERS.userId);
|
||
const username = readHeader(headers, GATEWAY_HEADERS.username);
|
||
const displayName = readHeader(headers, GATEWAY_HEADERS.displayName);
|
||
const role = readHeader(headers, GATEWAY_HEADERS.role);
|
||
|
||
if (!userId || !username || !role) {
|
||
return null;
|
||
}
|
||
if (role !== 'ADMIN' && role !== 'USER') {
|
||
return null;
|
||
}
|
||
|
||
return { userId, username, displayName: displayName ?? username, role };
|
||
}
|
||
|
||
/** Liest einen Header (case-insensitive, erster Wert). */
|
||
function readHeader(headers, name) {
|
||
const lowerName = name.toLowerCase();
|
||
for (const [key, value] of Object.entries(headers)) {
|
||
if (key.toLowerCase() === lowerName) {
|
||
if (Array.isArray(value)) {
|
||
return value[0] ?? null;
|
||
}
|
||
return value ?? null;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Standard-Antworten des Modul-API-Vertrags (Phase 6):
|
||
* Jedes Modul muss diese drei Endpunkte bereitstellen:
|
||
* GET /health → Liveness/Readiness
|
||
* GET /api/manifest → Manifest zur Laufzeit
|
||
* GET /api/me → Aktueller Benutzer (vom Gateway übergeben)
|
||
*/
|
||
|
||
/** Erstellt die /health-Antwort nach Vertrag. */
|
||
function healthResponse(moduleId, version) {
|
||
return { moduleId, version, status: 'healthy' };
|
||
}
|
||
|
||
/** Erstellt die /api/me-Antwort nach Vertrag. */
|
||
function meResponse(identity, moduleId, permissions = []) {
|
||
return {
|
||
user: {
|
||
id: identity.userId,
|
||
username: identity.username,
|
||
displayName: identity.displayName,
|
||
platformRole: identity.role,
|
||
},
|
||
module: { id: moduleId },
|
||
permissions,
|
||
};
|
||
}
|
||
|
||
module.exports = {
|
||
GATEWAY_HEADERS,
|
||
extractIdentity,
|
||
healthResponse,
|
||
meResponse,
|
||
}; |