@futdevpro/nts-dynamo 1.15.33 → 1.15.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dynamo/logs/cicd-pipeline/output.log +2593 -0
- package/.dynamo/logs/cicd-pipeline/status.json +321 -0
- package/build/_models/interfaces/cors-settings.interface.d.ts +52 -0
- package/build/_models/interfaces/cors-settings.interface.d.ts.map +1 -0
- package/build/_models/interfaces/cors-settings.interface.js +3 -0
- package/build/_models/interfaces/cors-settings.interface.js.map +1 -0
- package/build/_services/server/app.server.d.ts +25 -0
- package/build/_services/server/app.server.d.ts.map +1 -1
- package/build/_services/server/app.server.js +64 -0
- package/build/_services/server/app.server.js.map +1 -1
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/package.json +11 -2
- package/src/_models/interfaces/cors-settings.interface.spec.ts +52 -0
- package/src/_models/interfaces/cors-settings.interface.ts +56 -0
- package/src/_services/server/app.server.ts +82 -3
- package/src/index.ts +1 -0
- /package/{pipeline.cicd.config.json → .dynamo/pipeline.cicd.config.json} +0 -0
|
@@ -47,6 +47,9 @@ import {
|
|
|
47
47
|
import {
|
|
48
48
|
DyNTS_StaticClient_Settings
|
|
49
49
|
} from '../../_models/interfaces/static-client-settings.interface';
|
|
50
|
+
import {
|
|
51
|
+
DyNTS_Cors_Settings
|
|
52
|
+
} from '../../_models/interfaces/cors-settings.interface';
|
|
50
53
|
import { DyNTS_SingletonService } from '../base/singleton.service';
|
|
51
54
|
import { DyNTS_GlobalService } from '../core/global.service';
|
|
52
55
|
import { DyNTS_RoutingModule } from '../route/routing-module.service';
|
|
@@ -1074,20 +1077,24 @@ export abstract class DyNTS_App extends DyNTS_SingletonService {
|
|
|
1074
1077
|
*/
|
|
1075
1078
|
protected async initOpenExpress(): Promise<void> {
|
|
1076
1079
|
if (this.fnLogs) DyFM_Log.log('\nfn:. initOpenExpress');
|
|
1077
|
-
this.openExpress = Express();
|
|
1080
|
+
this.openExpress = Express();
|
|
1078
1081
|
this.openExpress.set('maxHeaderSize', 10 * megabyte); // 1024 * 1024 * 10, // 10MB
|
|
1079
1082
|
this.openExpress.use(BodyParser.urlencoded(this._portSettings.httpUrlencoded));
|
|
1080
1083
|
this.openExpress.use(BodyParser.json(this._portSettings.httpJson));
|
|
1084
|
+
// FR-041 — CORS allowlist enforcement. No-op if getCorsSettings() is not overridden.
|
|
1085
|
+
this.mountCors(this.openExpress);
|
|
1081
1086
|
}
|
|
1082
1087
|
|
|
1083
1088
|
/**
|
|
1084
|
-
*
|
|
1089
|
+
*
|
|
1085
1090
|
*/
|
|
1086
1091
|
protected async initSecureExpress(): Promise<void> {
|
|
1087
1092
|
if (this.fnLogs) DyFM_Log.log('\nfn:. initSecureExpress');
|
|
1088
|
-
this.secureExpress = Express();
|
|
1093
|
+
this.secureExpress = Express();
|
|
1089
1094
|
this.secureExpress.use(BodyParser.urlencoded(this._portSettings.httpsUrlencoded));
|
|
1090
1095
|
this.secureExpress.use(BodyParser.json(this._portSettings.httpsJson));
|
|
1096
|
+
// FR-041 — CORS allowlist enforcement (same as open express).
|
|
1097
|
+
this.mountCors(this.secureExpress);
|
|
1091
1098
|
|
|
1092
1099
|
const options = {
|
|
1093
1100
|
key: FileSystem.readFileSync(this._cert.keyPath),
|
|
@@ -1412,6 +1419,69 @@ export abstract class DyNTS_App extends DyNTS_SingletonService {
|
|
|
1412
1419
|
}
|
|
1413
1420
|
}
|
|
1414
1421
|
|
|
1422
|
+
/**
|
|
1423
|
+
* FR-041 — CORS middleware. Echoes a matching `Access-Control-Allow-Origin`
|
|
1424
|
+
* for any request whose Origin header is in `getCorsSettings().allowedOrigins`,
|
|
1425
|
+
* adds the canonical `Access-Control-*` companion headers, and short-circuits
|
|
1426
|
+
* the OPTIONS preflight with a 204.
|
|
1427
|
+
*
|
|
1428
|
+
* No-op when the subclass does NOT override `getCorsSettings()` — preserves
|
|
1429
|
+
* back-compat for apps that have always been same-origin and never needed
|
|
1430
|
+
* CORS (the typical pre-FR-041 case).
|
|
1431
|
+
*
|
|
1432
|
+
* Why hand-rolled instead of the `cors` npm package:
|
|
1433
|
+
* - ~30 lines, zero new dependency.
|
|
1434
|
+
* - Full control over Vary/credentials/preflight semantics.
|
|
1435
|
+
* - Aligns with FDP "no unnecessary deps" philosophy.
|
|
1436
|
+
*/
|
|
1437
|
+
protected mountCors(express: Express.Application): void {
|
|
1438
|
+
const settings: DyNTS_Cors_Settings | undefined = this.getCorsSettings?.();
|
|
1439
|
+
if (!settings) {
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
const allowCreds: boolean = settings.allowCredentials !== false;
|
|
1444
|
+
const methods: string[] = settings.allowedMethods ?? [
|
|
1445
|
+
'GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS',
|
|
1446
|
+
];
|
|
1447
|
+
const headers: string[] = settings.allowedHeaders ?? [
|
|
1448
|
+
'Authorization', 'Content-Type', 'X-Admin-Key', 'X-Requested-With',
|
|
1449
|
+
];
|
|
1450
|
+
const exposed: string[] = settings.exposedHeaders ?? [
|
|
1451
|
+
'Content-Length', 'Content-Type',
|
|
1452
|
+
];
|
|
1453
|
+
const maxAge: number = settings.maxAgeSeconds ?? 86400;
|
|
1454
|
+
|
|
1455
|
+
const isAllowed: (origin: string) => boolean = (origin: string): boolean => {
|
|
1456
|
+
if (settings.allowedOrigins === '*') return true;
|
|
1457
|
+
if (typeof settings.allowedOrigins === 'function') {
|
|
1458
|
+
return settings.allowedOrigins(origin);
|
|
1459
|
+
}
|
|
1460
|
+
return settings.allowedOrigins.includes(origin);
|
|
1461
|
+
};
|
|
1462
|
+
|
|
1463
|
+
express.use((req: Express.Request, res: Express.Response, next: Express.NextFunction): void => {
|
|
1464
|
+
const origin: string | undefined = req.headers.origin;
|
|
1465
|
+
if (origin && isAllowed(origin)) {
|
|
1466
|
+
// Echo the matching origin (NOT wildcard) because credentials require it.
|
|
1467
|
+
res.setHeader('Access-Control-Allow-Origin', origin);
|
|
1468
|
+
if (allowCreds) {
|
|
1469
|
+
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
1470
|
+
}
|
|
1471
|
+
res.setHeader('Access-Control-Allow-Methods', methods.join(', '));
|
|
1472
|
+
res.setHeader('Access-Control-Allow-Headers', headers.join(', '));
|
|
1473
|
+
res.setHeader('Access-Control-Expose-Headers', exposed.join(', '));
|
|
1474
|
+
res.setHeader('Access-Control-Max-Age', String(maxAge));
|
|
1475
|
+
res.setHeader('Vary', 'Origin');
|
|
1476
|
+
}
|
|
1477
|
+
if (req.method === 'OPTIONS') {
|
|
1478
|
+
res.status(204).end();
|
|
1479
|
+
return;
|
|
1480
|
+
}
|
|
1481
|
+
next();
|
|
1482
|
+
});
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1415
1485
|
/**
|
|
1416
1486
|
* Ha getStaticClientSettings() visszaad beállításokat, a client static fájlok a '/' alatt
|
|
1417
1487
|
* lesznek kiszolgálva (API route-ok után). SPA fallback opcionális (fallbackPath).
|
|
@@ -1580,6 +1650,15 @@ export abstract class DyNTS_App extends DyNTS_SingletonService {
|
|
|
1580
1650
|
*/
|
|
1581
1651
|
getStaticClientSettings?(): DyNTS_StaticClient_Settings | undefined;
|
|
1582
1652
|
|
|
1653
|
+
/**
|
|
1654
|
+
* FR-041 — Ha megadva, CORS middleware mount-olódik mindkét Express instance-ra
|
|
1655
|
+
* (open + secure). Az `allowedOrigins` listán szereplő Origin-eket echo-zza vissza,
|
|
1656
|
+
* `Access-Control-Allow-Credentials: true`-val (default) együtt a Bearer JWT
|
|
1657
|
+
* cross-domain auth flow miatt. OPTIONS preflight 204-gyel rövidre záródik.
|
|
1658
|
+
* Ha undefined → no CORS headers, no preflight handling — back-compat.
|
|
1659
|
+
*/
|
|
1660
|
+
getCorsSettings?(): DyNTS_Cors_Settings | undefined;
|
|
1661
|
+
|
|
1583
1662
|
/**
|
|
1584
1663
|
* MISSING Description (TODO)
|
|
1585
1664
|
*/
|
package/src/index.ts
CHANGED
|
@@ -50,6 +50,7 @@ export * from './_models/interfaces/global-service-settings.interface';
|
|
|
50
50
|
export * from './_models/interfaces/global-settings.interface';
|
|
51
51
|
export * from './_models/interfaces/routing-module-settings.interface';
|
|
52
52
|
export * from './_models/interfaces/static-client-settings.interface';
|
|
53
|
+
export * from './_models/interfaces/cors-settings.interface';
|
|
53
54
|
|
|
54
55
|
// models/CONTROL MODELS
|
|
55
56
|
export * from './_models/control-models/api-call-params.control-model';
|
|
File without changes
|