@authup/server-core 1.0.0-beta.57 → 1.0.0-beta.58
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/dist/adapters/database/logger/module.mjs +2 -4
- package/dist/adapters/database/logger/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/entities/identity-provider/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/entities/identity-provider/module.mjs +1 -1
- package/dist/adapters/http/controllers/entities/identity-provider/module.mjs.map +1 -1
- package/dist/adapters/http/middleware/built-in/authorization/module.mjs +2 -1
- package/dist/adapters/http/middleware/built-in/authorization/module.mjs.map +1 -1
- package/dist/adapters/http/middleware/built-in/rate-limit.mjs +2 -2
- package/dist/adapters/http/middleware/built-in/rate-limit.mjs.map +1 -1
- package/dist/adapters/http/request/client-certificate.mjs +1 -1
- package/dist/adapters/http/request/client-certificate.mjs.map +1 -1
- package/dist/adapters/http/request/helpers/locations.mjs +1 -3
- package/dist/adapters/http/request/helpers/locations.mjs.map +1 -1
- package/dist/app/modules/authentication/module.mjs +6 -3
- package/dist/app/modules/authentication/module.mjs.map +1 -1
- package/dist/app/modules/config/helpers.mjs +3 -2
- package/dist/app/modules/config/helpers.mjs.map +1 -1
- package/dist/app/modules/config/read/module.mjs +8 -3
- package/dist/app/modules/config/read/module.mjs.map +1 -1
- package/dist/app/modules/database/module.mjs +2 -1
- package/dist/app/modules/database/module.mjs.map +1 -1
- package/dist/app/modules/http/modules/controller.mjs +197 -126
- package/dist/app/modules/http/modules/controller.mjs.map +1 -1
- package/dist/app/modules/http/modules/middleware.mjs +10 -5
- package/dist/app/modules/http/modules/middleware.mjs.map +1 -1
- package/dist/app/modules/identity/module.mjs +6 -3
- package/dist/app/modules/identity/module.mjs.map +1 -1
- package/dist/app/modules/oauth2/module.mjs +37 -17
- package/dist/app/modules/oauth2/module.mjs.map +1 -1
- package/dist/app/modules/oauth2/repositories/authorize/state/repository.mjs +1 -1
- package/dist/app/modules/oauth2/repositories/authorize/state/repository.mjs.map +1 -1
- package/dist/app/modules/oauth2/repositories/token/repository.mjs +1 -1
- package/dist/app/modules/oauth2/repositories/token/repository.mjs.map +1 -1
- package/dist/app/modules/provisioning/module.mjs +9 -8
- package/dist/app/modules/provisioning/module.mjs.map +1 -1
- package/dist/app/modules/provisioning/sources/file/module.d.ts.map +1 -1
- package/dist/app/modules/provisioning/sources/file/module.mjs +11 -2
- package/dist/app/modules/provisioning/sources/file/module.mjs.map +1 -1
- package/dist/core/authentication/session/module.mjs +2 -4
- package/dist/core/authentication/session/module.mjs.map +1 -1
- package/dist/core/entities/client/service.d.ts.map +1 -1
- package/dist/core/entities/client/service.mjs +1 -1
- package/dist/core/entities/client/service.mjs.map +1 -1
- package/dist/core/entities/client-permission/service.mjs +12 -9
- package/dist/core/entities/client-permission/service.mjs.map +1 -1
- package/dist/core/entities/key/service.mjs +4 -2
- package/dist/core/entities/key/service.mjs.map +1 -1
- package/dist/core/entities/permission/service.d.ts.map +1 -1
- package/dist/core/entities/permission/service.mjs +1 -1
- package/dist/core/entities/permission/service.mjs.map +1 -1
- package/dist/core/entities/policy/service.d.ts.map +1 -1
- package/dist/core/entities/policy/service.mjs +3 -2
- package/dist/core/entities/policy/service.mjs.map +1 -1
- package/dist/core/entities/realm/service.d.ts.map +1 -1
- package/dist/core/entities/realm/service.mjs +1 -1
- package/dist/core/entities/realm/service.mjs.map +1 -1
- package/dist/core/entities/role/service.d.ts.map +1 -1
- package/dist/core/entities/role/service.mjs +1 -1
- package/dist/core/entities/role/service.mjs.map +1 -1
- package/dist/core/entities/role-permission/service.mjs +12 -9
- package/dist/core/entities/role-permission/service.mjs.map +1 -1
- package/dist/core/entities/scope/service.d.ts.map +1 -1
- package/dist/core/entities/scope/service.mjs +1 -1
- package/dist/core/entities/scope/service.mjs.map +1 -1
- package/dist/core/entities/user/service.d.ts.map +1 -1
- package/dist/core/entities/user/service.mjs +1 -1
- package/dist/core/entities/user/service.mjs.map +1 -1
- package/dist/core/entities/user-authenticator/helpers.mjs +1 -1
- package/dist/core/entities/user-authenticator/helpers.mjs.map +1 -1
- package/dist/core/entities/user-authenticator/service.mjs +7 -7
- package/dist/core/entities/user-authenticator/service.mjs.map +1 -1
- package/dist/core/entities/user-permission/service.mjs +12 -9
- package/dist/core/entities/user-permission/service.mjs.map +1 -1
- package/dist/core/identity/password-recovery/service.mjs +1 -1
- package/dist/core/identity/password-recovery/service.mjs.map +1 -1
- package/dist/core/provisioning/synchronizer/client/module.mjs +0 -1
- package/dist/core/provisioning/synchronizer/client/module.mjs.map +1 -1
- package/dist/core/provisioning/synchronizer/permission/module.mjs +0 -1
- package/dist/core/provisioning/synchronizer/permission/module.mjs.map +1 -1
- package/dist/core/provisioning/synchronizer/realm/module.mjs +0 -1
- package/dist/core/provisioning/synchronizer/realm/module.mjs.map +1 -1
- package/dist/core/provisioning/synchronizer/role/module.mjs +0 -1
- package/dist/core/provisioning/synchronizer/role/module.mjs.map +1 -1
- package/dist/core/provisioning/synchronizer/scope/module.mjs +0 -1
- package/dist/core/provisioning/synchronizer/scope/module.mjs.map +1 -1
- package/dist/core/provisioning/synchronizer/user/module.mjs +0 -1
- package/dist/core/provisioning/synchronizer/user/module.mjs.map +1 -1
- package/dist/path.mjs.map +1 -1
- package/dist/swagger.json +435 -11
- package/dist/ui/client/.vite/ssr-manifest.json +172 -10
- package/dist/ui/client/assets/index-BTK3GPZZ.js +106 -0
- package/dist/ui/client/assets/{index-Bk6-OZy9.css → index-Cx_pI7BS.css} +1 -1
- package/dist/ui/client/index.html +2 -2
- package/dist/ui/server/server.js +1894 -5045
- package/package.json +25 -24
- package/dist/ui/client/assets/index-DO6_7NTJ.js +0 -106
|
@@ -29,10 +29,8 @@ import { AdvancedConsoleLogger } from "typeorm";
|
|
|
29
29
|
else this.logger.warn(`[DB]: ${message.message}`);
|
|
30
30
|
break;
|
|
31
31
|
case "error":
|
|
32
|
-
case "query-error":
|
|
33
|
-
|
|
34
|
-
else this.logger.error(`[DB]: ${message.message}`);
|
|
35
|
-
break;
|
|
32
|
+
case "query-error": if (message.prefix) this.logger.error(`[DB]: ${message.prefix} ${message.message}`);
|
|
33
|
+
else this.logger.error(`[DB]: ${message.message}`);
|
|
36
34
|
}
|
|
37
35
|
}
|
|
38
36
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.mjs","names":["AdvancedConsoleLogger","DatabaseLogger","logger","writeLog","level","logMessage","messages","prepareLogMessages","message","type","debug","info","prefix","warn","error"],"sources":["../../../../src/adapters/database/logger/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { Logger } from '@authup/server-kit';\nimport type { LogLevel, LogMessage } from 'typeorm';\nimport { AdvancedConsoleLogger } from 'typeorm';\n\n/**\n * @see https://github.com/typeorm/typeorm/blob/master/src/logger/AdvancedConsoleLogger.ts\n */\n\nexport class DatabaseLogger extends AdvancedConsoleLogger {\n protected logger : Logger;\n\n constructor(logger : Logger) {\n super();\n\n this.logger = logger;\n }\n\n protected writeLog(\n level: LogLevel,\n logMessage: LogMessage | LogMessage[],\n ) {\n const messages = this.prepareLogMessages(logMessage);\n\n for (const message of messages) {\n switch (message.type ?? level) {\n case 'log':\n case 'schema-build':\n case 'migration':\n this.logger.debug(`[DB]: ${message.message}`);\n break;\n\n case 'info':\n case 'query':\n this.logger.info(`[DB]: ${message.message}`);\n break;\n\n case 'warn':\n case 'query-slow':\n if (message.prefix) {\n this.logger.warn(`[DB]: ${message.prefix} ${message.message}`);\n } else {\n this.logger.warn(`[DB]: ${message.message}`);\n }\n break;\n\n case 'error':\n case 'query-error':\n if (message.prefix) {\n this.logger.error(`[DB]: ${message.prefix} ${message.message}`);\n } else {\n this.logger.error(`[DB]: ${message.message}`);\n }\n break;\n }\n }\n }\n}\n"],"mappings":";;;;;;;GAeA,IAAaC,iBAAb,cAAoCD,sBAAAA;CACtBE;CAEV,YAAYA,QAAiB;EACzB,MAAK;EAEL,KAAKA,SAASA;CAClB;CAEUC,SACNC,OACAC,YACF;EACE,MAAMC,WAAW,KAAKC,mBAAmBF,UAAAA;EAEzC,KAAK,MAAMG,WAAWF,UAClB,QAAQE,QAAQC,QAAQL,OAAxB;GACI,KAAK;GACL,KAAK;GACL,KAAK;IACD,KAAKF,OAAOQ,MAAM,SAASF,QAAQA,SAAS;IAC5C;GAEJ,KAAK;GACL,KAAK;IACD,KAAKN,OAAOS,KAAK,SAASH,QAAQA,SAAS;IAC3C;GAEJ,KAAK;GACL,KAAK;IACD,IAAIA,QAAQI,QACR,KAAKV,OAAOW,KAAK,SAASL,QAAQI,OAAO,GAAGJ,QAAQA,SAAS;SAE7D,KAAKN,OAAOW,KAAK,SAASL,QAAQA,SAAS;IAE/C;GAEJ,KAAK;GACL,KAAK
|
|
1
|
+
{"version":3,"file":"module.mjs","names":["AdvancedConsoleLogger","DatabaseLogger","logger","writeLog","level","logMessage","messages","prepareLogMessages","message","type","debug","info","prefix","warn","error"],"sources":["../../../../src/adapters/database/logger/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { Logger } from '@authup/server-kit';\nimport type { LogLevel, LogMessage } from 'typeorm';\nimport { AdvancedConsoleLogger } from 'typeorm';\n\n/**\n * @see https://github.com/typeorm/typeorm/blob/master/src/logger/AdvancedConsoleLogger.ts\n */\n\nexport class DatabaseLogger extends AdvancedConsoleLogger {\n protected logger : Logger;\n\n constructor(logger : Logger) {\n super();\n\n this.logger = logger;\n }\n\n protected writeLog(\n level: LogLevel,\n logMessage: LogMessage | LogMessage[],\n ) {\n const messages = this.prepareLogMessages(logMessage);\n\n for (const message of messages) {\n switch (message.type ?? level) {\n case 'log':\n case 'schema-build':\n case 'migration':\n this.logger.debug(`[DB]: ${message.message}`);\n break;\n\n case 'info':\n case 'query':\n this.logger.info(`[DB]: ${message.message}`);\n break;\n\n case 'warn':\n case 'query-slow':\n if (message.prefix) {\n this.logger.warn(`[DB]: ${message.prefix} ${message.message}`);\n } else {\n this.logger.warn(`[DB]: ${message.message}`);\n }\n break;\n\n case 'error':\n case 'query-error':\n if (message.prefix) {\n this.logger.error(`[DB]: ${message.prefix} ${message.message}`);\n } else {\n this.logger.error(`[DB]: ${message.message}`);\n }\n break;\n }\n }\n }\n}\n"],"mappings":";;;;;;;GAeA,IAAaC,iBAAb,cAAoCD,sBAAAA;CACtBE;CAEV,YAAYA,QAAiB;EACzB,MAAK;EAEL,KAAKA,SAASA;CAClB;CAEUC,SACNC,OACAC,YACF;EACE,MAAMC,WAAW,KAAKC,mBAAmBF,UAAAA;EAEzC,KAAK,MAAMG,WAAWF,UAClB,QAAQE,QAAQC,QAAQL,OAAxB;GACI,KAAK;GACL,KAAK;GACL,KAAK;IACD,KAAKF,OAAOQ,MAAM,SAASF,QAAQA,SAAS;IAC5C;GAEJ,KAAK;GACL,KAAK;IACD,KAAKN,OAAOS,KAAK,SAASH,QAAQA,SAAS;IAC3C;GAEJ,KAAK;GACL,KAAK;IACD,IAAIA,QAAQI,QACR,KAAKV,OAAOW,KAAK,SAASL,QAAQI,OAAO,GAAGJ,QAAQA,SAAS;SAE7D,KAAKN,OAAOW,KAAK,SAASL,QAAQA,SAAS;IAE/C;GAEJ,KAAK;GACL,KAAK,eACD,IAAIA,QAAQI,QACR,KAAKV,OAAOY,MAAM,SAASN,QAAQI,OAAO,GAAGJ,QAAQA,SAAS;QAE9D,KAAKN,OAAOY,MAAM,SAASN,QAAQA,SAAS;EAGxD;CAER;AACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../../src/adapters/http/controllers/entities/identity-provider/module.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAMxC,OAAO,KAAK,EAAE,gBAAgB,EAAkC,MAAM,kBAAkB,CAAC;AAiBzF,OAAO,KAAK,EACR,wBAAwB,EACxB,oBAAoB,EACpB,6BAA6B,EAC7B,2BAA2B,EAC3B,6BAA6B,EAChC,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EACR,+BAA+B,EAC/B,2BAA2B,EAC3B,4BAA4B,EAC5B,8BAA8B,EAC9B,uCAAuC,EACvC,gCAAgC,EAChC,uBAAuB,EACvB,gBAAgB,EAEnB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACH,uCAAuC,EAO1C,MAAM,8BAA8B,CAAC;AAYtC,OAAO,KAAK,EAAE,iCAAiC,EAAE,iCAAiC,EAAE,MAAM,YAAY,CAAC;AAEvG,qBAEa,0BAA0B;IACnC,SAAS,CAAC,OAAO,EAAE,iCAAiC,CAAC;IAErD,SAAS,CAAC,UAAU,EAAE,2BAA2B,CAAC;IAElD,SAAS,CAAC,eAAe,EAAE,gBAAgB,CAAC;IAE5C,SAAS,CAAC,gBAAgB,EAAE,uBAAuB,CAAC;IAEpD,SAAS,CAAC,cAAc,EAAE,+BAA+B,CAAC;IAE1D,SAAS,CAAC,mBAAmB,EAAG,uCAAuC,CAAC;IAExE,SAAS,CAAC,oBAAoB,EAAG,uCAAuC,CAAC;IAEzE,SAAS,CAAC,YAAY,EAAG,gCAAgC,CAAC;IAE1D,SAAS,CAAC,UAAU,EAAG,8BAA8B,CAAC;IAEtD,SAAS,CAAC,qBAAqB,CAAC,EAAG,4BAA4B,CAAC;gBAIpD,GAAG,EAAE,iCAAiC;IAgB5C,YAAY,CACF,KAAK,EAAE,SAAS,GAC7B,OAAO,CAAC,wBAAwB,CAAC,gBAAgB,CAAC,CAAC;IAuChD,WAAW,CACA,EAAE,EAAE,MAAM,EACX,KAAK,EAAE,SAAS,GAC7B,OAAO,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;IA0B5C,YAAY,CACD,EAAE,EAAE,MAAM,EACd,IAAI,EAAE,6BAA6B,EAChC,KAAK,EAAE,SAAS,GAC5B,OAAO,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;IAK7C,GAAG,CACQ,EAAE,EAAE,MAAM,EACd,IAAI,EAAE,2BAA2B,EAC9B,KAAK,EAAE,SAAS,GAC5B,OAAO,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;IAK7C,YAAY,CACD,EAAE,EAAE,MAAM,EACX,KAAK,EAAE,SAAS,GAC5B,OAAO,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;IA6B7C,WAAW,CACJ,IAAI,EAAE,6BAA6B,EAChC,KAAK,EAAE,SAAS,GAC5B,OAAO,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;IAO7C,YAAY,CACD,GAAG,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS;IAgD1B,WAAW,CACA,GAAG,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS;YAyGlB,KAAK;
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../../src/adapters/http/controllers/entities/identity-provider/module.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAMxC,OAAO,KAAK,EAAE,gBAAgB,EAAkC,MAAM,kBAAkB,CAAC;AAiBzF,OAAO,KAAK,EACR,wBAAwB,EACxB,oBAAoB,EACpB,6BAA6B,EAC7B,2BAA2B,EAC3B,6BAA6B,EAChC,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EACR,+BAA+B,EAC/B,2BAA2B,EAC3B,4BAA4B,EAC5B,8BAA8B,EAC9B,uCAAuC,EACvC,gCAAgC,EAChC,uBAAuB,EACvB,gBAAgB,EAEnB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACH,uCAAuC,EAO1C,MAAM,8BAA8B,CAAC;AAYtC,OAAO,KAAK,EAAE,iCAAiC,EAAE,iCAAiC,EAAE,MAAM,YAAY,CAAC;AAEvG,qBAEa,0BAA0B;IACnC,SAAS,CAAC,OAAO,EAAE,iCAAiC,CAAC;IAErD,SAAS,CAAC,UAAU,EAAE,2BAA2B,CAAC;IAElD,SAAS,CAAC,eAAe,EAAE,gBAAgB,CAAC;IAE5C,SAAS,CAAC,gBAAgB,EAAE,uBAAuB,CAAC;IAEpD,SAAS,CAAC,cAAc,EAAE,+BAA+B,CAAC;IAE1D,SAAS,CAAC,mBAAmB,EAAG,uCAAuC,CAAC;IAExE,SAAS,CAAC,oBAAoB,EAAG,uCAAuC,CAAC;IAEzE,SAAS,CAAC,YAAY,EAAG,gCAAgC,CAAC;IAE1D,SAAS,CAAC,UAAU,EAAG,8BAA8B,CAAC;IAEtD,SAAS,CAAC,qBAAqB,CAAC,EAAG,4BAA4B,CAAC;gBAIpD,GAAG,EAAE,iCAAiC;IAgB5C,YAAY,CACF,KAAK,EAAE,SAAS,GAC7B,OAAO,CAAC,wBAAwB,CAAC,gBAAgB,CAAC,CAAC;IAuChD,WAAW,CACA,EAAE,EAAE,MAAM,EACX,KAAK,EAAE,SAAS,GAC7B,OAAO,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;IA0B5C,YAAY,CACD,EAAE,EAAE,MAAM,EACd,IAAI,EAAE,6BAA6B,EAChC,KAAK,EAAE,SAAS,GAC5B,OAAO,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;IAK7C,GAAG,CACQ,EAAE,EAAE,MAAM,EACd,IAAI,EAAE,2BAA2B,EAC9B,KAAK,EAAE,SAAS,GAC5B,OAAO,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;IAK7C,YAAY,CACD,EAAE,EAAE,MAAM,EACX,KAAK,EAAE,SAAS,GAC5B,OAAO,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;IA6B7C,WAAW,CACJ,IAAI,EAAE,6BAA6B,EAChC,KAAK,EAAE,SAAS,GAC5B,OAAO,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;IAO7C,YAAY,CACD,GAAG,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS;IAgD1B,WAAW,CACA,GAAG,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS;YAyGlB,KAAK;IA+FnB,OAAO,CAAC,uBAAuB;YAmBjB,OAAO;YAYP,sBAAsB;YAWtB,wBAAwB;CAWzC"}
|
|
@@ -238,7 +238,7 @@ var IdentityProviderController = class {
|
|
|
238
238
|
else where.name = id;
|
|
239
239
|
if (realmId) where.realmId = realmId;
|
|
240
240
|
entity = await this.repository.findOneBy(where);
|
|
241
|
-
if (!entity && options.updateOnly) throw new EntityNotFoundError();
|
|
241
|
+
if (!entity && (options.updateOnly || where.id)) throw new EntityNotFoundError();
|
|
242
242
|
} else if (options.updateOnly) throw new EntityNotFoundError();
|
|
243
243
|
const permissionEvaluator = useRequestPermissionEvaluator(event);
|
|
244
244
|
if (entity) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.mjs","names":["BuiltInPolicyType","definePolicyData","ValidatorGroup","base64URLDecode","isUUID","DBody","DContext","DController","DDelete","DGet","DPath","DPost","DPut","DTags","getRequestHeader","getRequestIP","sendRedirect","IdentityProviderAttributesValidator","IdentityProviderValidator","IdentityType","PermissionName","SessionAuthMethod","isOAuth2IdentityProvider","isOpenIDIdentityProvider","BadRequestError","EntityNotFoundError","resolveURL","useRequestQuery","readRequestBody","OAuth2ErrorCode","OAuth2RequestError","URL","OAuth2AuthorizationCodeRequestValidator","RECORD_QUERY_PARAMETERS","createIdentityProviderOAuth2Authenticator","decodeQuery","describeQuerySchema","identityProviderSchema","toIdentityPolicyData","applyRouteRealmIDToBody","buildActorContext","getBodyRealmID","getRequestParamID","getRequestRealmID","useRequestIdentityOrFail","useRequestParamID","useRequestPermissionEvaluator","ForceLoggedInMiddleware","IdentityProviderController","options","repository","realmRepository","clientRepository","accountManager","codeRequestVerifier","codeRequestValidator","stateManager","codeIssuer","accessPolicyEvaluator","ctx","getProviders","event","data","meta","findMany","schema","actor","permissionEvaluator","preEvaluate","name","IDENTITY_PROVIDER_READ","datum","evaluate","ATTRIBUTES","REALM_MATCH","realmId","getProvider","id","paramId","entity","findOneByIdOrName","editProvider","user","write","updateOnly","put","dropProvider","IDENTITY_PROVIDER_DELETE","findOneBy","entityId","remove","response","status","addProvider","authorizeOut","_id","resolve","authenticator","provider","baseURL","parameters","codeRequest","query","codeRequestDecoded","JSON","parse","malformed","codeRequestValidated","run","verify","client","state","saveAuthorizationState","buildRedirectURL","authorizeIn","Error","protocol","verifyAuthorizationState","realm_id","code","clientId","client_id","authenticate","realm","accessPolicyId","allowed","subject","type","USER","url","buildHostedAuthorizeURL","searchParams","set","ACCESS_DENIED","href","authorizationCode","issue","response_type","redirect_uri","scope","authMethod","EXTERNAL","group","body","where","IDENTITY_PROVIDER_UPDATE","UPDATE","IDENTITY_PROVIDER_CREATE","CREATE","validator","attributesValidator","attributes","validateJoinColumns","identity","checkUniqueness","undefined","merge","saveWithEA","create","codeRequestKeys","Object","keys","codeRequestKey_","codeRequestKey","codeRequestValue","String","findOneById","save","ip","userAgent","stateInvalid"],"sources":["../../../../../../src/adapters/http/controllers/entities/identity-provider/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { BuiltInPolicyType, definePolicyData } from '@authup/access';\nimport { ValidatorGroup, base64URLDecode, isUUID } from '@authup/kit';\nimport {\n DBody,\n DContext,\n DController,\n DDelete,\n DGet,\n DPath,\n DPost,\n DPut,\n DTags,\n} from '@routup/decorators';\nimport type { IAppEvent } from 'routup';\nimport {\n getRequestHeader,\n getRequestIP,\n sendRedirect,\n} from 'routup';\nimport type { IdentityProvider, OAuth2AuthorizationCodeRequest } from '@authup/core-kit';\nimport {\n\n IdentityProviderAttributesValidator,\n IdentityProviderValidator,\n IdentityType,\n PermissionName,\n SessionAuthMethod,\n isOAuth2IdentityProvider,\n isOpenIDIdentityProvider,\n} from '@authup/core-kit';\nimport { BadRequestError, EntityNotFoundError } from '@authup/errors';\nimport { resolveURL } from '../../../../../utils/index.ts';\nimport type { AuthorizeParameters } from '@hapic/oauth2';\nimport { useRequestQuery } from '@routup/basic/query';\nimport { readRequestBody } from '@routup/basic/body';\nimport { OAuth2ErrorCode, OAuth2RequestError } from '@authup/specs';\nimport type {\n EntityCollectionResponse,\n EntityRecordResponse,\n IdentityProviderCreatePayload,\n IdentityProviderSavePayload,\n IdentityProviderUpdatePayload,\n} from '@authup/core-http-kit';\nimport { URL } from 'node:url';\nimport type {\n IIdentityProviderAccountManager,\n IIdentityProviderRepository,\n IOAuth2AccessPolicyEvaluator,\n IOAuth2AuthorizationCodeIssuer,\n IOAuth2AuthorizationCodeRequestVerifier,\n IOAuth2AuthorizationStateManager,\n IOAuth2ClientRepository,\n IRealmRepository,\n OAuth2AuthorizationState,\n} from '../../../../../core/index.ts';\nimport {\n OAuth2AuthorizationCodeRequestValidator,\n RECORD_QUERY_PARAMETERS,\n createIdentityProviderOAuth2Authenticator,\n decodeQuery,\n describeQuerySchema,\n identityProviderSchema,\n toIdentityPolicyData,\n} from '../../../../../core/index.ts';\nimport {\n applyRouteRealmIDToBody,\n buildActorContext,\n getBodyRealmID,\n getRequestParamID,\n getRequestRealmID,\n useRequestIdentityOrFail,\n useRequestParamID,\n useRequestPermissionEvaluator,\n} from '../../../request/index.ts';\nimport { ForceLoggedInMiddleware } from '../../../middleware/index.ts';\nimport type { IdentityProviderControllerContext, IdentityProviderControllerOptions } from './types.ts';\n\n@DTags('identity')\n@DController(['/identity-providers', '/realms/:realmId/identity-providers'])\nexport class IdentityProviderController {\n protected options: IdentityProviderControllerOptions;\n\n protected repository: IIdentityProviderRepository;\n\n protected realmRepository: IRealmRepository;\n\n protected clientRepository: IOAuth2ClientRepository;\n\n protected accountManager: IIdentityProviderAccountManager;\n\n protected codeRequestVerifier : IOAuth2AuthorizationCodeRequestVerifier;\n\n protected codeRequestValidator : OAuth2AuthorizationCodeRequestValidator;\n\n protected stateManager : IOAuth2AuthorizationStateManager;\n\n protected codeIssuer : IOAuth2AuthorizationCodeIssuer;\n\n protected accessPolicyEvaluator? : IOAuth2AccessPolicyEvaluator;\n\n // ---------------------------------------------------------\n\n constructor(ctx: IdentityProviderControllerContext) {\n this.options = ctx.options;\n this.repository = ctx.repository;\n this.realmRepository = ctx.realmRepository;\n this.clientRepository = ctx.clientRepository;\n this.accountManager = ctx.accountManager;\n this.codeIssuer = ctx.codeIssuer;\n this.codeRequestVerifier = ctx.codeRequestVerifier;\n this.codeRequestValidator = new OAuth2AuthorizationCodeRequestValidator();\n this.stateManager = ctx.stateManager;\n this.accessPolicyEvaluator = ctx.accessPolicyEvaluator;\n }\n\n // ---------------------------------------------------------\n\n @DGet('', [])\n async getProviders(\n @DContext() event: IAppEvent,\n ): Promise<EntityCollectionResponse<IdentityProvider>> {\n const {\n data,\n meta,\n } = await this.repository.findMany(\n await decodeQuery(useRequestQuery(event), {\n schema: identityProviderSchema,\n actor: buildActorContext(event),\n }),\n );\n\n try {\n const permissionEvaluator = useRequestPermissionEvaluator(event);\n await permissionEvaluator.preEvaluate({ name: PermissionName.IDENTITY_PROVIDER_READ });\n\n for (const datum of data) {\n try {\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_READ,\n data: definePolicyData({ [BuiltInPolicyType.ATTRIBUTES]: datum, [BuiltInPolicyType.REALM_MATCH]: datum.realmId ?? null }),\n });\n } catch {\n // do nothing\n }\n }\n } catch {\n // do nothing\n }\n\n return {\n data,\n meta: {\n ...meta,\n schema: describeQuerySchema(identityProviderSchema),\n },\n };\n }\n\n @DGet('/:id', [])\n async getProvider(\n @DPath('id') id: string,\n @DContext() event: IAppEvent,\n ): Promise<EntityRecordResponse<IdentityProvider>> {\n const paramId = useRequestParamID(event, { isUUID: false });\n\n const entity = await this.repository.findOneByIdOrName(\n paramId,\n getRequestRealmID(event),\n );\n\n if (!entity) {\n throw new EntityNotFoundError();\n }\n\n try {\n const permissionEvaluator = useRequestPermissionEvaluator(event);\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_READ,\n data: definePolicyData({ [BuiltInPolicyType.ATTRIBUTES]: entity, [BuiltInPolicyType.REALM_MATCH]: entity.realmId ?? null }),\n });\n } catch {\n // do nothing\n }\n\n return { data: entity, meta: { schema: describeQuerySchema(identityProviderSchema, RECORD_QUERY_PARAMETERS) } };\n }\n\n @DPost('/:id', [ForceLoggedInMiddleware])\n async editProvider(\n @DPath('id') id: string,\n @DBody() user: IdentityProviderUpdatePayload,\n @DContext() event: IAppEvent,\n ) : Promise<EntityRecordResponse<IdentityProvider>> {\n return this.write(event, { updateOnly: true });\n }\n\n @DPut('/:id', [ForceLoggedInMiddleware])\n async put(\n @DPath('id') id: string,\n @DBody() user: IdentityProviderSavePayload,\n @DContext() event: IAppEvent,\n ) : Promise<EntityRecordResponse<IdentityProvider>> {\n return this.write(event);\n }\n\n @DDelete('/:id', [ForceLoggedInMiddleware])\n async dropProvider(\n @DPath('id') id: string,\n @DContext() event: IAppEvent,\n ) : Promise<EntityRecordResponse<IdentityProvider>> {\n const paramId = useRequestParamID(event);\n\n const permissionEvaluator = useRequestPermissionEvaluator(event);\n await permissionEvaluator.preEvaluate({ name: PermissionName.IDENTITY_PROVIDER_DELETE });\n\n const entity = await this.repository.findOneBy({ id: paramId });\n\n if (!entity) {\n throw new EntityNotFoundError();\n }\n\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_DELETE,\n data: definePolicyData({ [BuiltInPolicyType.ATTRIBUTES]: entity, [BuiltInPolicyType.REALM_MATCH]: entity.realmId ?? null }),\n });\n\n const { id: entityId } = entity;\n\n await this.repository.remove(entity);\n\n entity.id = entityId;\n\n event.response.status = 202;\n\n return { data: entity, meta: {} };\n }\n\n @DPost('', [ForceLoggedInMiddleware])\n async addProvider(\n @DBody() user: IdentityProviderCreatePayload,\n @DContext() event: IAppEvent,\n ) : Promise<EntityRecordResponse<IdentityProvider>> {\n return this.write(event);\n }\n\n // ---------------------------------------------------------\n\n @DGet('/:id/authorize-out', [])\n async authorizeOut(\n @DPath('id') _id: string,\n @DContext() event: IAppEvent,\n ) {\n const id = useRequestParamID(event);\n const entity = await this.resolve(id);\n\n if (!isOAuth2IdentityProvider(entity) && !isOpenIDIdentityProvider(entity)) {\n throw new BadRequestError('Only an identity-provider based on the oauth protocol supports authorize redirect.');\n }\n\n const authenticator = createIdentityProviderOAuth2Authenticator({\n accountManager: this.accountManager,\n provider: entity,\n options: { baseURL: this.options.baseURL },\n });\n\n const parameters : AuthorizeParameters = {};\n\n let codeRequest: OAuth2AuthorizationCodeRequest | undefined;\n const query = useRequestQuery(event);\n if (typeof query.codeRequest === 'string') {\n let codeRequestDecoded: OAuth2AuthorizationCodeRequest;\n\n try {\n codeRequestDecoded = JSON.parse(base64URLDecode(query.codeRequest));\n } catch {\n throw OAuth2RequestError.malformed('The code request is malformed and can not be parsed.');\n }\n\n const codeRequestValidated = await this.codeRequestValidator.run(codeRequestDecoded);\n const data = await this.codeRequestVerifier.verify(codeRequestValidated);\n\n if (\n data.client.realmId &&\n entity.realmId &&\n entity.realmId !== data.client.realmId\n ) {\n throw OAuth2RequestError.malformed('The provider and client realm do not match.');\n }\n\n codeRequest = data.data;\n }\n\n parameters.state = await this.saveAuthorizationState(event, codeRequest);\n\n return sendRedirect(event, authenticator.buildRedirectURL(parameters));\n }\n\n @DGet('/:id/authorize-in', [])\n async authorizeIn(\n @DPath('id') _id: string,\n @DContext() event: IAppEvent,\n ) {\n const id = useRequestParamID(event);\n\n const entity = await this.resolve(id);\n\n if (!isOAuth2IdentityProvider(entity) && !isOpenIDIdentityProvider(entity)) {\n throw new Error(`The provider protocol ${entity.protocol} is not valid.`);\n }\n\n const data = await this.verifyAuthorizationState(event);\n if (\n entity.realmId &&\n data.codeRequest &&\n data.codeRequest.realm_id &&\n data.codeRequest.realm_id !== entity.realmId\n ) {\n throw OAuth2RequestError.malformed('The provider and client realm do not match.');\n }\n\n const { code } = useRequestQuery(event);\n\n const authenticator = createIdentityProviderOAuth2Authenticator({\n accountManager: this.accountManager,\n provider: entity,\n options: {\n baseURL: this.options.baseURL,\n clientId: data.codeRequest?.client_id,\n },\n });\n\n const user = await authenticator.authenticate(code);\n\n const realm = await this.realmRepository.resolve(entity.realmId, true);\n\n // Application access policy (plan 052), federated leg: the callback\n // never redirects to the RP directly — a denial bounces back to the\n // hosted authorize page with error=access_denied, so no\n // redirectUriVerified threading through the state blob is needed.\n // A policy id with no wired evaluator denies (fail closed); a\n // since-deleted client is skipped (the /token backstop still covers it).\n if (data.codeRequest?.client_id) {\n const client = await this.clientRepository.findOneByIdOrName(\n data.codeRequest.client_id,\n data.codeRequest.realm_id,\n );\n\n if (client?.accessPolicyId) {\n let allowed = false;\n\n const subject = toIdentityPolicyData({\n type: IdentityType.USER,\n data: {\n ...user,\n realm,\n },\n });\n if (this.accessPolicyEvaluator && subject) {\n allowed = await this.accessPolicyEvaluator.evaluate(\n client.accessPolicyId,\n subject,\n );\n }\n\n if (!allowed) {\n const url = this.buildHostedAuthorizeURL(data.codeRequest);\n url.searchParams.set('error', OAuth2ErrorCode.ACCESS_DENIED);\n\n return sendRedirect(event, url.href);\n }\n }\n }\n\n const authorizationCode = await this.codeIssuer.issue(\n {\n response_type: 'code',\n client_id: data.codeRequest?.client_id,\n redirect_uri: data.codeRequest?.redirect_uri,\n scope: data.codeRequest?.scope,\n },\n {\n type: IdentityType.USER,\n data: {\n ...user,\n realm,\n },\n },\n { authMethod: SessionAuthMethod.EXTERNAL },\n );\n\n if (data.codeRequest) {\n const url = this.buildHostedAuthorizeURL(data.codeRequest);\n url.searchParams.set('code', authorizationCode.id);\n\n return sendRedirect(event, url.href);\n }\n\n const url = new URL(this.options.baseURL);\n url.searchParams.set('code', authorizationCode.id);\n\n return sendRedirect(event, url.href);\n }\n\n // ---------------------------------------------------------\n\n private async write(event: IAppEvent, options: {\n updateOnly?: boolean\n } = {}): Promise<EntityRecordResponse<IdentityProvider>> {\n let group: string;\n const id = getRequestParamID(event, { isUUID: false });\n const body = await readRequestBody(event);\n applyRouteRealmIDToBody(event, body);\n const realmId = getRequestRealmID(event) ?? getBodyRealmID(body);\n\n let entity: IdentityProvider | null | undefined;\n if (id) {\n const where: Record<string, any> = {};\n if (isUUID(id)) {\n where.id = id;\n } else {\n where.name = id;\n }\n\n if (realmId) {\n where.realmId = realmId;\n }\n\n entity = await this.repository.findOneBy(where);\n if (!entity && options.updateOnly) {\n throw new EntityNotFoundError();\n }\n } else if (options.updateOnly) {\n throw new EntityNotFoundError();\n }\n\n const permissionEvaluator = useRequestPermissionEvaluator(event);\n if (entity) {\n await permissionEvaluator.preEvaluate({ name: PermissionName.IDENTITY_PROVIDER_UPDATE });\n\n group = ValidatorGroup.UPDATE;\n } else {\n await permissionEvaluator.preEvaluate({ name: PermissionName.IDENTITY_PROVIDER_CREATE });\n\n group = ValidatorGroup.CREATE;\n }\n\n const validator = new IdentityProviderValidator();\n const data = await validator.run(body, { group });\n\n const attributesValidator = new IdentityProviderAttributesValidator();\n const attributes = await attributesValidator.run(body);\n\n await this.repository.validateJoinColumns(data);\n\n if (entity) {\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_UPDATE,\n data: definePolicyData({\n [BuiltInPolicyType.ATTRIBUTES]: {\n ...entity,\n ...data,\n },\n [BuiltInPolicyType.REALM_MATCH]: data.realmId ?? entity.realmId ?? null,\n }),\n });\n } else {\n if (!data.realmId) {\n const identity = useRequestIdentityOrFail(event);\n data.realmId = identity.realmId;\n }\n\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_CREATE,\n data: definePolicyData({ [BuiltInPolicyType.ATTRIBUTES]: data, [BuiltInPolicyType.REALM_MATCH]: data.realmId ?? null }),\n });\n }\n\n await this.repository.checkUniqueness(data, entity || undefined);\n\n if (entity) {\n entity = this.repository.merge(entity, data);\n await this.repository.saveWithEA(entity, attributes);\n\n event.response.status = 202;\n\n return { data: entity, meta: {} };\n }\n\n entity = this.repository.create(data);\n await this.repository.saveWithEA(entity, attributes);\n\n event.response.status = 201;\n\n return { data: entity, meta: {} };\n }\n\n // ---------------------------------------------------------\n\n private buildHostedAuthorizeURL(codeRequest: OAuth2AuthorizationCodeRequest): URL {\n const url = new URL(resolveURL(this.options.baseURL, 'authorize'));\n\n const codeRequestKeys = Object.keys(codeRequest);\n for (const codeRequestKey_ of codeRequestKeys) {\n const codeRequestKey = codeRequestKey_ as keyof OAuth2AuthorizationCodeRequest;\n const codeRequestValue = codeRequest[codeRequestKey];\n // Preserve meaningful falsy values (e.g. max_age=0, which OIDC\n // treats as prompt=login) — only skip absent ones.\n if (typeof codeRequestValue !== 'undefined' && codeRequestValue !== null) {\n url.searchParams.set(codeRequestKey, String(codeRequestValue));\n }\n }\n\n return url;\n }\n\n // ---------------------------------------------------------\n\n private async resolve(id: string) {\n const entity = await this.repository.findOneById(id);\n\n if (!entity) {\n throw new EntityNotFoundError();\n }\n\n return entity;\n }\n\n // ---------------------------------------------------------\n\n private async saveAuthorizationState(\n event: IAppEvent,\n codeRequest?: OAuth2AuthorizationCodeRequest,\n ) : Promise<string> {\n return this.stateManager.save({\n codeRequest,\n ip: getRequestIP(event) ?? '',\n userAgent: getRequestHeader(event, 'user-agent') ?? undefined,\n });\n }\n\n private async verifyAuthorizationState(event: IAppEvent): Promise<OAuth2AuthorizationState> {\n const query = useRequestQuery(event);\n if (typeof query.state !== 'string') {\n throw OAuth2RequestError.stateInvalid();\n }\n\n return this.stateManager.verify(query.state, {\n ip: getRequestIP(event) ?? '',\n userAgent: getRequestHeader(event, 'user-agent') ?? undefined,\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"module.mjs","names":["BuiltInPolicyType","definePolicyData","ValidatorGroup","base64URLDecode","isUUID","DBody","DContext","DController","DDelete","DGet","DPath","DPost","DPut","DTags","getRequestHeader","getRequestIP","sendRedirect","IdentityProviderAttributesValidator","IdentityProviderValidator","IdentityType","PermissionName","SessionAuthMethod","isOAuth2IdentityProvider","isOpenIDIdentityProvider","BadRequestError","EntityNotFoundError","resolveURL","useRequestQuery","readRequestBody","OAuth2ErrorCode","OAuth2RequestError","URL","OAuth2AuthorizationCodeRequestValidator","RECORD_QUERY_PARAMETERS","createIdentityProviderOAuth2Authenticator","decodeQuery","describeQuerySchema","identityProviderSchema","toIdentityPolicyData","applyRouteRealmIDToBody","buildActorContext","getBodyRealmID","getRequestParamID","getRequestRealmID","useRequestIdentityOrFail","useRequestParamID","useRequestPermissionEvaluator","ForceLoggedInMiddleware","IdentityProviderController","options","repository","realmRepository","clientRepository","accountManager","codeRequestVerifier","codeRequestValidator","stateManager","codeIssuer","accessPolicyEvaluator","ctx","getProviders","event","data","meta","findMany","schema","actor","permissionEvaluator","preEvaluate","name","IDENTITY_PROVIDER_READ","datum","evaluate","ATTRIBUTES","REALM_MATCH","realmId","getProvider","id","paramId","entity","findOneByIdOrName","editProvider","user","write","updateOnly","put","dropProvider","IDENTITY_PROVIDER_DELETE","findOneBy","entityId","remove","response","status","addProvider","authorizeOut","_id","resolve","authenticator","provider","baseURL","parameters","codeRequest","query","codeRequestDecoded","JSON","parse","malformed","codeRequestValidated","run","verify","client","state","saveAuthorizationState","buildRedirectURL","authorizeIn","Error","protocol","verifyAuthorizationState","realm_id","code","clientId","client_id","authenticate","realm","accessPolicyId","allowed","subject","type","USER","url","buildHostedAuthorizeURL","searchParams","set","ACCESS_DENIED","href","authorizationCode","issue","response_type","redirect_uri","scope","authMethod","EXTERNAL","group","body","where","IDENTITY_PROVIDER_UPDATE","UPDATE","IDENTITY_PROVIDER_CREATE","CREATE","validator","attributesValidator","attributes","validateJoinColumns","identity","checkUniqueness","undefined","merge","saveWithEA","create","codeRequestKeys","Object","keys","codeRequestKey_","codeRequestKey","codeRequestValue","String","findOneById","save","ip","userAgent","stateInvalid"],"sources":["../../../../../../src/adapters/http/controllers/entities/identity-provider/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { BuiltInPolicyType, definePolicyData } from '@authup/access';\nimport { ValidatorGroup, base64URLDecode, isUUID } from '@authup/kit';\nimport {\n DBody,\n DContext,\n DController,\n DDelete,\n DGet,\n DPath,\n DPost,\n DPut,\n DTags,\n} from '@routup/decorators';\nimport type { IAppEvent } from 'routup';\nimport {\n getRequestHeader,\n getRequestIP,\n sendRedirect,\n} from 'routup';\nimport type { IdentityProvider, OAuth2AuthorizationCodeRequest } from '@authup/core-kit';\nimport {\n\n IdentityProviderAttributesValidator,\n IdentityProviderValidator,\n IdentityType,\n PermissionName,\n SessionAuthMethod,\n isOAuth2IdentityProvider,\n isOpenIDIdentityProvider,\n} from '@authup/core-kit';\nimport { BadRequestError, EntityNotFoundError } from '@authup/errors';\nimport { resolveURL } from '../../../../../utils/index.ts';\nimport type { AuthorizeParameters } from '@hapic/oauth2';\nimport { useRequestQuery } from '@routup/basic/query';\nimport { readRequestBody } from '@routup/basic/body';\nimport { OAuth2ErrorCode, OAuth2RequestError } from '@authup/specs';\nimport type {\n EntityCollectionResponse,\n EntityRecordResponse,\n IdentityProviderCreatePayload,\n IdentityProviderSavePayload,\n IdentityProviderUpdatePayload,\n} from '@authup/core-http-kit';\nimport { URL } from 'node:url';\nimport type {\n IIdentityProviderAccountManager,\n IIdentityProviderRepository,\n IOAuth2AccessPolicyEvaluator,\n IOAuth2AuthorizationCodeIssuer,\n IOAuth2AuthorizationCodeRequestVerifier,\n IOAuth2AuthorizationStateManager,\n IOAuth2ClientRepository,\n IRealmRepository,\n OAuth2AuthorizationState,\n} from '../../../../../core/index.ts';\nimport {\n OAuth2AuthorizationCodeRequestValidator,\n RECORD_QUERY_PARAMETERS,\n createIdentityProviderOAuth2Authenticator,\n decodeQuery,\n describeQuerySchema,\n identityProviderSchema,\n toIdentityPolicyData,\n} from '../../../../../core/index.ts';\nimport {\n applyRouteRealmIDToBody,\n buildActorContext,\n getBodyRealmID,\n getRequestParamID,\n getRequestRealmID,\n useRequestIdentityOrFail,\n useRequestParamID,\n useRequestPermissionEvaluator,\n} from '../../../request/index.ts';\nimport { ForceLoggedInMiddleware } from '../../../middleware/index.ts';\nimport type { IdentityProviderControllerContext, IdentityProviderControllerOptions } from './types.ts';\n\n@DTags('identity')\n@DController(['/identity-providers', '/realms/:realmId/identity-providers'])\nexport class IdentityProviderController {\n protected options: IdentityProviderControllerOptions;\n\n protected repository: IIdentityProviderRepository;\n\n protected realmRepository: IRealmRepository;\n\n protected clientRepository: IOAuth2ClientRepository;\n\n protected accountManager: IIdentityProviderAccountManager;\n\n protected codeRequestVerifier : IOAuth2AuthorizationCodeRequestVerifier;\n\n protected codeRequestValidator : OAuth2AuthorizationCodeRequestValidator;\n\n protected stateManager : IOAuth2AuthorizationStateManager;\n\n protected codeIssuer : IOAuth2AuthorizationCodeIssuer;\n\n protected accessPolicyEvaluator? : IOAuth2AccessPolicyEvaluator;\n\n // ---------------------------------------------------------\n\n constructor(ctx: IdentityProviderControllerContext) {\n this.options = ctx.options;\n this.repository = ctx.repository;\n this.realmRepository = ctx.realmRepository;\n this.clientRepository = ctx.clientRepository;\n this.accountManager = ctx.accountManager;\n this.codeIssuer = ctx.codeIssuer;\n this.codeRequestVerifier = ctx.codeRequestVerifier;\n this.codeRequestValidator = new OAuth2AuthorizationCodeRequestValidator();\n this.stateManager = ctx.stateManager;\n this.accessPolicyEvaluator = ctx.accessPolicyEvaluator;\n }\n\n // ---------------------------------------------------------\n\n @DGet('', [])\n async getProviders(\n @DContext() event: IAppEvent,\n ): Promise<EntityCollectionResponse<IdentityProvider>> {\n const {\n data,\n meta,\n } = await this.repository.findMany(\n await decodeQuery(useRequestQuery(event), {\n schema: identityProviderSchema,\n actor: buildActorContext(event),\n }),\n );\n\n try {\n const permissionEvaluator = useRequestPermissionEvaluator(event);\n await permissionEvaluator.preEvaluate({ name: PermissionName.IDENTITY_PROVIDER_READ });\n\n for (const datum of data) {\n try {\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_READ,\n data: definePolicyData({ [BuiltInPolicyType.ATTRIBUTES]: datum, [BuiltInPolicyType.REALM_MATCH]: datum.realmId ?? null }),\n });\n } catch {\n // do nothing\n }\n }\n } catch {\n // do nothing\n }\n\n return {\n data,\n meta: {\n ...meta,\n schema: describeQuerySchema(identityProviderSchema),\n },\n };\n }\n\n @DGet('/:id', [])\n async getProvider(\n @DPath('id') id: string,\n @DContext() event: IAppEvent,\n ): Promise<EntityRecordResponse<IdentityProvider>> {\n const paramId = useRequestParamID(event, { isUUID: false });\n\n const entity = await this.repository.findOneByIdOrName(\n paramId,\n getRequestRealmID(event),\n );\n\n if (!entity) {\n throw new EntityNotFoundError();\n }\n\n try {\n const permissionEvaluator = useRequestPermissionEvaluator(event);\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_READ,\n data: definePolicyData({ [BuiltInPolicyType.ATTRIBUTES]: entity, [BuiltInPolicyType.REALM_MATCH]: entity.realmId ?? null }),\n });\n } catch {\n // do nothing\n }\n\n return { data: entity, meta: { schema: describeQuerySchema(identityProviderSchema, RECORD_QUERY_PARAMETERS) } };\n }\n\n @DPost('/:id', [ForceLoggedInMiddleware])\n async editProvider(\n @DPath('id') id: string,\n @DBody() user: IdentityProviderUpdatePayload,\n @DContext() event: IAppEvent,\n ) : Promise<EntityRecordResponse<IdentityProvider>> {\n return this.write(event, { updateOnly: true });\n }\n\n @DPut('/:id', [ForceLoggedInMiddleware])\n async put(\n @DPath('id') id: string,\n @DBody() user: IdentityProviderSavePayload,\n @DContext() event: IAppEvent,\n ) : Promise<EntityRecordResponse<IdentityProvider>> {\n return this.write(event);\n }\n\n @DDelete('/:id', [ForceLoggedInMiddleware])\n async dropProvider(\n @DPath('id') id: string,\n @DContext() event: IAppEvent,\n ) : Promise<EntityRecordResponse<IdentityProvider>> {\n const paramId = useRequestParamID(event);\n\n const permissionEvaluator = useRequestPermissionEvaluator(event);\n await permissionEvaluator.preEvaluate({ name: PermissionName.IDENTITY_PROVIDER_DELETE });\n\n const entity = await this.repository.findOneBy({ id: paramId });\n\n if (!entity) {\n throw new EntityNotFoundError();\n }\n\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_DELETE,\n data: definePolicyData({ [BuiltInPolicyType.ATTRIBUTES]: entity, [BuiltInPolicyType.REALM_MATCH]: entity.realmId ?? null }),\n });\n\n const { id: entityId } = entity;\n\n await this.repository.remove(entity);\n\n entity.id = entityId;\n\n event.response.status = 202;\n\n return { data: entity, meta: {} };\n }\n\n @DPost('', [ForceLoggedInMiddleware])\n async addProvider(\n @DBody() user: IdentityProviderCreatePayload,\n @DContext() event: IAppEvent,\n ) : Promise<EntityRecordResponse<IdentityProvider>> {\n return this.write(event);\n }\n\n // ---------------------------------------------------------\n\n @DGet('/:id/authorize-out', [])\n async authorizeOut(\n @DPath('id') _id: string,\n @DContext() event: IAppEvent,\n ) {\n const id = useRequestParamID(event);\n const entity = await this.resolve(id);\n\n if (!isOAuth2IdentityProvider(entity) && !isOpenIDIdentityProvider(entity)) {\n throw new BadRequestError('Only an identity-provider based on the oauth protocol supports authorize redirect.');\n }\n\n const authenticator = createIdentityProviderOAuth2Authenticator({\n accountManager: this.accountManager,\n provider: entity,\n options: { baseURL: this.options.baseURL },\n });\n\n const parameters : AuthorizeParameters = {};\n\n let codeRequest: OAuth2AuthorizationCodeRequest | undefined;\n const query = useRequestQuery(event);\n if (typeof query.codeRequest === 'string') {\n let codeRequestDecoded: OAuth2AuthorizationCodeRequest;\n\n try {\n codeRequestDecoded = JSON.parse(base64URLDecode(query.codeRequest));\n } catch {\n throw OAuth2RequestError.malformed('The code request is malformed and can not be parsed.');\n }\n\n const codeRequestValidated = await this.codeRequestValidator.run(codeRequestDecoded);\n const data = await this.codeRequestVerifier.verify(codeRequestValidated);\n\n if (\n data.client.realmId &&\n entity.realmId &&\n entity.realmId !== data.client.realmId\n ) {\n throw OAuth2RequestError.malformed('The provider and client realm do not match.');\n }\n\n codeRequest = data.data;\n }\n\n parameters.state = await this.saveAuthorizationState(event, codeRequest);\n\n return sendRedirect(event, authenticator.buildRedirectURL(parameters));\n }\n\n @DGet('/:id/authorize-in', [])\n async authorizeIn(\n @DPath('id') _id: string,\n @DContext() event: IAppEvent,\n ) {\n const id = useRequestParamID(event);\n\n const entity = await this.resolve(id);\n\n if (!isOAuth2IdentityProvider(entity) && !isOpenIDIdentityProvider(entity)) {\n throw new Error(`The provider protocol ${entity.protocol} is not valid.`);\n }\n\n const data = await this.verifyAuthorizationState(event);\n if (\n entity.realmId &&\n data.codeRequest &&\n data.codeRequest.realm_id &&\n data.codeRequest.realm_id !== entity.realmId\n ) {\n throw OAuth2RequestError.malformed('The provider and client realm do not match.');\n }\n\n const { code } = useRequestQuery(event);\n\n const authenticator = createIdentityProviderOAuth2Authenticator({\n accountManager: this.accountManager,\n provider: entity,\n options: {\n baseURL: this.options.baseURL,\n clientId: data.codeRequest?.client_id,\n },\n });\n\n const user = await authenticator.authenticate(code);\n\n const realm = await this.realmRepository.resolve(entity.realmId, true);\n\n // Application access policy (plan 052), federated leg: the callback\n // never redirects to the RP directly — a denial bounces back to the\n // hosted authorize page with error=access_denied, so no\n // redirectUriVerified threading through the state blob is needed.\n // A policy id with no wired evaluator denies (fail closed); a\n // since-deleted client is skipped (the /token backstop still covers it).\n if (data.codeRequest?.client_id) {\n const client = await this.clientRepository.findOneByIdOrName(\n data.codeRequest.client_id,\n data.codeRequest.realm_id,\n );\n\n if (client?.accessPolicyId) {\n let allowed = false;\n\n const subject = toIdentityPolicyData({\n type: IdentityType.USER,\n data: {\n ...user,\n realm,\n },\n });\n if (this.accessPolicyEvaluator && subject) {\n allowed = await this.accessPolicyEvaluator.evaluate(\n client.accessPolicyId,\n subject,\n );\n }\n\n if (!allowed) {\n const url = this.buildHostedAuthorizeURL(data.codeRequest);\n url.searchParams.set('error', OAuth2ErrorCode.ACCESS_DENIED);\n\n return sendRedirect(event, url.href);\n }\n }\n }\n\n const authorizationCode = await this.codeIssuer.issue(\n {\n response_type: 'code',\n client_id: data.codeRequest?.client_id,\n redirect_uri: data.codeRequest?.redirect_uri,\n scope: data.codeRequest?.scope,\n },\n {\n type: IdentityType.USER,\n data: {\n ...user,\n realm,\n },\n },\n { authMethod: SessionAuthMethod.EXTERNAL },\n );\n\n if (data.codeRequest) {\n const url = this.buildHostedAuthorizeURL(data.codeRequest);\n url.searchParams.set('code', authorizationCode.id);\n\n return sendRedirect(event, url.href);\n }\n\n const url = new URL(this.options.baseURL);\n url.searchParams.set('code', authorizationCode.id);\n\n return sendRedirect(event, url.href);\n }\n\n // ---------------------------------------------------------\n\n private async write(event: IAppEvent, options: {\n updateOnly?: boolean\n } = {}): Promise<EntityRecordResponse<IdentityProvider>> {\n let group: string;\n const id = getRequestParamID(event, { isUUID: false });\n const body = await readRequestBody(event);\n applyRouteRealmIDToBody(event, body);\n const realmId = getRequestRealmID(event) ?? getBodyRealmID(body);\n\n let entity: IdentityProvider | null | undefined;\n if (id) {\n const where: Record<string, any> = {};\n if (isUUID(id)) {\n where.id = id;\n } else {\n where.name = id;\n }\n\n if (realmId) {\n where.realmId = realmId;\n }\n\n entity = await this.repository.findOneBy(where);\n // Only a NAME key may upsert-create. A UUID addresses one specific\n // row, so a miss is a 404 (creating would write a different id).\n if (!entity && (options.updateOnly || where.id)) {\n throw new EntityNotFoundError();\n }\n } else if (options.updateOnly) {\n throw new EntityNotFoundError();\n }\n\n const permissionEvaluator = useRequestPermissionEvaluator(event);\n if (entity) {\n await permissionEvaluator.preEvaluate({ name: PermissionName.IDENTITY_PROVIDER_UPDATE });\n\n group = ValidatorGroup.UPDATE;\n } else {\n await permissionEvaluator.preEvaluate({ name: PermissionName.IDENTITY_PROVIDER_CREATE });\n\n group = ValidatorGroup.CREATE;\n }\n\n const validator = new IdentityProviderValidator();\n const data = await validator.run(body, { group });\n\n const attributesValidator = new IdentityProviderAttributesValidator();\n const attributes = await attributesValidator.run(body);\n\n await this.repository.validateJoinColumns(data);\n\n if (entity) {\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_UPDATE,\n data: definePolicyData({\n [BuiltInPolicyType.ATTRIBUTES]: {\n ...entity,\n ...data,\n },\n [BuiltInPolicyType.REALM_MATCH]: data.realmId ?? entity.realmId ?? null,\n }),\n });\n } else {\n if (!data.realmId) {\n const identity = useRequestIdentityOrFail(event);\n data.realmId = identity.realmId;\n }\n\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_CREATE,\n data: definePolicyData({ [BuiltInPolicyType.ATTRIBUTES]: data, [BuiltInPolicyType.REALM_MATCH]: data.realmId ?? null }),\n });\n }\n\n await this.repository.checkUniqueness(data, entity || undefined);\n\n if (entity) {\n entity = this.repository.merge(entity, data);\n await this.repository.saveWithEA(entity, attributes);\n\n event.response.status = 202;\n\n return { data: entity, meta: {} };\n }\n\n entity = this.repository.create(data);\n await this.repository.saveWithEA(entity, attributes);\n\n event.response.status = 201;\n\n return { data: entity, meta: {} };\n }\n\n // ---------------------------------------------------------\n\n private buildHostedAuthorizeURL(codeRequest: OAuth2AuthorizationCodeRequest): URL {\n const url = new URL(resolveURL(this.options.baseURL, 'authorize'));\n\n const codeRequestKeys = Object.keys(codeRequest);\n for (const codeRequestKey_ of codeRequestKeys) {\n const codeRequestKey = codeRequestKey_ as keyof OAuth2AuthorizationCodeRequest;\n const codeRequestValue = codeRequest[codeRequestKey];\n // Preserve meaningful falsy values (e.g. max_age=0, which OIDC\n // treats as prompt=login) — only skip absent ones.\n if (typeof codeRequestValue !== 'undefined' && codeRequestValue !== null) {\n url.searchParams.set(codeRequestKey, String(codeRequestValue));\n }\n }\n\n return url;\n }\n\n // ---------------------------------------------------------\n\n private async resolve(id: string) {\n const entity = await this.repository.findOneById(id);\n\n if (!entity) {\n throw new EntityNotFoundError();\n }\n\n return entity;\n }\n\n // ---------------------------------------------------------\n\n private async saveAuthorizationState(\n event: IAppEvent,\n codeRequest?: OAuth2AuthorizationCodeRequest,\n ) : Promise<string> {\n return this.stateManager.save({\n codeRequest,\n ip: getRequestIP(event) ?? '',\n userAgent: getRequestHeader(event, 'user-agent') ?? undefined,\n });\n }\n\n private async verifyAuthorizationState(event: IAppEvent): Promise<OAuth2AuthorizationState> {\n const query = useRequestQuery(event);\n if (typeof query.state !== 'string') {\n throw OAuth2RequestError.stateInvalid();\n }\n\n return this.stateManager.verify(query.state, {\n ip: getRequestIP(event) ?? '',\n userAgent: getRequestHeader(event, 'user-agent') ?? undefined,\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -52,7 +52,8 @@ var AuthorizationMiddleware = class {
|
|
|
52
52
|
return promise;
|
|
53
53
|
}
|
|
54
54
|
async runInner(event) {
|
|
55
|
-
|
|
55
|
+
const requestAccessContext = new RequestPermissionEvaluator(event, this.permissionEvaluator);
|
|
56
|
+
setRequestPermissionEvaluator(event, requestAccessContext);
|
|
56
57
|
const headerValue = event.headers.get("authorization");
|
|
57
58
|
if (!headerValue) return;
|
|
58
59
|
const header = parseAuthorizationHeader(headerValue);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.mjs","names":["PermissionEvaluator","IdentityType","ScopeName","AuthHeaderError","JWTError","OAuth2SubKind","OAuth2TokenKind","deserializeOAuth2Scope","AuthorizationHeaderType","parseAuthorizationHeader","ClientAuthenticator","PolicyEngine","UserAuthenticator","assertClientCertificateEvidenceValidForBinding","RequestIdentity","RequestPermissionEvaluator","extractClientCertificateEvidence","setRequestIdentity","setRequestMfaLoginTicket","setRequestPermissionEvaluator","setRequestScopes","setRequestSessionId","setRequestToken","runSymbol","Symbol","AuthorizationMiddleware","options","oauth2TokenVerifier","permissionEvaluator","identityResolver","sessionManager","clientAuthenticator","userAuthenticator","ctx","provider","permissionProvider","policyEngine","identityPermissionProvider","realmId","clientId","run","event","pending","store","promise","runInner","requestAccessContext","headerValue","headers","get","header","type","BEARER","verifyBearerAuthorizationHeader","BASIC","verifyBasicAuthorizationHeader","unsupportedType","payload","verify","token","verifyCertificateBinding","kind","MFA","verifyMfaLoginTicket","ACCESS","payloadPropertyInvalid","realm_id","scope","session_id","session","findOneById","expired","ping","sub_kind","sub","identity","resolve","cnf","expectedThumbprint","length","invalid","evidence","certificateSource","thumbprint","USER","subKind","clientAuthBasic","authenticator","safeAuthenticate","username","password","success","GLOBAL","CLIENT","data","userAuthBasic","authenticated"],"sources":["../../../../../../src/adapters/http/middleware/built-in/authorization/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { IPermissionEvaluator } from '@authup/access';\nimport { PermissionEvaluator } from '@authup/access';\nimport type { Client, User } from '@authup/core-kit';\nimport {\n IdentityType,\n ScopeName,\n} from '@authup/core-kit';\nimport { AuthHeaderError } from '@authup/errors';\nimport type { OAuth2TokenPayload } from '@authup/specs';\nimport {\n JWTError,\n OAuth2SubKind,\n OAuth2TokenKind,\n deserializeOAuth2Scope,\n} from '@authup/specs';\nimport type { IAppEvent } from 'routup';\nimport {\n AuthorizationHeaderType,\n type BasicAuthorizationHeader,\n type BearerAuthorizationHeader,\n parseAuthorizationHeader,\n} from 'hapic';\nimport {\n ClientAuthenticator,\n PolicyEngine,\n UserAuthenticator,\n assertClientCertificateEvidenceValidForBinding,\n} from '../../../../../core/index.ts';\nimport type {\n ICredentialsAuthenticator,\n IIdentityResolver,\n IOAuth2TokenVerifier,\n ISessionManager,\n} from '../../../../../core/index.ts';\nimport {\n RequestIdentity,\n RequestPermissionEvaluator,\n extractClientCertificateEvidence,\n setRequestIdentity,\n setRequestMfaLoginTicket,\n setRequestPermissionEvaluator,\n setRequestScopes,\n setRequestSessionId,\n setRequestToken,\n} from '../../../request/index.ts';\nimport type { HTTPAuthorizationMiddlewareContext, HTTPAuthorizationMiddlewareOptions } from './types.ts';\n\nconst runSymbol = Symbol('RAuthorizationMiddlewareRun');\n\nexport class AuthorizationMiddleware {\n protected options: HTTPAuthorizationMiddlewareOptions;\n\n // --------------------------------------\n\n protected oauth2TokenVerifier: IOAuth2TokenVerifier;\n\n protected permissionEvaluator: IPermissionEvaluator;\n\n // --------------------------------------\n\n protected identityResolver: IIdentityResolver;\n\n protected sessionManager : ISessionManager;\n\n // --------------------------------------\n\n protected clientAuthenticator : ICredentialsAuthenticator<Client>;\n\n protected userAuthenticator : ICredentialsAuthenticator<User>;\n\n // --------------------------------------\n\n constructor(ctx: HTTPAuthorizationMiddlewareContext) {\n this.options = ctx.options || {};\n\n this.identityResolver = ctx.identityResolver;\n this.sessionManager = ctx.sessionManager;\n\n this.clientAuthenticator = new ClientAuthenticator(ctx.identityResolver);\n this.userAuthenticator = new UserAuthenticator(ctx.identityResolver);\n\n this.oauth2TokenVerifier = ctx.oauth2TokenVerifier;\n\n this.permissionEvaluator = new PermissionEvaluator({\n provider: ctx.permissionProvider,\n policyEngine: new PolicyEngine(ctx.identityPermissionProvider),\n realmId: null,\n clientId: null,\n });\n }\n\n // --------------------------------------\n\n async run(event: IAppEvent): Promise<void> {\n // routup's dispatch walk re-enters earlier middlewares once per\n // remaining match when no handler produces a response — exponentially\n // (routup/routup#946), so an unmatched authenticated request re-ran\n // this middleware ~100+ times, re-verifying Basic credentials (bcrypt)\n // on every re-entry (~4s per 404). Authorization is a pure function of\n // the request: the first run's settlement — including a rejection —\n // is authoritative, so memoize the promise on the request store (the\n // store is shared by every re-entry of the same request).\n const pending = event.store[runSymbol] as Promise<void> | undefined;\n if (pending) {\n return pending;\n }\n\n const promise = this.runInner(event);\n event.store[runSymbol] = promise;\n return promise;\n }\n\n protected async runInner(event: IAppEvent): Promise<void> {\n const requestAccessContext = new RequestPermissionEvaluator(\n event,\n this.permissionEvaluator,\n );\n setRequestPermissionEvaluator(event, requestAccessContext);\n\n const headerValue = event.headers.get('authorization');\n if (!headerValue) {\n return;\n }\n\n const header = parseAuthorizationHeader(headerValue);\n\n if (header.type === AuthorizationHeaderType.BEARER) {\n await this.verifyBearerAuthorizationHeader(event, header);\n return;\n }\n\n if (header.type === AuthorizationHeaderType.BASIC) {\n await this.verifyBasicAuthorizationHeader(event, header);\n return;\n }\n\n throw AuthHeaderError.unsupportedType(header.type);\n }\n\n /**\n * @throws JWTError\n */\n protected async verifyBearerAuthorizationHeader(\n event: IAppEvent,\n header: BearerAuthorizationHeader,\n ) {\n const payload = await this.oauth2TokenVerifier.verify(header.token);\n await this.verifyCertificateBinding(event, payload);\n if (payload.kind === OAuth2TokenKind.MFA) {\n await this.verifyMfaLoginTicket(event, payload);\n return;\n }\n\n if (payload.kind !== OAuth2TokenKind.ACCESS) {\n throw JWTError.payloadPropertyInvalid('kind');\n }\n\n if (!payload.realm_id) {\n throw JWTError.payloadPropertyInvalid('realm_id');\n }\n\n setRequestToken(event, header.token);\n\n if (payload.scope) {\n setRequestScopes(event, deserializeOAuth2Scope(payload.scope));\n }\n\n // -------------------------------------------------------\n\n if (!payload.session_id) {\n throw JWTError.payloadPropertyInvalid('session_id');\n }\n\n const session = await this.sessionManager.findOneById(payload.session_id);\n if (!session) {\n throw JWTError.expired();\n }\n\n try {\n await this.sessionManager.verify(session);\n } catch {\n throw JWTError.expired();\n }\n\n await this.sessionManager.ping(session);\n\n setRequestSessionId(event, payload.session_id);\n\n // -------------------------------------------------------\n\n if (!payload.sub_kind) {\n throw JWTError.payloadPropertyInvalid('sub_kind');\n }\n\n if (!payload.sub) {\n throw JWTError.payloadPropertyInvalid('sub');\n }\n\n const identity = await this.identityResolver.resolve(\n payload.sub_kind,\n payload.sub,\n );\n\n if (identity) {\n setRequestIdentity(event, identity);\n }\n }\n\n protected async verifyCertificateBinding(event: IAppEvent, payload: OAuth2TokenPayload): Promise<void> {\n if (!payload.cnf) {\n return;\n }\n\n const expectedThumbprint = payload.cnf['x5t#S256'];\n if (typeof expectedThumbprint !== 'string' || expectedThumbprint.length === 0) {\n throw JWTError.invalid();\n }\n\n try {\n const evidence = await extractClientCertificateEvidence(\n event,\n this.options.certificateSource ?? 'disabled',\n );\n if (!evidence || evidence.thumbprint !== expectedThumbprint) {\n throw JWTError.invalid();\n }\n\n assertClientCertificateEvidenceValidForBinding(evidence);\n } catch {\n throw JWTError.invalid();\n }\n }\n\n /**\n * An \"MFA-pending\" login ticket (issue #3242). Verified with the same\n * rigor as an access token (session existence + subject match), but\n * stashed on a DEDICATED request slot — the main identity / scope /\n * session slots stay empty, so every identity-gated route rejects a\n * ticket bearer (default-deny); only the challenge routes opt in via\n * useRequestMfaLoginTicket.\n *\n * @throws JWTError\n */\n protected async verifyMfaLoginTicket(\n event: IAppEvent,\n payload: OAuth2TokenPayload,\n ) {\n if (payload.sub_kind !== OAuth2SubKind.USER) {\n throw JWTError.payloadPropertyInvalid('sub_kind');\n }\n\n if (!payload.sub) {\n throw JWTError.payloadPropertyInvalid('sub');\n }\n\n if (!payload.realm_id) {\n throw JWTError.payloadPropertyInvalid('realm_id');\n }\n\n if (!payload.session_id) {\n throw JWTError.payloadPropertyInvalid('session_id');\n }\n\n const session = await this.sessionManager.findOneById(payload.session_id);\n if (!session) {\n throw JWTError.expired();\n }\n\n try {\n await this.sessionManager.verify(session);\n } catch {\n throw JWTError.expired();\n }\n\n // defense in depth — the pending session must still belong to the\n // ticket subject.\n if (\n session.sub !== payload.sub ||\n session.subKind !== IdentityType.USER\n ) {\n throw JWTError.expired();\n }\n\n await this.sessionManager.ping(session);\n\n const identity = await this.identityResolver.resolve(\n payload.sub_kind,\n payload.sub,\n );\n if (!identity) {\n throw JWTError.expired();\n }\n\n setRequestMfaLoginTicket(event, {\n identity: new RequestIdentity(identity),\n payload,\n });\n }\n\n protected async verifyBasicAuthorizationHeader(\n event: IAppEvent,\n header: BasicAuthorizationHeader,\n ) {\n if (this.options.clientAuthBasic) {\n const authenticator = await this.clientAuthenticator.safeAuthenticate(\n header.username,\n header.password,\n );\n if (authenticator.success) {\n setRequestScopes(event, [ScopeName.GLOBAL]);\n setRequestIdentity(event, {\n type: IdentityType.CLIENT,\n data: authenticator.data,\n });\n }\n }\n\n if (this.options.userAuthBasic) {\n const authenticated = await this.userAuthenticator.safeAuthenticate(\n header.username,\n header.password,\n );\n\n if (authenticated.success) {\n setRequestScopes(event, [ScopeName.GLOBAL]);\n setRequestIdentity(event, {\n type: IdentityType.USER,\n data: authenticated.data,\n });\n }\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"module.mjs","names":["PermissionEvaluator","IdentityType","ScopeName","AuthHeaderError","JWTError","OAuth2SubKind","OAuth2TokenKind","deserializeOAuth2Scope","AuthorizationHeaderType","parseAuthorizationHeader","ClientAuthenticator","PolicyEngine","UserAuthenticator","assertClientCertificateEvidenceValidForBinding","RequestIdentity","RequestPermissionEvaluator","extractClientCertificateEvidence","setRequestIdentity","setRequestMfaLoginTicket","setRequestPermissionEvaluator","setRequestScopes","setRequestSessionId","setRequestToken","runSymbol","Symbol","AuthorizationMiddleware","options","oauth2TokenVerifier","permissionEvaluator","identityResolver","sessionManager","clientAuthenticator","userAuthenticator","ctx","provider","permissionProvider","policyEngine","identityPermissionProvider","realmId","clientId","run","event","pending","store","promise","runInner","requestAccessContext","headerValue","headers","get","header","type","BEARER","verifyBearerAuthorizationHeader","BASIC","verifyBasicAuthorizationHeader","unsupportedType","payload","verify","token","verifyCertificateBinding","kind","MFA","verifyMfaLoginTicket","ACCESS","payloadPropertyInvalid","realm_id","scope","session_id","session","findOneById","expired","ping","sub_kind","sub","identity","resolve","cnf","expectedThumbprint","length","invalid","evidence","certificateSource","thumbprint","USER","subKind","clientAuthBasic","authenticator","safeAuthenticate","username","password","success","GLOBAL","CLIENT","data","userAuthBasic","authenticated"],"sources":["../../../../../../src/adapters/http/middleware/built-in/authorization/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { IPermissionEvaluator } from '@authup/access';\nimport { PermissionEvaluator } from '@authup/access';\nimport type { Client, User } from '@authup/core-kit';\nimport {\n IdentityType,\n ScopeName,\n} from '@authup/core-kit';\nimport { AuthHeaderError } from '@authup/errors';\nimport type { OAuth2TokenPayload } from '@authup/specs';\nimport {\n JWTError,\n OAuth2SubKind,\n OAuth2TokenKind,\n deserializeOAuth2Scope,\n} from '@authup/specs';\nimport type { IAppEvent } from 'routup';\nimport {\n AuthorizationHeaderType,\n type BasicAuthorizationHeader,\n type BearerAuthorizationHeader,\n parseAuthorizationHeader,\n} from 'hapic';\nimport {\n ClientAuthenticator,\n PolicyEngine,\n UserAuthenticator,\n assertClientCertificateEvidenceValidForBinding,\n} from '../../../../../core/index.ts';\nimport type {\n ICredentialsAuthenticator,\n IIdentityResolver,\n IOAuth2TokenVerifier,\n ISessionManager,\n} from '../../../../../core/index.ts';\nimport {\n RequestIdentity,\n RequestPermissionEvaluator,\n extractClientCertificateEvidence,\n setRequestIdentity,\n setRequestMfaLoginTicket,\n setRequestPermissionEvaluator,\n setRequestScopes,\n setRequestSessionId,\n setRequestToken,\n} from '../../../request/index.ts';\nimport type { HTTPAuthorizationMiddlewareContext, HTTPAuthorizationMiddlewareOptions } from './types.ts';\n\nconst runSymbol = Symbol('RAuthorizationMiddlewareRun');\n\nexport class AuthorizationMiddleware {\n protected options: HTTPAuthorizationMiddlewareOptions;\n\n // --------------------------------------\n\n protected oauth2TokenVerifier: IOAuth2TokenVerifier;\n\n protected permissionEvaluator: IPermissionEvaluator;\n\n // --------------------------------------\n\n protected identityResolver: IIdentityResolver;\n\n protected sessionManager : ISessionManager;\n\n // --------------------------------------\n\n protected clientAuthenticator : ICredentialsAuthenticator<Client>;\n\n protected userAuthenticator : ICredentialsAuthenticator<User>;\n\n // --------------------------------------\n\n constructor(ctx: HTTPAuthorizationMiddlewareContext) {\n this.options = ctx.options || {};\n\n this.identityResolver = ctx.identityResolver;\n this.sessionManager = ctx.sessionManager;\n\n this.clientAuthenticator = new ClientAuthenticator(ctx.identityResolver);\n this.userAuthenticator = new UserAuthenticator(ctx.identityResolver);\n\n this.oauth2TokenVerifier = ctx.oauth2TokenVerifier;\n\n this.permissionEvaluator = new PermissionEvaluator({\n provider: ctx.permissionProvider,\n policyEngine: new PolicyEngine(ctx.identityPermissionProvider),\n realmId: null,\n clientId: null,\n });\n }\n\n // --------------------------------------\n\n async run(event: IAppEvent): Promise<void> {\n // routup's dispatch walk re-enters earlier middlewares once per\n // remaining match when no handler produces a response — exponentially\n // (routup/routup#946), so an unmatched authenticated request re-ran\n // this middleware ~100+ times, re-verifying Basic credentials (bcrypt)\n // on every re-entry (~4s per 404). Authorization is a pure function of\n // the request: the first run's settlement — including a rejection —\n // is authoritative, so memoize the promise on the request store (the\n // store is shared by every re-entry of the same request).\n const pending = event.store[runSymbol] as Promise<void> | undefined;\n if (pending) {\n return pending;\n }\n\n const promise = this.runInner(event);\n event.store[runSymbol] = promise;\n return promise;\n }\n\n protected async runInner(event: IAppEvent): Promise<void> {\n const requestAccessContext = new RequestPermissionEvaluator(\n event,\n this.permissionEvaluator,\n );\n setRequestPermissionEvaluator(event, requestAccessContext);\n\n const headerValue = event.headers.get('authorization');\n if (!headerValue) {\n return;\n }\n\n const header = parseAuthorizationHeader(headerValue);\n\n if (header.type === AuthorizationHeaderType.BEARER) {\n await this.verifyBearerAuthorizationHeader(event, header);\n return;\n }\n\n if (header.type === AuthorizationHeaderType.BASIC) {\n await this.verifyBasicAuthorizationHeader(event, header);\n return;\n }\n\n throw AuthHeaderError.unsupportedType(header.type);\n }\n\n /**\n * @throws JWTError\n */\n protected async verifyBearerAuthorizationHeader(\n event: IAppEvent,\n header: BearerAuthorizationHeader,\n ) {\n const payload = await this.oauth2TokenVerifier.verify(header.token);\n await this.verifyCertificateBinding(event, payload);\n if (payload.kind === OAuth2TokenKind.MFA) {\n await this.verifyMfaLoginTicket(event, payload);\n return;\n }\n\n if (payload.kind !== OAuth2TokenKind.ACCESS) {\n throw JWTError.payloadPropertyInvalid('kind');\n }\n\n if (!payload.realm_id) {\n throw JWTError.payloadPropertyInvalid('realm_id');\n }\n\n setRequestToken(event, header.token);\n\n if (payload.scope) {\n setRequestScopes(event, deserializeOAuth2Scope(payload.scope));\n }\n\n // -------------------------------------------------------\n\n if (!payload.session_id) {\n throw JWTError.payloadPropertyInvalid('session_id');\n }\n\n const session = await this.sessionManager.findOneById(payload.session_id);\n if (!session) {\n throw JWTError.expired();\n }\n\n try {\n await this.sessionManager.verify(session);\n } catch {\n throw JWTError.expired();\n }\n\n await this.sessionManager.ping(session);\n\n setRequestSessionId(event, payload.session_id);\n\n // -------------------------------------------------------\n\n if (!payload.sub_kind) {\n throw JWTError.payloadPropertyInvalid('sub_kind');\n }\n\n if (!payload.sub) {\n throw JWTError.payloadPropertyInvalid('sub');\n }\n\n const identity = await this.identityResolver.resolve(\n payload.sub_kind,\n payload.sub,\n );\n\n if (identity) {\n setRequestIdentity(event, identity);\n }\n }\n\n protected async verifyCertificateBinding(event: IAppEvent, payload: OAuth2TokenPayload): Promise<void> {\n if (!payload.cnf) {\n return;\n }\n\n const expectedThumbprint = payload.cnf['x5t#S256'];\n if (typeof expectedThumbprint !== 'string' || expectedThumbprint.length === 0) {\n throw JWTError.invalid();\n }\n\n try {\n const evidence = await extractClientCertificateEvidence(\n event,\n this.options.certificateSource ?? 'disabled',\n );\n if (!evidence || evidence.thumbprint !== expectedThumbprint) {\n throw JWTError.invalid();\n }\n\n assertClientCertificateEvidenceValidForBinding(evidence);\n } catch {\n throw JWTError.invalid();\n }\n }\n\n /**\n * An \"MFA-pending\" login ticket (issue #3242). Verified with the same\n * rigor as an access token (session existence + subject match), but\n * stashed on a DEDICATED request slot — the main identity / scope /\n * session slots stay empty, so every identity-gated route rejects a\n * ticket bearer (default-deny); only the challenge routes opt in via\n * useRequestMfaLoginTicket.\n *\n * @throws JWTError\n */\n protected async verifyMfaLoginTicket(\n event: IAppEvent,\n payload: OAuth2TokenPayload,\n ) {\n if (payload.sub_kind !== OAuth2SubKind.USER) {\n throw JWTError.payloadPropertyInvalid('sub_kind');\n }\n\n if (!payload.sub) {\n throw JWTError.payloadPropertyInvalid('sub');\n }\n\n if (!payload.realm_id) {\n throw JWTError.payloadPropertyInvalid('realm_id');\n }\n\n if (!payload.session_id) {\n throw JWTError.payloadPropertyInvalid('session_id');\n }\n\n const session = await this.sessionManager.findOneById(payload.session_id);\n if (!session) {\n throw JWTError.expired();\n }\n\n try {\n await this.sessionManager.verify(session);\n } catch {\n throw JWTError.expired();\n }\n\n // defense in depth — the pending session must still belong to the\n // ticket subject.\n if (\n session.sub !== payload.sub ||\n session.subKind !== IdentityType.USER\n ) {\n throw JWTError.expired();\n }\n\n await this.sessionManager.ping(session);\n\n const identity = await this.identityResolver.resolve(\n payload.sub_kind,\n payload.sub,\n );\n if (!identity) {\n throw JWTError.expired();\n }\n\n setRequestMfaLoginTicket(event, {\n identity: new RequestIdentity(identity),\n payload,\n });\n }\n\n protected async verifyBasicAuthorizationHeader(\n event: IAppEvent,\n header: BasicAuthorizationHeader,\n ) {\n if (this.options.clientAuthBasic) {\n const authenticator = await this.clientAuthenticator.safeAuthenticate(\n header.username,\n header.password,\n );\n if (authenticator.success) {\n setRequestScopes(event, [ScopeName.GLOBAL]);\n setRequestIdentity(event, {\n type: IdentityType.CLIENT,\n data: authenticator.data,\n });\n }\n }\n\n if (this.options.userAuthBasic) {\n const authenticated = await this.userAuthenticator.safeAuthenticate(\n header.username,\n header.password,\n );\n\n if (authenticated.success) {\n setRequestScopes(event, [ScopeName.GLOBAL]);\n setRequestIdentity(event, {\n type: IdentityType.USER,\n data: authenticated.data,\n });\n }\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -14,11 +14,11 @@ function registerRateLimitMiddleware(router, input) {
|
|
|
14
14
|
const identity = useRequestIdentity(event);
|
|
15
15
|
if (!identity) return 1200;
|
|
16
16
|
switch (identity.type) {
|
|
17
|
-
case "client": return
|
|
17
|
+
case "client": return 3e5;
|
|
18
18
|
default: return 6e3;
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
|
-
windowMs:
|
|
21
|
+
windowMs: 6e4
|
|
22
22
|
};
|
|
23
23
|
options = merge(input || {}, options);
|
|
24
24
|
router.use(rateLimit(options));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.mjs","names":["rateLimit","getRequestIP","merge","useRequestIdentity","registerRateLimitMiddleware","router","input","options","keyGenerator","event","max","identity","type","windowMs","use"],"sources":["../../../../../src/adapters/http/middleware/built-in/rate-limit.ts"],"sourcesContent":["/*\n * Copyright (c) 2023.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { OptionsInput } from '@routup/rate-limit';\nimport { rateLimit } from '@routup/rate-limit';\nimport type { App } from 'routup';\nimport { getRequestIP } from 'routup';\nimport { merge } from 'smob';\nimport { useRequestIdentity } from '../../request/index.ts';\n\nexport function registerRateLimitMiddleware(router: App, input?: OptionsInput) {\n let options : OptionsInput = {\n // @routup/rate-limit's default keyGenerator hardcodes\n // `{ trustProxy: true }`; deriving the key here instead lets it\n // follow the app-level trust contract (config `trustProxy`).\n keyGenerator: (event) => getRequestIP(event) || '127.0.0.1',\n max(event) {\n const identity = useRequestIdentity(event);\n if (!identity) {\n return 60 * 20; // 20 req. p. sec\n }\n\n switch (identity.type) {\n case 'client': {\n return 60 * 5_000; // 1000 req p. sec\n }\n case 'user':\n default: {\n return 60 * 100; // 100 req p. sec\n }\n }\n },\n windowMs: 60 * 1000, // 60 sec\n };\n\n options = merge(input || {}, options);\n\n router.use(rateLimit(options));\n}\n"],"mappings":";;;;;;;;;AAcA,SAAgBI,4BAA4BC,QAAaC,OAAoB;CACzE,IAAIC,UAAyB;EAIzBC,eAAeC,UAAUR,aAAaQ,KAAAA,KAAU;EAChDC,IAAID,OAAK;GACL,MAAME,WAAWR,mBAAmBM,KAAAA;GACpC,IAAI,CAACE,UACD,OAAO;GAGX,QAAQA,SAASC,MAAjB;IACI,KAAK,UACD,OAAO
|
|
1
|
+
{"version":3,"file":"rate-limit.mjs","names":["rateLimit","getRequestIP","merge","useRequestIdentity","registerRateLimitMiddleware","router","input","options","keyGenerator","event","max","identity","type","windowMs","use"],"sources":["../../../../../src/adapters/http/middleware/built-in/rate-limit.ts"],"sourcesContent":["/*\n * Copyright (c) 2023.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { OptionsInput } from '@routup/rate-limit';\nimport { rateLimit } from '@routup/rate-limit';\nimport type { App } from 'routup';\nimport { getRequestIP } from 'routup';\nimport { merge } from 'smob';\nimport { useRequestIdentity } from '../../request/index.ts';\n\nexport function registerRateLimitMiddleware(router: App, input?: OptionsInput) {\n let options : OptionsInput = {\n // @routup/rate-limit's default keyGenerator hardcodes\n // `{ trustProxy: true }`; deriving the key here instead lets it\n // follow the app-level trust contract (config `trustProxy`).\n keyGenerator: (event) => getRequestIP(event) || '127.0.0.1',\n max(event) {\n const identity = useRequestIdentity(event);\n if (!identity) {\n return 60 * 20; // 20 req. p. sec\n }\n\n switch (identity.type) {\n case 'client': {\n return 60 * 5_000; // 1000 req p. sec\n }\n case 'user':\n default: {\n return 60 * 100; // 100 req p. sec\n }\n }\n },\n windowMs: 60 * 1000, // 60 sec\n };\n\n options = merge(input || {}, options);\n\n router.use(rateLimit(options));\n}\n"],"mappings":";;;;;;;;;AAcA,SAAgBI,4BAA4BC,QAAaC,OAAoB;CACzE,IAAIC,UAAyB;EAIzBC,eAAeC,UAAUR,aAAaQ,KAAAA,KAAU;EAChDC,IAAID,OAAK;GACL,MAAME,WAAWR,mBAAmBM,KAAAA;GACpC,IAAI,CAACE,UACD,OAAO;GAGX,QAAQA,SAASC,MAAjB;IACI,KAAK,UACD,OAAO;IAGX,SACI,OAAO;GAEf;EACJ;EACAC,UAAU;CACd;CAEAN,UAAUL,MAAMI,SAAS,CAAC,GAAGC,OAAAA;CAE7BF,OAAOS,IAAId,UAAUO,OAAAA,CAAAA;AACzB"}
|
|
@@ -8,7 +8,7 @@ import { base64ToArrayBuffer } from "@authup/kit";
|
|
|
8
8
|
import { BadRequestError } from "@authup/errors";
|
|
9
9
|
import { X509Certificate } from "@peculiar/x509";
|
|
10
10
|
//#region src/adapters/http/request/client-certificate.ts
|
|
11
|
-
const MAX_CERTIFICATE_HEADER_LENGTH =
|
|
11
|
+
const MAX_CERTIFICATE_HEADER_LENGTH = 131072;
|
|
12
12
|
const MAX_CERTIFICATE_CHAIN_LENGTH = 10;
|
|
13
13
|
const STRUCTURED_BINARY_PATTERN = /^:([A-Za-z0-9+/]*={0,2}):$/;
|
|
14
14
|
async function extractClientCertificateEvidence(event, source) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-certificate.mjs","names":["X509Certificate","BadRequestError","base64ToArrayBuffer","buildClientCertificateThumbprint","parseClientCertificateChain","MAX_CERTIFICATE_HEADER_LENGTH","MAX_CERTIFICATE_CHAIN_LENGTH","STRUCTURED_BINARY_PATTERN","extractClientCertificateEvidence","event","source","undefined","result","extractStandardEvidence","extractForwardedEvidence","thumbprint","certificate","leafHeader","headers","get","chainHeader","certificateHeaderError","assertHeaderLength","parseStructuredCertificate","chain","parseStructuredCertificateList","value","pem","includes","decodeURIComponent","replace","certificates","length","items","split","map","item","trim","some","match","exec","raw","byteLength","toString"],"sources":["../../../../src/adapters/http/request/client-certificate.ts"],"sourcesContent":["/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport '../../../core/client-certificate/reflect.ts';\nimport { X509Certificate } from '@peculiar/x509';\nimport { BadRequestError } from '@authup/errors';\nimport { base64ToArrayBuffer } from '@authup/kit';\nimport type { IAppEvent } from 'routup';\nimport type { ClientCertificateEvidence } from '../../../core/index.ts';\nimport {\n buildClientCertificateThumbprint,\n parseClientCertificateChain,\n} from '../../../core/index.ts';\nimport type { CertificateSource } from './types.ts';\n\nconst MAX_CERTIFICATE_HEADER_LENGTH = 128 * 1024;\nconst MAX_CERTIFICATE_CHAIN_LENGTH = 10;\nconst STRUCTURED_BINARY_PATTERN = /^:([A-Za-z0-9+/]*={0,2}):$/;\n\nexport async function extractClientCertificateEvidence(\n event: IAppEvent,\n source: CertificateSource,\n): Promise<ClientCertificateEvidence | undefined> {\n if (source === 'disabled') {\n return undefined;\n }\n\n let result: Omit<ClientCertificateEvidence, 'thumbprint'> | undefined;\n if (source === 'standard') {\n result = extractStandardEvidence(event);\n } else if (source === 'forwarded') {\n result = extractForwardedEvidence(event);\n } else {\n throw new BadRequestError('The client certificate source is not configured correctly.');\n }\n if (!result) {\n return undefined;\n }\n\n return {\n ...result,\n thumbprint: await buildClientCertificateThumbprint(result.certificate),\n };\n}\n\nfunction extractStandardEvidence(\n event: IAppEvent,\n): Omit<ClientCertificateEvidence, 'thumbprint'> | undefined {\n const leafHeader = event.headers.get('client-cert');\n const chainHeader = event.headers.get('client-cert-chain');\n\n if (!leafHeader) {\n if (chainHeader) {\n throw certificateHeaderError();\n }\n return undefined;\n }\n\n assertHeaderLength(leafHeader);\n const certificate = parseStructuredCertificate(leafHeader);\n const chain = chainHeader ? parseStructuredCertificateList(chainHeader) : [];\n\n return { certificate, chain };\n}\n\nfunction extractForwardedEvidence(\n event: IAppEvent,\n): Omit<ClientCertificateEvidence, 'thumbprint'> | undefined {\n const value = event.headers.get('x-forwarded-tls-client-cert');\n if (!value) {\n return undefined;\n }\n\n assertHeaderLength(value);\n\n let pem: string;\n try {\n // Native raw PEM is useful in tests and a few proxy integrations. The\n // NGINX/Traefik contract is escaped PEM: query-style `+` represents a\n // space, while literal base64 plus signs arrive as `%2B`.\n pem = value.includes('-----BEGIN CERTIFICATE-----') ?\n value :\n decodeURIComponent(value.replace(/\\+/g, '%20'));\n } catch {\n throw certificateHeaderError();\n }\n\n let certificates: X509Certificate[];\n try {\n certificates = parseClientCertificateChain(pem);\n } catch {\n throw certificateHeaderError();\n }\n\n if (certificates.length !== 1 || !certificates[0]) {\n throw certificateHeaderError();\n }\n\n return {\n certificate: certificates[0],\n chain: [],\n };\n}\n\nfunction parseStructuredCertificateList(value: string): X509Certificate[] {\n assertHeaderLength(value);\n const items = value.split(',').map((item) => item.trim());\n if (items.length > MAX_CERTIFICATE_CHAIN_LENGTH || items.some((item) => item.length === 0)) {\n throw certificateHeaderError();\n }\n\n return items.map(parseStructuredCertificate);\n}\n\nfunction parseStructuredCertificate(value: string): X509Certificate {\n const match = STRUCTURED_BINARY_PATTERN.exec(value.trim());\n if (!match?.[1]) {\n throw certificateHeaderError();\n }\n\n try {\n const raw = base64ToArrayBuffer(match[1]);\n if (raw.byteLength === 0) {\n throw certificateHeaderError();\n }\n\n const certificate = new X509Certificate(raw);\n if (\n certificate.toString('base64').replace(/=+$/, '') !==\n match[1].replace(/=+$/, '')\n ) {\n throw certificateHeaderError();\n }\n\n return certificate;\n } catch {\n throw certificateHeaderError();\n }\n}\n\nfunction assertHeaderLength(value: string): void {\n if (value.length > MAX_CERTIFICATE_HEADER_LENGTH) {\n throw certificateHeaderError();\n }\n}\n\nfunction certificateHeaderError(): BadRequestError {\n return new BadRequestError('The forwarded client certificate header is malformed.');\n}\n"],"mappings":";;;;;;;;;;AAmBA,MAAMK,gCAAgC
|
|
1
|
+
{"version":3,"file":"client-certificate.mjs","names":["X509Certificate","BadRequestError","base64ToArrayBuffer","buildClientCertificateThumbprint","parseClientCertificateChain","MAX_CERTIFICATE_HEADER_LENGTH","MAX_CERTIFICATE_CHAIN_LENGTH","STRUCTURED_BINARY_PATTERN","extractClientCertificateEvidence","event","source","undefined","result","extractStandardEvidence","extractForwardedEvidence","thumbprint","certificate","leafHeader","headers","get","chainHeader","certificateHeaderError","assertHeaderLength","parseStructuredCertificate","chain","parseStructuredCertificateList","value","pem","includes","decodeURIComponent","replace","certificates","length","items","split","map","item","trim","some","match","exec","raw","byteLength","toString"],"sources":["../../../../src/adapters/http/request/client-certificate.ts"],"sourcesContent":["/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport '../../../core/client-certificate/reflect.ts';\nimport { X509Certificate } from '@peculiar/x509';\nimport { BadRequestError } from '@authup/errors';\nimport { base64ToArrayBuffer } from '@authup/kit';\nimport type { IAppEvent } from 'routup';\nimport type { ClientCertificateEvidence } from '../../../core/index.ts';\nimport {\n buildClientCertificateThumbprint,\n parseClientCertificateChain,\n} from '../../../core/index.ts';\nimport type { CertificateSource } from './types.ts';\n\nconst MAX_CERTIFICATE_HEADER_LENGTH = 128 * 1024;\nconst MAX_CERTIFICATE_CHAIN_LENGTH = 10;\nconst STRUCTURED_BINARY_PATTERN = /^:([A-Za-z0-9+/]*={0,2}):$/;\n\nexport async function extractClientCertificateEvidence(\n event: IAppEvent,\n source: CertificateSource,\n): Promise<ClientCertificateEvidence | undefined> {\n if (source === 'disabled') {\n return undefined;\n }\n\n let result: Omit<ClientCertificateEvidence, 'thumbprint'> | undefined;\n if (source === 'standard') {\n result = extractStandardEvidence(event);\n } else if (source === 'forwarded') {\n result = extractForwardedEvidence(event);\n } else {\n throw new BadRequestError('The client certificate source is not configured correctly.');\n }\n if (!result) {\n return undefined;\n }\n\n return {\n ...result,\n thumbprint: await buildClientCertificateThumbprint(result.certificate),\n };\n}\n\nfunction extractStandardEvidence(\n event: IAppEvent,\n): Omit<ClientCertificateEvidence, 'thumbprint'> | undefined {\n const leafHeader = event.headers.get('client-cert');\n const chainHeader = event.headers.get('client-cert-chain');\n\n if (!leafHeader) {\n if (chainHeader) {\n throw certificateHeaderError();\n }\n return undefined;\n }\n\n assertHeaderLength(leafHeader);\n const certificate = parseStructuredCertificate(leafHeader);\n const chain = chainHeader ? parseStructuredCertificateList(chainHeader) : [];\n\n return { certificate, chain };\n}\n\nfunction extractForwardedEvidence(\n event: IAppEvent,\n): Omit<ClientCertificateEvidence, 'thumbprint'> | undefined {\n const value = event.headers.get('x-forwarded-tls-client-cert');\n if (!value) {\n return undefined;\n }\n\n assertHeaderLength(value);\n\n let pem: string;\n try {\n // Native raw PEM is useful in tests and a few proxy integrations. The\n // NGINX/Traefik contract is escaped PEM: query-style `+` represents a\n // space, while literal base64 plus signs arrive as `%2B`.\n pem = value.includes('-----BEGIN CERTIFICATE-----') ?\n value :\n decodeURIComponent(value.replace(/\\+/g, '%20'));\n } catch {\n throw certificateHeaderError();\n }\n\n let certificates: X509Certificate[];\n try {\n certificates = parseClientCertificateChain(pem);\n } catch {\n throw certificateHeaderError();\n }\n\n if (certificates.length !== 1 || !certificates[0]) {\n throw certificateHeaderError();\n }\n\n return {\n certificate: certificates[0],\n chain: [],\n };\n}\n\nfunction parseStructuredCertificateList(value: string): X509Certificate[] {\n assertHeaderLength(value);\n const items = value.split(',').map((item) => item.trim());\n if (items.length > MAX_CERTIFICATE_CHAIN_LENGTH || items.some((item) => item.length === 0)) {\n throw certificateHeaderError();\n }\n\n return items.map(parseStructuredCertificate);\n}\n\nfunction parseStructuredCertificate(value: string): X509Certificate {\n const match = STRUCTURED_BINARY_PATTERN.exec(value.trim());\n if (!match?.[1]) {\n throw certificateHeaderError();\n }\n\n try {\n const raw = base64ToArrayBuffer(match[1]);\n if (raw.byteLength === 0) {\n throw certificateHeaderError();\n }\n\n const certificate = new X509Certificate(raw);\n if (\n certificate.toString('base64').replace(/=+$/, '') !==\n match[1].replace(/=+$/, '')\n ) {\n throw certificateHeaderError();\n }\n\n return certificate;\n } catch {\n throw certificateHeaderError();\n }\n}\n\nfunction assertHeaderLength(value: string): void {\n if (value.length > MAX_CERTIFICATE_HEADER_LENGTH) {\n throw certificateHeaderError();\n }\n}\n\nfunction certificateHeaderError(): BadRequestError {\n return new BadRequestError('The forwarded client certificate header is malformed.');\n}\n"],"mappings":";;;;;;;;;;AAmBA,MAAMK,gCAAgC;AACtC,MAAMC,+BAA+B;AACrC,MAAMC,4BAA4B;AAElC,eAAsBC,iCAClBC,OACAC,QAAyB;CAEzB,IAAIA,WAAW,YACX;CAGJ,IAAIE;CACJ,IAAIF,WAAW,YACXE,SAASC,wBAAwBJ,KAAAA;MAC9B,IAAIC,WAAW,aAClBE,SAASE,yBAAyBL,KAAAA;MAElC,MAAM,IAAIR,gBAAgB,4DAAA;CAE9B,IAAI,CAACW,QACD;CAGJ,OAAO;EACH,GAAGA;EACHG,YAAY,MAAMZ,iCAAiCS,OAAOI,WAAW;CACzE;AACJ;AAEA,SAASH,wBACLJ,OAAgB;CAEhB,MAAMQ,aAAaR,MAAMS,QAAQC,IAAI,aAAA;CACrC,MAAMC,cAAcX,MAAMS,QAAQC,IAAI,mBAAA;CAEtC,IAAI,CAACF,YAAY;EACb,IAAIG,aACA,MAAMC,uBAAAA;EAEV;CACJ;CAEAC,mBAAmBL,UAAAA;CAInB,OAAO;EAAED,aAHWO,2BAA2BN,UAGtCD;EAAaQ,OAFRJ,cAAcK,+BAA+BL,WAAAA,IAAe,CAAA;CAE9C;AAChC;AAEA,SAASN,yBACLL,OAAgB;CAEhB,MAAMiB,QAAQjB,MAAMS,QAAQC,IAAI,6BAAA;CAChC,IAAI,CAACO,OACD;CAGJJ,mBAAmBI,KAAAA;CAEnB,IAAIC;CACJ,IAAI;EAIAA,MAAMD,MAAME,SAAS,6BAAA,IACjBF,QACAG,mBAAmBH,MAAMI,QAAQ,OAAO,KAAA,CAAA;CAChD,QAAQ;EACJ,MAAMT,uBAAAA;CACV;CAEA,IAAIU;CACJ,IAAI;EACAA,eAAe3B,4BAA4BuB,GAAAA;CAC/C,QAAQ;EACJ,MAAMN,uBAAAA;CACV;CAEA,IAAIU,aAAaC,WAAW,KAAK,CAACD,aAAa,IAC3C,MAAMV,uBAAAA;CAGV,OAAO;EACHL,aAAae,aAAa;EAC1BP,OAAO,CAAA;CACX;AACJ;AAEA,SAASC,+BAA+BC,OAAa;CACjDJ,mBAAmBI,KAAAA;CACnB,MAAMO,QAAQP,MAAMQ,MAAM,GAAA,CAAA,CAAKC,KAAKC,SAASA,KAAKC,KAAI,CAAA;CACtD,IAAIJ,MAAMD,SAAS1B,gCAAgC2B,MAAMK,MAAMF,SAASA,KAAKJ,WAAW,CAAA,GACpF,MAAMX,uBAAAA;CAGV,OAAOY,MAAME,IAAIZ,0BAAAA;AACrB;AAEA,SAASA,2BAA2BG,OAAa;CAC7C,MAAMa,QAAQhC,0BAA0BiC,KAAKd,MAAMW,KAAI,CAAA;CACvD,IAAI,CAACE,QAAQ,IACT,MAAMlB,uBAAAA;CAGV,IAAI;EACA,MAAMoB,MAAMvC,oBAAoBqC,MAAM,EAAE;EACxC,IAAIE,IAAIC,eAAe,GACnB,MAAMrB,uBAAAA;EAGV,MAAML,cAAc,IAAIhB,gBAAgByC,GAAAA;EACxC,IACIzB,YAAY2B,SAAS,QAAA,CAAA,CAAUb,QAAQ,OAAO,EAAA,MAC9CS,MAAM,EAAE,CAACT,QAAQ,OAAO,EAAA,GAExB,MAAMT,uBAAAA;EAGV,OAAOL;CACX,QAAQ;EACJ,MAAMK,uBAAAA;CACV;AACJ;AAEA,SAASC,mBAAmBI,OAAa;CACrC,IAAIA,MAAMM,SAAS3B,+BACf,MAAMgB,uBAAAA;AAEd;AAEA,SAASA,yBAAAA;CACL,OAAO,IAAIpB,gBAAgB,uDAAA;AAC/B"}
|
|
@@ -19,9 +19,7 @@ async function readFromLocations(event, locations) {
|
|
|
19
19
|
case "params":
|
|
20
20
|
Object.assign(out, event.params);
|
|
21
21
|
break;
|
|
22
|
-
case "cookies":
|
|
23
|
-
Object.assign(out, useRequestCookies(event));
|
|
24
|
-
break;
|
|
22
|
+
case "cookies": Object.assign(out, useRequestCookies(event));
|
|
25
23
|
}
|
|
26
24
|
return out;
|
|
27
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locations.mjs","names":["readRequestBody","useRequestCookies","useRequestQuery","readFromLocations","event","locations","out","loc","body","Object","assign","params"],"sources":["../../../../../src/adapters/http/request/helpers/locations.ts"],"sourcesContent":["/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { IAppEvent } from 'routup';\nimport { readRequestBody } from '@routup/basic/body';\nimport { useRequestCookies } from '@routup/basic/cookie';\nimport { useRequestQuery } from '@routup/basic/query';\n\nexport type RequestDataLocation = 'body' | 'query' | 'params' | 'cookies';\n\nexport async function readFromLocations(\n event: IAppEvent,\n locations: RequestDataLocation[],\n): Promise<Record<string, any>> {\n const out: Record<string, any> = {};\n for (const loc of locations) {\n switch (loc) {\n case 'body': {\n const body = await readRequestBody(event);\n if (body && typeof body === 'object') {\n Object.assign(out, body);\n }\n break;\n }\n case 'query': {\n Object.assign(out, useRequestQuery(event));\n break;\n }\n case 'params': {\n Object.assign(out, event.params);\n break;\n }\n case 'cookies': {\n Object.assign(out, useRequestCookies(event));\n break;\n }\n }\n }\n return out;\n}\n"],"mappings":";;;;;;;AAcA,eAAsBG,kBAClBC,OACAC,WAAgC;CAEhC,MAAMC,MAA2B,CAAC;CAClC,KAAK,MAAMC,OAAOF,WACd,QAAQE,KAAR;EACI,KAAK,QAAQ;GACT,MAAMC,OAAO,MAAMR,gBAAgBI,KAAAA;GACnC,IAAII,QAAQ,OAAOA,SAAS,UACxBC,OAAOC,OAAOJ,KAAKE,IAAAA;GAEvB;EACJ;EACA,KAAK;GACDC,OAAOC,OAAOJ,KAAKJ,gBAAgBE,KAAAA,CAAAA;GACnC;EAEJ,KAAK;GACDK,OAAOC,OAAOJ,KAAKF,MAAMO,MAAM;GAC/B;EAEJ,KAAK
|
|
1
|
+
{"version":3,"file":"locations.mjs","names":["readRequestBody","useRequestCookies","useRequestQuery","readFromLocations","event","locations","out","loc","body","Object","assign","params"],"sources":["../../../../../src/adapters/http/request/helpers/locations.ts"],"sourcesContent":["/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { IAppEvent } from 'routup';\nimport { readRequestBody } from '@routup/basic/body';\nimport { useRequestCookies } from '@routup/basic/cookie';\nimport { useRequestQuery } from '@routup/basic/query';\n\nexport type RequestDataLocation = 'body' | 'query' | 'params' | 'cookies';\n\nexport async function readFromLocations(\n event: IAppEvent,\n locations: RequestDataLocation[],\n): Promise<Record<string, any>> {\n const out: Record<string, any> = {};\n for (const loc of locations) {\n switch (loc) {\n case 'body': {\n const body = await readRequestBody(event);\n if (body && typeof body === 'object') {\n Object.assign(out, body);\n }\n break;\n }\n case 'query': {\n Object.assign(out, useRequestQuery(event));\n break;\n }\n case 'params': {\n Object.assign(out, event.params);\n break;\n }\n case 'cookies': {\n Object.assign(out, useRequestCookies(event));\n break;\n }\n }\n }\n return out;\n}\n"],"mappings":";;;;;;;AAcA,eAAsBG,kBAClBC,OACAC,WAAgC;CAEhC,MAAMC,MAA2B,CAAC;CAClC,KAAK,MAAMC,OAAOF,WACd,QAAQE,KAAR;EACI,KAAK,QAAQ;GACT,MAAMC,OAAO,MAAMR,gBAAgBI,KAAAA;GACnC,IAAII,QAAQ,OAAOA,SAAS,UACxBC,OAAOC,OAAOJ,KAAKE,IAAAA;GAEvB;EACJ;EACA,KAAK;GACDC,OAAOC,OAAOJ,KAAKJ,gBAAgBE,KAAAA,CAAAA;GACnC;EAEJ,KAAK;GACDK,OAAOC,OAAOJ,KAAKF,MAAMO,MAAM;GAC/B;EAEJ,KAAK,WACDF,OAAOC,OAAOJ,KAAKL,kBAAkBG,KAAAA,CAAAA;CAG7C;CAEJ,OAAOE;AACX"}
|
|
@@ -27,15 +27,18 @@ var AuthenticationModule = class {
|
|
|
27
27
|
}
|
|
28
28
|
async setup(container) {
|
|
29
29
|
container.register(AuthenticationInjectionKey.SessionRepository, { useFactory: (c) => {
|
|
30
|
+
const cache = c.resolve(CacheInjectionKey);
|
|
31
|
+
const repository = c.resolve(SessionEntity);
|
|
30
32
|
return new SessionRepository({
|
|
31
|
-
cache
|
|
32
|
-
repository
|
|
33
|
+
cache,
|
|
34
|
+
repository
|
|
33
35
|
});
|
|
34
36
|
} });
|
|
35
37
|
container.register(AuthenticationInjectionKey.SessionManager, { useFactory: (c) => {
|
|
36
38
|
const config = c.resolve(ConfigInjectionKey);
|
|
39
|
+
const repository = c.resolve(AuthenticationInjectionKey.SessionRepository);
|
|
37
40
|
return new SessionManager({
|
|
38
|
-
repository
|
|
41
|
+
repository,
|
|
39
42
|
options: { maxAge: config.tokenRefreshMaxAge + 3600 }
|
|
40
43
|
});
|
|
41
44
|
} });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.mjs","names":["SessionEntity","SessionManager","CacheInjectionKey","ConfigInjectionKey","ModuleName","AuthenticationInjectionKey","SessionRepository","AuthenticationModule","name","dependencies","AUTHENTICATION","DATABASE","CACHE","CONFIG","setup","container","register","useFactory","c","cache","resolve","repository","config","options","maxAge","tokenRefreshMaxAge"],"sources":["../../../../src/app/modules/authentication/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { Session } from '@authup/core-kit';\nimport type { Repository } from 'typeorm';\nimport { SessionEntity } from '../../../adapters/database/domains/index.ts';\nimport type { IContainer } from 'eldin';\nimport { SessionManager } from '../../../core/index.ts';\nimport { CacheInjectionKey } from '../cache/index.ts';\nimport { ConfigInjectionKey } from '../config/index.ts';\n\nimport type { IModule } from 'orkos';\nimport { ModuleName } from '../constants.ts';\nimport { AuthenticationInjectionKey } from './constants.ts';\nimport { SessionRepository } from './repositories/index.ts';\n\nexport class AuthenticationModule implements IModule {\n readonly name: string;\n\n readonly dependencies: string[];\n\n constructor() {\n this.name = ModuleName.AUTHENTICATION;\n this.dependencies = [ModuleName.DATABASE, ModuleName.CACHE, ModuleName.CONFIG];\n }\n\n async setup(container: IContainer): Promise<void> {\n container.register(AuthenticationInjectionKey.SessionRepository, {\n useFactory: (c) => {\n const cache = c.resolve(CacheInjectionKey);\n const repository = c.resolve<Repository<Session>>(SessionEntity);\n return new SessionRepository({\n cache,\n repository,\n });\n },\n });\n\n container.register(AuthenticationInjectionKey.SessionManager, {\n useFactory: (c) => {\n const config = c.resolve(ConfigInjectionKey);\n const repository = c.resolve(AuthenticationInjectionKey.SessionRepository);\n return new SessionManager({\n repository,\n options: { maxAge: config.tokenRefreshMaxAge + 3_600 },\n });\n },\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAoBA,IAAaO,uBAAb,MAAaA;CACAC;CAEAC;CAET,cAAc;EACV,KAAKD,OAAOJ,WAAWM;EACvB,KAAKD,eAAe;GAACL,WAAWO;GAAUP,WAAWQ;GAAOR,WAAWS;EAAO;CAClF;CAEA,MAAMC,MAAMC,WAAsC;EAC9CA,UAAUC,SAASX,2BAA2BC,mBAAmB,EAC7DW,aAAaC,MAAAA;
|
|
1
|
+
{"version":3,"file":"module.mjs","names":["SessionEntity","SessionManager","CacheInjectionKey","ConfigInjectionKey","ModuleName","AuthenticationInjectionKey","SessionRepository","AuthenticationModule","name","dependencies","AUTHENTICATION","DATABASE","CACHE","CONFIG","setup","container","register","useFactory","c","cache","resolve","repository","config","options","maxAge","tokenRefreshMaxAge"],"sources":["../../../../src/app/modules/authentication/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { Session } from '@authup/core-kit';\nimport type { Repository } from 'typeorm';\nimport { SessionEntity } from '../../../adapters/database/domains/index.ts';\nimport type { IContainer } from 'eldin';\nimport { SessionManager } from '../../../core/index.ts';\nimport { CacheInjectionKey } from '../cache/index.ts';\nimport { ConfigInjectionKey } from '../config/index.ts';\n\nimport type { IModule } from 'orkos';\nimport { ModuleName } from '../constants.ts';\nimport { AuthenticationInjectionKey } from './constants.ts';\nimport { SessionRepository } from './repositories/index.ts';\n\nexport class AuthenticationModule implements IModule {\n readonly name: string;\n\n readonly dependencies: string[];\n\n constructor() {\n this.name = ModuleName.AUTHENTICATION;\n this.dependencies = [ModuleName.DATABASE, ModuleName.CACHE, ModuleName.CONFIG];\n }\n\n async setup(container: IContainer): Promise<void> {\n container.register(AuthenticationInjectionKey.SessionRepository, {\n useFactory: (c) => {\n const cache = c.resolve(CacheInjectionKey);\n const repository = c.resolve<Repository<Session>>(SessionEntity);\n return new SessionRepository({\n cache,\n repository,\n });\n },\n });\n\n container.register(AuthenticationInjectionKey.SessionManager, {\n useFactory: (c) => {\n const config = c.resolve(ConfigInjectionKey);\n const repository = c.resolve(AuthenticationInjectionKey.SessionRepository);\n return new SessionManager({\n repository,\n options: { maxAge: config.tokenRefreshMaxAge + 3_600 },\n });\n },\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAoBA,IAAaO,uBAAb,MAAaA;CACAC;CAEAC;CAET,cAAc;EACV,KAAKD,OAAOJ,WAAWM;EACvB,KAAKD,eAAe;GAACL,WAAWO;GAAUP,WAAWQ;GAAOR,WAAWS;EAAO;CAClF;CAEA,MAAMC,MAAMC,WAAsC;EAC9CA,UAAUC,SAASX,2BAA2BC,mBAAmB,EAC7DW,aAAaC,MAAAA;GACT,MAAMC,QAAQD,EAAEE,QAAQlB,iBAAAA;GACxB,MAAMmB,aAAaH,EAAEE,QAA6BpB,aAAAA;GAClD,OAAO,IAAIM,kBAAkB;IACzBa;IACAE;GACJ,CAAA;EACJ,EACJ,CAAA;EAEAN,UAAUC,SAASX,2BAA2BJ,gBAAgB,EAC1DgB,aAAaC,MAAAA;GACT,MAAMI,SAASJ,EAAEE,QAAQjB,kBAAAA;GACzB,MAAMkB,aAAaH,EAAEE,QAAQf,2BAA2BC,iBAAiB;GACzE,OAAO,IAAIL,eAAe;IACtBoB;IACAE,SAAS,EAAEC,QAAQF,OAAOG,qBAAqB,KAAM;GACzD,CAAA;EACJ,EACJ,CAAA;CACJ;AACJ"}
|
|
@@ -10,10 +10,11 @@ import "./read/index.mjs";
|
|
|
10
10
|
*
|
|
11
11
|
* @param options
|
|
12
12
|
*/ async function readConfig(options = {}) {
|
|
13
|
-
|
|
13
|
+
const raw = await readConfigRaw({
|
|
14
14
|
env: true,
|
|
15
15
|
...options
|
|
16
|
-
})
|
|
16
|
+
});
|
|
17
|
+
return normalizeConfig(raw);
|
|
17
18
|
}
|
|
18
19
|
//#endregion
|
|
19
20
|
export { readConfig };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.mjs","names":["normalizeConfig","readConfigRaw","readConfig","options","raw","env"],"sources":["../../../../src/app/modules/config/helpers.ts"],"sourcesContent":["/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { normalizeConfig } from './normalize.ts';\nimport type { ConfigRawReadOptions } from './read/index.ts';\nimport { readConfigRaw } from './read/index.ts';\nimport type { Config } from './types.ts';\n\n/**\n * Read config from env (and optionally fs) and normalize it.\n *\n * @param options\n */\nexport async function readConfig(options: ConfigRawReadOptions = {}) : Promise<Config> {\n const raw = await readConfigRaw({\n env: true,\n ...options,\n });\n\n return normalizeConfig(raw);\n}\n"],"mappings":";;;;;;;;;;;GAiBA,eAAsBE,WAAWC,UAAgC,CAAC,GAAC;
|
|
1
|
+
{"version":3,"file":"helpers.mjs","names":["normalizeConfig","readConfigRaw","readConfig","options","raw","env"],"sources":["../../../../src/app/modules/config/helpers.ts"],"sourcesContent":["/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { normalizeConfig } from './normalize.ts';\nimport type { ConfigRawReadOptions } from './read/index.ts';\nimport { readConfigRaw } from './read/index.ts';\nimport type { Config } from './types.ts';\n\n/**\n * Read config from env (and optionally fs) and normalize it.\n *\n * @param options\n */\nexport async function readConfig(options: ConfigRawReadOptions = {}) : Promise<Config> {\n const raw = await readConfigRaw({\n env: true,\n ...options,\n });\n\n return normalizeConfig(raw);\n}\n"],"mappings":";;;;;;;;;;;GAiBA,eAAsBE,WAAWC,UAAgC,CAAC,GAAC;CAC/D,MAAMC,MAAM,MAAMH,cAAc;EAC5BI,KAAK;EACL,GAAGF;CACP,CAAA;CAEA,OAAOH,gBAAgBI,GAAAA;AAC3B"}
|
|
@@ -7,10 +7,15 @@ import { merge } from "smob";
|
|
|
7
7
|
//#region src/app/modules/config/read/module.ts
|
|
8
8
|
async function readConfigRaw(options = {}) {
|
|
9
9
|
if (options.fs && options.env) {
|
|
10
|
-
const
|
|
11
|
-
|
|
10
|
+
const fsOptions = boolableToObject(options.fs);
|
|
11
|
+
const fs = await readConfigRawFromFS(fsOptions);
|
|
12
|
+
const env = readConfigRawFromEnv();
|
|
13
|
+
return merge(env, fs);
|
|
14
|
+
}
|
|
15
|
+
if (options.fs) {
|
|
16
|
+
const fsOptions = boolableToObject(options.fs);
|
|
17
|
+
return readConfigRawFromFS(fsOptions);
|
|
12
18
|
}
|
|
13
|
-
if (options.fs) return readConfigRawFromFS(boolableToObject(options.fs));
|
|
14
19
|
if (options.env) return readConfigRawFromEnv();
|
|
15
20
|
return {};
|
|
16
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.mjs","names":["merge","readConfigRawFromEnv","readConfigRawFromFS","readConfigRaw","options","fs","env","fsOptions","boolableToObject","input"],"sources":["../../../../../src/app/modules/config/read/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2024-2024.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { merge } from 'smob';\nimport type { ConfigInput } from '../types.ts';\nimport { readConfigRawFromEnv } from './env.ts';\nimport { readConfigRawFromFS } from './fs.ts';\nimport type { ConfigRawReadOptions } from './types.ts';\n\nexport async function readConfigRaw(options: ConfigRawReadOptions = {}) : Promise<ConfigInput> {\n if (options.fs && options.env) {\n const fsOptions = boolableToObject(options.fs);\n const fs = await readConfigRawFromFS(fsOptions);\n const env = readConfigRawFromEnv();\n\n return merge(env, fs);\n }\n\n if (options.fs) {\n const fsOptions = boolableToObject(options.fs);\n return readConfigRawFromFS(fsOptions);\n }\n\n if (options.env) {\n return readConfigRawFromEnv();\n }\n\n return {};\n}\n\nfunction boolableToObject<T>(input: T | boolean) : T {\n if (typeof input === 'boolean') {\n return {} as T;\n }\n\n return input;\n}\n"],"mappings":";;;;;;;AAaA,eAAsBG,cAAcC,UAAgC,CAAC,GAAC;CAClE,IAAIA,QAAQC,MAAMD,QAAQE,KAAK;
|
|
1
|
+
{"version":3,"file":"module.mjs","names":["merge","readConfigRawFromEnv","readConfigRawFromFS","readConfigRaw","options","fs","env","fsOptions","boolableToObject","input"],"sources":["../../../../../src/app/modules/config/read/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2024-2024.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { merge } from 'smob';\nimport type { ConfigInput } from '../types.ts';\nimport { readConfigRawFromEnv } from './env.ts';\nimport { readConfigRawFromFS } from './fs.ts';\nimport type { ConfigRawReadOptions } from './types.ts';\n\nexport async function readConfigRaw(options: ConfigRawReadOptions = {}) : Promise<ConfigInput> {\n if (options.fs && options.env) {\n const fsOptions = boolableToObject(options.fs);\n const fs = await readConfigRawFromFS(fsOptions);\n const env = readConfigRawFromEnv();\n\n return merge(env, fs);\n }\n\n if (options.fs) {\n const fsOptions = boolableToObject(options.fs);\n return readConfigRawFromFS(fsOptions);\n }\n\n if (options.env) {\n return readConfigRawFromEnv();\n }\n\n return {};\n}\n\nfunction boolableToObject<T>(input: T | boolean) : T {\n if (typeof input === 'boolean') {\n return {} as T;\n }\n\n return input;\n}\n"],"mappings":";;;;;;;AAaA,eAAsBG,cAAcC,UAAgC,CAAC,GAAC;CAClE,IAAIA,QAAQC,MAAMD,QAAQE,KAAK;EAC3B,MAAMC,YAAYC,iBAAiBJ,QAAQC,EAAE;EAC7C,MAAMA,KAAK,MAAMH,oBAAoBK,SAAAA;EACrC,MAAMD,MAAML,qBAAAA;EAEZ,OAAOD,MAAMM,KAAKD,EAAAA;CACtB;CAEA,IAAID,QAAQC,IAAI;EACZ,MAAME,YAAYC,iBAAiBJ,QAAQC,EAAE;EAC7C,OAAOH,oBAAoBK,SAAAA;CAC/B;CAEA,IAAIH,QAAQE,KACR,OAAOL,qBAAAA;CAGX,OAAO,CAAC;AACZ;AAEA,SAASO,iBAAoBC,OAAkB;CAC3C,IAAI,OAAOA,UAAU,WACjB,OAAO,CAAC;CAGZ,OAAOA;AACX"}
|
|
@@ -135,7 +135,8 @@ var DatabaseModule = class {
|
|
|
135
135
|
}
|
|
136
136
|
registerEventPublisher(container, dataSource) {
|
|
137
137
|
const config = container.resolve(ConfigInjectionKey);
|
|
138
|
-
const
|
|
138
|
+
const logger = container.resolve(LoggerInjectionKey);
|
|
139
|
+
const publisher = new DomainEventPublisher({ logger });
|
|
139
140
|
this.eventPublisher = publisher;
|
|
140
141
|
if (config.redis) {
|
|
141
142
|
const client = createRedisClient(config.redis);
|