@authup/server-core 1.0.0-beta.60 → 1.0.0-beta.62
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/domains/client-scope/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/client-scope/entity.mjs +16 -8
- package/dist/adapters/database/domains/client-scope/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/identity-provider-account/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/identity-provider-account/entity.mjs +1 -1
- package/dist/adapters/database/domains/identity-provider-account/entity.mjs.map +1 -1
- package/dist/adapters/database/migrations/mysql/1786631686318-SortIndexesAndAccountUniqueness.d.ts +50 -0
- package/dist/adapters/database/migrations/mysql/1786631686318-SortIndexesAndAccountUniqueness.d.ts.map +1 -0
- package/dist/adapters/database/migrations/mysql/1786631686318-SortIndexesAndAccountUniqueness.mjs +86 -0
- package/dist/adapters/database/migrations/mysql/1786631686318-SortIndexesAndAccountUniqueness.mjs.map +1 -0
- package/dist/adapters/database/migrations/postgres/1786631686318-SortIndexesAndAccountUniqueness.d.ts +42 -0
- package/dist/adapters/database/migrations/postgres/1786631686318-SortIndexesAndAccountUniqueness.d.ts.map +1 -0
- package/dist/adapters/database/migrations/postgres/1786631686318-SortIndexesAndAccountUniqueness.mjs +80 -0
- package/dist/adapters/database/migrations/postgres/1786631686318-SortIndexesAndAccountUniqueness.mjs.map +1 -0
- package/dist/adapters/http/adapters/oauth2/grant-types/utils/credentials.mjs +1 -1
- package/dist/adapters/http/adapters/oauth2/grant-types/utils/guess.mjs +1 -1
- package/dist/adapters/http/controllers/entities/client/module.mjs +2 -2
- package/dist/adapters/http/controllers/entities/identity-provider/module.d.ts +12 -8
- package/dist/adapters/http/controllers/entities/identity-provider/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/entities/identity-provider/module.mjs +137 -88
- package/dist/adapters/http/controllers/entities/identity-provider/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/entities/identity-provider/types.d.ts +7 -5
- package/dist/adapters/http/controllers/entities/identity-provider/types.d.ts.map +1 -1
- package/dist/adapters/http/controllers/entities/realm/module.mjs +2 -2
- package/dist/adapters/http/controllers/entities/session/module.mjs +2 -2
- package/dist/adapters/http/controllers/entities/user/module.mjs +2 -2
- package/dist/adapters/http/controllers/entities/user-authenticator/module.mjs +2 -2
- package/dist/adapters/http/controllers/workflows/authorize/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/workflows/authorize/module.mjs +9 -5
- package/dist/adapters/http/controllers/workflows/authorize/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/workflows/token/utils/extract.mjs +2 -1
- package/dist/adapters/http/controllers/workflows/token/utils/extract.mjs.map +1 -1
- package/dist/adapters/http/middleware/built-in/assets.mjs +1 -1
- package/dist/adapters/http/request/helpers/param-id.d.ts.map +1 -1
- package/dist/adapters/http/request/helpers/param-id.mjs +2 -1
- package/dist/adapters/http/request/helpers/param-id.mjs.map +1 -1
- package/dist/adapters/http/ui/account-console/module.mjs +1 -1
- package/dist/adapters/http/ui/auth-console/http-client.mjs +1 -1
- package/dist/adapters/http/ui/auth-console/module.mjs +1 -1
- package/dist/adapters/http/ui/console-packages/module.d.ts +1 -1
- package/dist/adapters/http/ui/console-packages/module.mjs +2 -2
- package/dist/adapters/http/ui/console-packages/module.mjs.map +1 -1
- package/dist/adapters/http/ui/shared/html.d.ts.map +1 -1
- package/dist/adapters/http/ui/shared/html.mjs +1 -0
- package/dist/adapters/http/ui/shared/html.mjs.map +1 -1
- package/dist/app/index.mjs +3 -1
- package/dist/app/modules/config/read/env.mjs +1 -1
- package/dist/app/modules/database/repositories/event/repository.d.ts +2 -2
- package/dist/app/modules/database/repositories/event/repository.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/event/repository.mjs +23 -6
- package/dist/app/modules/database/repositories/event/repository.mjs.map +1 -1
- package/dist/app/modules/database/repositories/identity-provider-account/repository.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/identity-provider-account/repository.mjs +9 -1
- package/dist/app/modules/database/repositories/identity-provider-account/repository.mjs.map +1 -1
- package/dist/app/modules/http/modules/controller.d.ts.map +1 -1
- package/dist/app/modules/http/modules/controller.mjs +18 -6
- package/dist/app/modules/http/modules/controller.mjs.map +1 -1
- package/dist/app/modules/identity/constants.d.ts +2 -1
- package/dist/app/modules/identity/constants.d.ts.map +1 -1
- package/dist/app/modules/identity/constants.mjs +1 -0
- package/dist/app/modules/identity/constants.mjs.map +1 -1
- package/dist/app/modules/identity/index.mjs +3 -1
- package/dist/app/modules/identity/module.d.ts.map +1 -1
- package/dist/app/modules/identity/module.mjs +13 -3
- package/dist/app/modules/identity/module.mjs.map +1 -1
- package/dist/app/modules/identity/repositories/constants.d.ts +4 -0
- package/dist/app/modules/identity/repositories/constants.d.ts.map +1 -0
- package/dist/app/modules/identity/repositories/constants.mjs +12 -0
- package/dist/app/modules/identity/repositories/constants.mjs.map +1 -0
- package/dist/app/modules/identity/repositories/index.d.ts +1 -0
- package/dist/app/modules/identity/repositories/index.d.ts.map +1 -1
- package/dist/app/modules/identity/repositories/index.mjs +3 -1
- package/dist/app/modules/identity/repositories/provider/index.d.ts +1 -0
- package/dist/app/modules/identity/repositories/provider/index.d.ts.map +1 -1
- package/dist/app/modules/identity/repositories/provider/index.mjs +2 -1
- package/dist/app/modules/identity/repositories/provider/link.d.ts +9 -0
- package/dist/app/modules/identity/repositories/provider/link.d.ts.map +1 -0
- package/dist/app/modules/identity/repositories/provider/link.mjs +34 -0
- package/dist/app/modules/identity/repositories/provider/link.mjs.map +1 -0
- package/dist/app/modules/identity/repositories/user.d.ts +1 -0
- package/dist/app/modules/identity/repositories/user.d.ts.map +1 -1
- package/dist/app/modules/identity/repositories/user.mjs +3 -0
- package/dist/app/modules/identity/repositories/user.mjs.map +1 -1
- package/dist/app/modules/index.mjs +3 -1
- package/dist/app/modules/oauth2/repositories/authorize/state/repository.d.ts +1 -2
- package/dist/app/modules/oauth2/repositories/authorize/state/repository.d.ts.map +1 -1
- package/dist/app/modules/oauth2/repositories/authorize/state/repository.mjs +7 -16
- package/dist/app/modules/oauth2/repositories/authorize/state/repository.mjs.map +1 -1
- package/dist/app/modules/runtime/module.mjs +2 -2
- package/dist/cli/commands/migration.mjs +1 -1
- package/dist/core/entities/client-scope/schema.d.ts.map +1 -1
- package/dist/core/entities/client-scope/schema.mjs +16 -1
- package/dist/core/entities/client-scope/schema.mjs.map +1 -1
- package/dist/core/entities/event/constants.d.ts +9 -0
- package/dist/core/entities/event/constants.d.ts.map +1 -1
- package/dist/core/entities/event/constants.mjs +9 -1
- package/dist/core/entities/event/constants.mjs.map +1 -1
- package/dist/core/entities/event/index.mjs +2 -2
- package/dist/core/entities/event/types.d.ts +11 -2
- package/dist/core/entities/event/types.d.ts.map +1 -1
- package/dist/core/entities/identity-provider-account/types.d.ts +6 -0
- package/dist/core/entities/identity-provider-account/types.d.ts.map +1 -1
- package/dist/core/entities/identity-provider-account/types.mjs.map +1 -1
- package/dist/core/entities/index.mjs +2 -2
- package/dist/core/identity/entities/user/types.d.ts +1 -0
- package/dist/core/identity/entities/user/types.d.ts.map +1 -1
- package/dist/core/identity/index.mjs +12 -11
- package/dist/core/identity/provider/account/constants.d.ts +10 -0
- package/dist/core/identity/provider/account/constants.d.ts.map +1 -0
- package/dist/core/identity/provider/account/constants.mjs +16 -0
- package/dist/core/identity/provider/account/constants.mjs.map +1 -0
- package/dist/core/identity/provider/account/index.d.ts +1 -0
- package/dist/core/identity/provider/account/index.d.ts.map +1 -1
- package/dist/core/identity/provider/account/index.mjs +2 -1
- package/dist/core/identity/provider/account/module.d.ts +3 -0
- package/dist/core/identity/provider/account/module.d.ts.map +1 -1
- package/dist/core/identity/provider/account/module.mjs +54 -27
- package/dist/core/identity/provider/account/module.mjs.map +1 -1
- package/dist/core/identity/provider/account/types.d.ts +42 -0
- package/dist/core/identity/provider/account/types.d.ts.map +1 -1
- package/dist/core/identity/provider/authentication/index.mjs +1 -1
- package/dist/core/identity/provider/authentication/protocols/oauth2/module.d.ts +18 -0
- package/dist/core/identity/provider/authentication/protocols/oauth2/module.d.ts.map +1 -1
- package/dist/core/identity/provider/authentication/protocols/oauth2/module.mjs +55 -2
- package/dist/core/identity/provider/authentication/protocols/oauth2/module.mjs.map +1 -1
- package/dist/core/identity/provider/authentication/protocols/oauth2/types.d.ts +2 -0
- package/dist/core/identity/provider/authentication/protocols/oauth2/types.d.ts.map +1 -1
- package/dist/core/identity/provider/authentication/protocols/open-id/module.d.ts +0 -3
- package/dist/core/identity/provider/authentication/protocols/open-id/module.d.ts.map +1 -1
- package/dist/core/identity/provider/authentication/protocols/open-id/module.mjs +0 -17
- package/dist/core/identity/provider/authentication/protocols/open-id/module.mjs.map +1 -1
- package/dist/core/identity/provider/index.mjs +12 -11
- package/dist/core/index.mjs +15 -12
- package/dist/core/oauth2/authorization/code-request/verifier/module.d.ts.map +1 -1
- package/dist/core/oauth2/authorization/code-request/verifier/module.mjs +9 -2
- package/dist/core/oauth2/authorization/code-request/verifier/module.mjs.map +1 -1
- package/dist/core/oauth2/authorization/state/module.mjs +1 -2
- package/dist/core/oauth2/authorization/state/module.mjs.map +1 -1
- package/dist/core/oauth2/authorization/state/types.d.ts +5 -2
- package/dist/core/oauth2/authorization/state/types.d.ts.map +1 -1
- package/dist/core/oauth2/end-session/service.d.ts.map +1 -1
- package/dist/core/oauth2/end-session/service.mjs +1 -0
- package/dist/core/oauth2/end-session/service.mjs.map +1 -1
- package/dist/core/oauth2/federated-login/index.d.ts +3 -0
- package/dist/core/oauth2/federated-login/index.d.ts.map +1 -0
- package/dist/core/oauth2/federated-login/index.mjs +6 -0
- package/dist/core/oauth2/federated-login/module.d.ts +20 -0
- package/dist/core/oauth2/federated-login/module.d.ts.map +1 -0
- package/dist/core/oauth2/federated-login/module.mjs +137 -0
- package/dist/core/oauth2/federated-login/module.mjs.map +1 -0
- package/dist/core/oauth2/federated-login/types.d.ts +138 -0
- package/dist/core/oauth2/federated-login/types.d.ts.map +1 -0
- package/dist/core/oauth2/federated-login/types.mjs +31 -0
- package/dist/core/oauth2/federated-login/types.mjs.map +1 -0
- package/dist/core/oauth2/index.d.ts +1 -0
- package/dist/core/oauth2/index.d.ts.map +1 -1
- package/dist/core/oauth2/index.mjs +4 -1
- package/dist/core/provisioning/entities/policy/validator.d.ts.map +1 -1
- package/dist/core/provisioning/entities/policy/validator.mjs +2 -1
- package/dist/core/provisioning/entities/policy/validator.mjs.map +1 -1
- package/dist/core/provisioning/entities/realm/wildcard-validator.d.ts.map +1 -1
- package/dist/core/provisioning/entities/realm/wildcard-validator.mjs +2 -1
- package/dist/core/provisioning/entities/realm/wildcard-validator.mjs.map +1 -1
- package/dist/core/security/policy/evaluator.mjs.map +1 -1
- package/dist/index.mjs +3 -1
- package/dist/node_modules/@ebec/core/dist/index.mjs +130 -0
- package/dist/node_modules/@ebec/core/dist/index.mjs.map +1 -0
- package/dist/swagger.json +146 -18
- package/dist/utils/error.d.ts.map +1 -1
- package/dist/utils/error.mjs +5 -6
- package/dist/utils/error.mjs.map +1 -1
- package/package.json +28 -28
|
@@ -3,13 +3,13 @@ import "node:url";
|
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { RECORD_QUERY_PARAMETERS, describeQuerySchema } from "../../../../../core/query/describe.mjs";
|
|
5
5
|
import { userAuthenticatorSchema } from "../../../../../core/entities/user-authenticator/schema.mjs";
|
|
6
|
+
import { isSelfToken } from "../../../../../utils/self-id.mjs";
|
|
7
|
+
import "../../../../../utils/index.mjs";
|
|
6
8
|
import "../../../../../core/index.mjs";
|
|
7
9
|
import { useRequestIdentity } from "../../../request/helpers/identity.mjs";
|
|
8
10
|
import { buildActorContext } from "../../../request/helpers/actor.mjs";
|
|
9
11
|
import "../../../request/index.mjs";
|
|
10
12
|
import { ForceLoggedInMiddleware } from "../../../middleware/built-in/loggedin/module.mjs";
|
|
11
|
-
import { isSelfToken } from "../../../../../utils/self-id.mjs";
|
|
12
|
-
import "../../../../../utils/index.mjs";
|
|
13
13
|
import "../../../middleware/index.mjs";
|
|
14
14
|
import { IdentityType } from "@authup/core-kit";
|
|
15
15
|
import { BadRequestError } from "@authup/errors";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../../src/adapters/http/controllers/workflows/authorize/module.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../../src/adapters/http/controllers/workflows/authorize/module.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAexC,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAGlE,OAAO,KAAK,EAAE,uCAAuC,EAAE,MAAM,8BAA8B,CAAC;AAC5F,OAAO,EAAE,uCAAuC,EAAE,MAAM,8BAA8B,CAAC;AACvF,OAAO,KAAK,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAMzF,qBACa,mBAAmB;IAI5B,SAAS,CAAC,OAAO,EAAE,0BAA0B,CAAC;IAE9C,SAAS,CAAC,mBAAmB,EAAG,uCAAuC,CAAC;IAExE,SAAS,CAAC,oBAAoB,EAAG,uCAAuC,CAAC;IAEzE,SAAS,CAAC,UAAU,EAAE,oBAAoB,CAAC;gBAI/B,GAAG,EAAE,0BAA0B;IAyBrC,OAAO,CAAa,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAmC/D,KAAK,CAAa,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;CAsG7D"}
|
|
@@ -2,18 +2,18 @@ import "node:path";
|
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { OAuth2AuthorizationCodeRequestValidator } from "../../../../../core/oauth2/authorization/code-request/validator.mjs";
|
|
5
|
+
import { sanitizeError } from "../../../../../utils/error.mjs";
|
|
6
|
+
import "../../../../../utils/index.mjs";
|
|
5
7
|
import "../../../../../core/index.mjs";
|
|
6
8
|
import { readFromLocations } from "../../../request/helpers/locations.mjs";
|
|
7
9
|
import "../../../request/index.mjs";
|
|
8
10
|
import { ForceUserLoggedInMiddleware } from "../../../middleware/built-in/loggedin/user.mjs";
|
|
9
11
|
import { renderAuthConsolePage } from "../../../ui/auth-console/module.mjs";
|
|
10
|
-
import { sanitizeError } from "../../../../../utils/error.mjs";
|
|
11
|
-
import "../../../../../utils/index.mjs";
|
|
12
12
|
import "../../../middleware/index.mjs";
|
|
13
13
|
import "../../../ui/index.mjs";
|
|
14
14
|
import { HTTPOAuth2Authorizer } from "../../../adapters/oauth2/authorization/module.mjs";
|
|
15
15
|
import "../../../adapters/index.mjs";
|
|
16
|
-
import { OAuth2AccessDeniedError, OAuth2ErrorCode, isOAuth2AccessDeniedError } from "@authup/specs";
|
|
16
|
+
import { OAuth2AccessDeniedError, OAuth2ErrorCode, OAuth2LoginRequiredError, isOAuth2AccessDeniedError } from "@authup/specs";
|
|
17
17
|
import { URL } from "node:url";
|
|
18
18
|
import { useRequestQuery } from "@routup/basic/query";
|
|
19
19
|
import { DContext, DController, DGet, DPost } from "@routup/decorators";
|
|
@@ -106,8 +106,12 @@ var AuthorizeController = class {
|
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
108
|
if (!error) {
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
const query = useRequestQuery(event);
|
|
110
|
+
let mapped;
|
|
111
|
+
if (query.error === OAuth2ErrorCode.ACCESS_DENIED) mapped = OAuth2AccessDeniedError.forClient();
|
|
112
|
+
else if (query.error === OAuth2ErrorCode.LOGIN_REQUIRED) mapped = OAuth2LoginRequiredError.providerUnavailable();
|
|
113
|
+
if (mapped) {
|
|
114
|
+
const normalized = sanitizeError(mapped);
|
|
111
115
|
error = {
|
|
112
116
|
...normalized,
|
|
113
117
|
message: normalized.message
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.mjs","names":["DContext","DController","DGet","DPost","URL","useRequestQuery","OAuth2AccessDeniedError","OAuth2ErrorCode","isOAuth2AccessDeniedError","ForceUserLoggedInMiddleware","HTTPOAuth2Authorizer","renderAuthConsolePage","readFromLocations","OAuth2AuthorizationCodeRequestValidator","sanitizeError","AuthorizeController","options","codeRequestVerifier","codeRequestValidator","authorizer","ctx","codeIssuer","sessionManager","eventService","metrics","promptLoginMaxAge","mfaFreshnessMaxAge","mfaChallengeProvider","accessPolicyEvaluator","consentService","logger","confirm","event","result","authorizeWithRequest","url","redirectUri","state","searchParams","set","authorizationCode","href","e","ACCESS_DENIED","serve","codeRequest","client","scopes","realm","redirectUriVerified","error","merged","data","run","verify","id","name","displayName","builtIn","createdAt","normalized","message","query","forClient","requestURL","request","payload","config","baseURL","features","requestPath","pathname","search"],"sources":["../../../../../../src/adapters/http/controllers/workflows/authorize/module.ts"],"sourcesContent":["/*\n * Copyright (c) 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 {\n DContext,\n DController,\n DGet,\n DPost,\n} from '@routup/decorators';\nimport { URL } from 'node:url';\n\nimport type { IAppEvent } from 'routup';\nimport { useRequestQuery } from '@routup/basic/query';\nimport type {\n Client,\n OAuth2AuthorizationCodeRequest,\n Realm,\n Scope,\n} from '@authup/core-kit';\nimport { OAuth2AccessDeniedError, OAuth2ErrorCode, isOAuth2AccessDeniedError } from '@authup/specs';\nimport { ForceUserLoggedInMiddleware } from '../../../middleware/index.ts';\nimport { HTTPOAuth2Authorizer } from '../../../adapters/index.ts';\nimport { renderAuthConsolePage } from '../../../ui/index.ts';\nimport { readFromLocations } from '../../../request/index.ts';\nimport type { IOAuth2AuthorizationCodeRequestVerifier } from '../../../../../core/index.ts';\nimport { OAuth2AuthorizationCodeRequestValidator } from '../../../../../core/index.ts';\nimport type { AuthorizeControllerContext, AuthorizeControllerOptions } from './types.ts';\nimport { sanitizeError } from '../../../../../utils/index.ts';\n\ntype RealmSummary = Pick<Realm, 'id' | 'name' | 'displayName'>;\ntype ClientSummary = Pick<Client, 'id' | 'name' | 'displayName' | 'builtIn' | 'createdAt'>;\n\n@DController('/authorize')\nexport class AuthorizeController {\n // todo: maybe /realms/<realm>/protocol/openid-connect/authorize\n // todo: maybe /realms/<realm>/[...]/authorize\n\n protected options: AuthorizeControllerOptions;\n\n protected codeRequestVerifier : IOAuth2AuthorizationCodeRequestVerifier;\n\n protected codeRequestValidator : OAuth2AuthorizationCodeRequestValidator;\n\n protected authorizer: HTTPOAuth2Authorizer;\n\n // ---------------------------------------------------------\n\n constructor(ctx: AuthorizeControllerContext) {\n this.options = ctx.options;\n\n this.codeRequestVerifier = ctx.codeRequestVerifier;\n\n this.codeRequestValidator = new OAuth2AuthorizationCodeRequestValidator();\n\n this.authorizer = new HTTPOAuth2Authorizer({\n codeRequestVerifier: this.codeRequestVerifier,\n codeIssuer: ctx.codeIssuer,\n sessionManager: ctx.sessionManager,\n eventService: ctx.eventService,\n metrics: ctx.metrics,\n promptLoginMaxAge: ctx.options.promptLoginMaxAge,\n mfaFreshnessMaxAge: ctx.options.mfaFreshnessMaxAge,\n mfaChallengeProvider: ctx.mfaChallengeProvider,\n accessPolicyEvaluator: ctx.accessPolicyEvaluator,\n consentService: ctx.consentService,\n logger: ctx.logger,\n });\n }\n\n // ---------------------------------------------------------\n\n @DPost('', [ForceUserLoggedInMiddleware])\n async confirm(@DContext() event: IAppEvent): Promise<{ url: string }> {\n try {\n const result = await this.authorizer.authorizeWithRequest(event);\n\n const url = new URL(result.redirectUri);\n if (result.state) {\n url.searchParams.set('state', result.state);\n }\n\n if (result.authorizationCode) {\n url.searchParams.set('code', result.authorizationCode);\n }\n\n return { url: url.href };\n } catch (e) {\n // Access-policy denial (plan 052): with a pattern-verified\n // redirect_uri the denial is answered as an error redirect\n // (RFC 6749 §4.1.2.1) — the kit navigates the returned url like\n // any success. Unverified → rethrow → 400 body → interactive\n // denial card.\n if (isOAuth2AccessDeniedError(e) && e.redirectUri) {\n const url = new URL(e.redirectUri);\n url.searchParams.set('error', OAuth2ErrorCode.ACCESS_DENIED);\n if (e.state) {\n url.searchParams.set('state', e.state);\n }\n\n return { url: url.href };\n }\n\n throw e;\n }\n }\n\n @DGet('', [])\n async serve(@DContext() event: IAppEvent): Promise<string> {\n let codeRequest : OAuth2AuthorizationCodeRequest | undefined;\n\n let client : ClientSummary | undefined;\n let scopes : Scope[] | undefined;\n\n // Target realm summary (the client's realm) — the UI names it in the\n // realm-mismatch notice. codeRequest.realm_id is only the id.\n let realm : RealmSummary | undefined;\n\n // Whether the request redirect_uri matched a registered client pattern —\n // the UI must not offer an automatic \"return to application\" redirect to\n // an unverified (pattern-less-client) redirect_uri.\n let redirectUriVerified = false;\n\n let error : Error | undefined;\n\n try {\n const merged = await readFromLocations(event, ['body', 'query']);\n const data = await this.codeRequestValidator.run(merged);\n\n const result = await this.codeRequestVerifier.verify(data);\n\n // Trim the client to a deliberate DTO before it reaches the\n // anonymous SSR hydration payload — never disclose redirect_uri\n // patterns (the trusted-origin set), grant_types, internal\n // base/root URLs, auth methods, or the secret storage flags to an\n // unauthenticated visitor. (ClientEntity.secret is additionally\n // select:false, so the secret is never loaded — but the DTO must not\n // rely on that alone: a future entity/query change could unset it.)\n client = {\n id: result.client.id,\n name: result.client.name,\n displayName: result.client.displayName,\n builtIn: result.client.builtIn,\n createdAt: result.client.createdAt,\n };\n scopes = result.scopes;\n redirectUriVerified = result.redirectUriVerified;\n\n if (result.client.realm) {\n realm = {\n id: result.client.realm.id,\n name: result.client.realm.name,\n displayName: result.client.realm.displayName,\n };\n }\n\n codeRequest = result.data;\n } catch (e) {\n const normalized = sanitizeError(e);\n error = {\n ...normalized,\n message: normalized.message,\n };\n }\n\n // A recognized `error` query param (the federated-IdP callback\n // redirects back here with error=access_denied on a policy denial)\n // is mapped onto the hydration payload's error — neutral message,\n // never attacker-controlled text.\n if (!error) {\n const query = useRequestQuery(event);\n if (query.error === OAuth2ErrorCode.ACCESS_DENIED) {\n const normalized = sanitizeError(OAuth2AccessDeniedError.forClient());\n error = {\n ...normalized,\n message: normalized.message,\n };\n }\n }\n\n // Path + query of the original request — the SSR page uses it as\n // the same-origin `redirect` parameter on register / password links\n // so those pages can lead back into this authorize request.\n const requestURL = new URL(event.request.url);\n\n return renderAuthConsolePage(event, {\n url: '/authorize',\n payload: {\n config: { baseURL: this.options.baseURL },\n data: {\n codeRequest,\n error,\n client,\n scopes,\n realm,\n redirectUriVerified,\n features: this.options.features,\n requestPath: `${requestURL.pathname}${requestURL.search}`,\n },\n },\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"module.mjs","names":["DContext","DController","DGet","DPost","URL","useRequestQuery","OAuth2AccessDeniedError","OAuth2ErrorCode","OAuth2LoginRequiredError","isOAuth2AccessDeniedError","ForceUserLoggedInMiddleware","HTTPOAuth2Authorizer","renderAuthConsolePage","readFromLocations","OAuth2AuthorizationCodeRequestValidator","sanitizeError","AuthorizeController","options","codeRequestVerifier","codeRequestValidator","authorizer","ctx","codeIssuer","sessionManager","eventService","metrics","promptLoginMaxAge","mfaFreshnessMaxAge","mfaChallengeProvider","accessPolicyEvaluator","consentService","logger","confirm","event","result","authorizeWithRequest","url","redirectUri","state","searchParams","set","authorizationCode","href","e","ACCESS_DENIED","serve","codeRequest","client","scopes","realm","redirectUriVerified","error","merged","data","run","verify","id","name","displayName","builtIn","createdAt","normalized","message","query","mapped","forClient","LOGIN_REQUIRED","providerUnavailable","requestURL","request","payload","config","baseURL","features","requestPath","pathname","search"],"sources":["../../../../../../src/adapters/http/controllers/workflows/authorize/module.ts"],"sourcesContent":["/*\n * Copyright (c) 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 {\n DContext,\n DController,\n DGet,\n DPost,\n} from '@routup/decorators';\nimport { URL } from 'node:url';\n\nimport type { IAppEvent } from 'routup';\nimport { useRequestQuery } from '@routup/basic/query';\nimport type {\n Client,\n OAuth2AuthorizationCodeRequest,\n Realm,\n Scope,\n} from '@authup/core-kit';\nimport {\n OAuth2AccessDeniedError,\n OAuth2ErrorCode,\n OAuth2LoginRequiredError,\n isOAuth2AccessDeniedError,\n} from '@authup/specs';\nimport { ForceUserLoggedInMiddleware } from '../../../middleware/index.ts';\nimport { HTTPOAuth2Authorizer } from '../../../adapters/index.ts';\nimport { renderAuthConsolePage } from '../../../ui/index.ts';\nimport { readFromLocations } from '../../../request/index.ts';\nimport type { IOAuth2AuthorizationCodeRequestVerifier } from '../../../../../core/index.ts';\nimport { OAuth2AuthorizationCodeRequestValidator } from '../../../../../core/index.ts';\nimport type { AuthorizeControllerContext, AuthorizeControllerOptions } from './types.ts';\nimport { sanitizeError } from '../../../../../utils/index.ts';\n\ntype RealmSummary = Pick<Realm, 'id' | 'name' | 'displayName'>;\ntype ClientSummary = Pick<Client, 'id' | 'name' | 'displayName' | 'builtIn' | 'createdAt'>;\n\n@DController('/authorize')\nexport class AuthorizeController {\n // todo: maybe /realms/<realm>/protocol/openid-connect/authorize\n // todo: maybe /realms/<realm>/[...]/authorize\n\n protected options: AuthorizeControllerOptions;\n\n protected codeRequestVerifier : IOAuth2AuthorizationCodeRequestVerifier;\n\n protected codeRequestValidator : OAuth2AuthorizationCodeRequestValidator;\n\n protected authorizer: HTTPOAuth2Authorizer;\n\n // ---------------------------------------------------------\n\n constructor(ctx: AuthorizeControllerContext) {\n this.options = ctx.options;\n\n this.codeRequestVerifier = ctx.codeRequestVerifier;\n\n this.codeRequestValidator = new OAuth2AuthorizationCodeRequestValidator();\n\n this.authorizer = new HTTPOAuth2Authorizer({\n codeRequestVerifier: this.codeRequestVerifier,\n codeIssuer: ctx.codeIssuer,\n sessionManager: ctx.sessionManager,\n eventService: ctx.eventService,\n metrics: ctx.metrics,\n promptLoginMaxAge: ctx.options.promptLoginMaxAge,\n mfaFreshnessMaxAge: ctx.options.mfaFreshnessMaxAge,\n mfaChallengeProvider: ctx.mfaChallengeProvider,\n accessPolicyEvaluator: ctx.accessPolicyEvaluator,\n consentService: ctx.consentService,\n logger: ctx.logger,\n });\n }\n\n // ---------------------------------------------------------\n\n @DPost('', [ForceUserLoggedInMiddleware])\n async confirm(@DContext() event: IAppEvent): Promise<{ url: string }> {\n try {\n const result = await this.authorizer.authorizeWithRequest(event);\n\n const url = new URL(result.redirectUri);\n if (result.state) {\n url.searchParams.set('state', result.state);\n }\n\n if (result.authorizationCode) {\n url.searchParams.set('code', result.authorizationCode);\n }\n\n return { url: url.href };\n } catch (e) {\n // Access-policy denial (plan 052): with a pattern-verified\n // redirect_uri the denial is answered as an error redirect\n // (RFC 6749 §4.1.2.1) — the kit navigates the returned url like\n // any success. Unverified → rethrow → 400 body → interactive\n // denial card.\n if (isOAuth2AccessDeniedError(e) && e.redirectUri) {\n const url = new URL(e.redirectUri);\n url.searchParams.set('error', OAuth2ErrorCode.ACCESS_DENIED);\n if (e.state) {\n url.searchParams.set('state', e.state);\n }\n\n return { url: url.href };\n }\n\n throw e;\n }\n }\n\n @DGet('', [])\n async serve(@DContext() event: IAppEvent): Promise<string> {\n let codeRequest : OAuth2AuthorizationCodeRequest | undefined;\n\n let client : ClientSummary | undefined;\n let scopes : Scope[] | undefined;\n\n // Target realm summary (the client's realm) — the UI names it in the\n // realm-mismatch notice. codeRequest.realm_id is only the id.\n let realm : RealmSummary | undefined;\n\n // Whether the request redirect_uri matched a registered client pattern —\n // the UI must not offer an automatic \"return to application\" redirect to\n // an unverified (pattern-less-client) redirect_uri.\n let redirectUriVerified = false;\n\n let error : Error | undefined;\n\n try {\n const merged = await readFromLocations(event, ['body', 'query']);\n const data = await this.codeRequestValidator.run(merged);\n\n const result = await this.codeRequestVerifier.verify(data);\n\n // Trim the client to a deliberate DTO before it reaches the\n // anonymous SSR hydration payload — never disclose redirect_uri\n // patterns (the trusted-origin set), grant_types, internal\n // base/root URLs, auth methods, or the secret storage flags to an\n // unauthenticated visitor. (ClientEntity.secret is additionally\n // select:false, so the secret is never loaded — but the DTO must not\n // rely on that alone: a future entity/query change could unset it.)\n client = {\n id: result.client.id,\n name: result.client.name,\n displayName: result.client.displayName,\n builtIn: result.client.builtIn,\n createdAt: result.client.createdAt,\n };\n scopes = result.scopes;\n redirectUriVerified = result.redirectUriVerified;\n\n if (result.client.realm) {\n realm = {\n id: result.client.realm.id,\n name: result.client.realm.name,\n displayName: result.client.realm.displayName,\n };\n }\n\n codeRequest = result.data;\n } catch (e) {\n const normalized = sanitizeError(e);\n error = {\n ...normalized,\n message: normalized.message,\n };\n }\n\n // A recognized `error` query param (the federated-IdP callback\n // redirects back here with one when it refuses a completion) is\n // mapped onto the hydration payload's error. The set stays closed and\n // the text is server-side and neutral, never attacker-controlled;\n // any other value is ignored.\n if (!error) {\n const query = useRequestQuery(event);\n let mapped : Error | undefined;\n if (query.error === OAuth2ErrorCode.ACCESS_DENIED) {\n mapped = OAuth2AccessDeniedError.forClient();\n } else if (query.error === OAuth2ErrorCode.LOGIN_REQUIRED) {\n mapped = OAuth2LoginRequiredError.providerUnavailable();\n }\n\n if (mapped) {\n const normalized = sanitizeError(mapped);\n error = {\n ...normalized,\n message: normalized.message,\n };\n }\n }\n\n // Path + query of the original request — the SSR page uses it as\n // the same-origin `redirect` parameter on register / password links\n // so those pages can lead back into this authorize request.\n const requestURL = new URL(event.request.url);\n\n return renderAuthConsolePage(event, {\n url: '/authorize',\n payload: {\n config: { baseURL: this.options.baseURL },\n data: {\n codeRequest,\n error,\n client,\n scopes,\n realm,\n redirectUriVerified,\n features: this.options.features,\n requestPath: `${requestURL.pathname}${requestURL.search}`,\n },\n },\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
+
import { defineIssueItem } from "../../../../../../node_modules/@ebec/core/dist/index.mjs";
|
|
4
5
|
import { readFromLocations } from "../../../../request/helpers/locations.mjs";
|
|
5
6
|
import { useRequestToken } from "../../../../request/helpers/token.mjs";
|
|
6
7
|
import "../../../../request/index.mjs";
|
|
7
8
|
import { TokenRequestValidator } from "./validator.mjs";
|
|
8
|
-
import { ValidupError, buildErrorMessageForAttribute,
|
|
9
|
+
import { ValidupError, buildErrorMessageForAttribute, isValidupError } from "validup";
|
|
9
10
|
//#region src/adapters/http/controllers/workflows/token/utils/extract.ts
|
|
10
11
|
async function extractTokenFromRequest(event) {
|
|
11
12
|
let token;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract.mjs","names":["ValidupError","buildErrorMessageForAttribute","
|
|
1
|
+
{"version":3,"file":"extract.mjs","names":["ValidupError","buildErrorMessageForAttribute","isValidupError","defineIssueItem","readFromLocations","useRequestToken","TokenRequestValidator","extractTokenFromRequest","event","token","validator","data","run","e","path","message"],"sources":["../../../../../../../src/adapters/http/controllers/workflows/token/utils/extract.ts"],"sourcesContent":["/*\n * Copyright (c) 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 type { IAppEvent } from 'routup';\nimport {\n ValidupError,\n buildErrorMessageForAttribute,\n isValidupError,\n} from 'validup';\nimport { defineIssueItem } from '@ebec/core';\nimport { readFromLocations, useRequestToken } from '../../../../request/index.ts';\nimport { TokenRequestValidator } from './validator.ts';\n\nexport async function extractTokenFromRequest(event: IAppEvent) : Promise<string> {\n let token : string | undefined;\n\n try {\n const validator = new TokenRequestValidator();\n const data = await validator.run(\n await readFromLocations(event, ['body', 'query', 'params']),\n );\n\n token = data.token;\n } catch (e) {\n if (!isValidupError(e)) {\n throw e;\n }\n token = useRequestToken(event);\n }\n\n if (!token) {\n throw new ValidupError([\n defineIssueItem({\n path: ['token'],\n message: buildErrorMessageForAttribute('token'),\n }),\n ]);\n }\n\n return token;\n}\n"],"mappings":";;;;;;;;;;AAiBA,eAAsBO,wBAAwBC,OAAgB;CAC1D,IAAIC;CAEJ,IAAI;EAMAA,SAAQE,MAJWD,IADGJ,sBACHI,CAAAA,CAAUE,IACzB,MAAMR,kBAAkBI,OAAO;GAAC;GAAQ;GAAS;EAAS,CAAA,CAAA,EAAA,CAGjDC;CACjB,SAASI,GAAG;EACR,IAAI,CAACX,eAAeW,CAAAA,GAChB,MAAMA;EAEVJ,QAAQJ,gBAAgBG,KAAAA;CAC5B;CAEA,IAAI,CAACC,OACD,MAAM,IAAIT,aAAa,CACnBG,gBAAgB;EACZW,MAAM,CAAC,OAAQ;EACfC,SAASd,8BAA8B,OAAA;CAC3C,CAAA,CACH,CAAA;CAGL,OAAOQ;AACX"}
|
|
@@ -12,9 +12,9 @@ import { registerThemeMiddleware } from "./theme.mjs";
|
|
|
12
12
|
import { resolveAccountConsoleDistPath } from "../../ui/account-console/module.mjs";
|
|
13
13
|
import "../../ui/account-console/index.mjs";
|
|
14
14
|
import { InternalError } from "@authup/errors";
|
|
15
|
+
import { CodeTransformation, isCodeTransformation } from "typeorm-extension";
|
|
15
16
|
import path from "node:path";
|
|
16
17
|
import { defineCoreHandler } from "routup";
|
|
17
|
-
import { CodeTransformation, isCodeTransformation } from "typeorm-extension";
|
|
18
18
|
import { fromNodeMiddleware } from "routup/node";
|
|
19
19
|
import { read } from "locter";
|
|
20
20
|
import fs from "node:fs";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"param-id.d.ts","sourceRoot":"","sources":["../../../../../src/adapters/http/request/helpers/param-id.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"param-id.d.ts","sourceRoot":"","sources":["../../../../../src/adapters/http/request/helpers/param-id.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAIxC,KAAK,qBAAqB,GAAG;IACzB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACnB,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,GAAE,qBAA0B,GAAI,MAAM,CAYhG;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,GAAE,qBAA0B,GAAI,MAAM,GAAG,SAAS,CAY5G;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAI,MAAM,GAAG,SAAS,CAOxF;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAI,MAAM,GAAG,SAAS,CAY9F"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
+
import { defineIssueItem } from "../../../../node_modules/@ebec/core/dist/index.mjs";
|
|
4
5
|
import { isUUID } from "@authup/kit";
|
|
5
|
-
import { ValidupError, buildErrorMessageForAttribute
|
|
6
|
+
import { ValidupError, buildErrorMessageForAttribute } from "validup";
|
|
6
7
|
//#region src/adapters/http/request/helpers/param-id.ts
|
|
7
8
|
function useRequestParamID(event, options = {}) {
|
|
8
9
|
const id = getRequestParamID(event, options);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"param-id.mjs","names":["isUUID","ValidupError","buildErrorMessageForAttribute","defineIssueItem","useRequestParamID","event","options","id","getRequestParamID","path","message","getRequestStringParam","undefined","key","value","params","length","getRequestStringParamOrFail"],"sources":["../../../../../src/adapters/http/request/helpers/param-id.ts"],"sourcesContent":["/*\n * Copyright (c) 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 { isUUID } from '@authup/kit';\nimport type { IAppEvent } from 'routup';\nimport { ValidupError, buildErrorMessageForAttribute
|
|
1
|
+
{"version":3,"file":"param-id.mjs","names":["isUUID","ValidupError","buildErrorMessageForAttribute","defineIssueItem","useRequestParamID","event","options","id","getRequestParamID","path","message","getRequestStringParam","undefined","key","value","params","length","getRequestStringParamOrFail"],"sources":["../../../../../src/adapters/http/request/helpers/param-id.ts"],"sourcesContent":["/*\n * Copyright (c) 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 { isUUID } from '@authup/kit';\nimport type { IAppEvent } from 'routup';\nimport { ValidupError, buildErrorMessageForAttribute } from 'validup';\nimport { defineIssueItem } from '@ebec/core';\n\ntype RequestIDParamOptions = {\n /**\n * default: true\n */\n isUUID?: boolean\n};\n\nexport function useRequestParamID(event: IAppEvent, options: RequestIDParamOptions = {}) : string {\n const id = getRequestParamID(event, options);\n if (typeof id === 'undefined') {\n throw new ValidupError([\n defineIssueItem({\n path: ['id'],\n message: buildErrorMessageForAttribute('id'),\n }),\n ]);\n }\n\n return id;\n}\n\nexport function getRequestParamID(event: IAppEvent, options: RequestIDParamOptions = {}) : string | undefined {\n const id = getRequestStringParam(event, 'id');\n if (!id) {\n return undefined;\n }\n\n options.isUUID = options.isUUID ?? true;\n if (options.isUUID && !isUUID(id)) {\n return undefined;\n }\n\n return id;\n}\n\nexport function getRequestStringParam(event: IAppEvent, key: string) : string | undefined {\n const value = event.params[key];\n if (typeof value !== 'string' || value.length === 0) {\n return undefined;\n }\n\n return value;\n}\n\nexport function getRequestStringParamOrFail(event: IAppEvent, key: string) : string | undefined {\n const value = getRequestStringParam(event, key);\n if (typeof value === 'undefined') {\n throw new ValidupError([\n defineIssueItem({\n path: [key],\n message: buildErrorMessageForAttribute(key),\n }),\n ]);\n }\n\n return value;\n}\n"],"mappings":";;;;;;;AAmBA,SAAgBI,kBAAkBC,OAAkBC,UAAiC,CAAC,GAAC;CACnF,MAAMC,KAAKC,kBAAkBH,OAAOC,OAAAA;CACpC,IAAI,OAAOC,OAAO,aACd,MAAM,IAAIN,aAAa,CACnBE,gBAAgB;EACZM,MAAM,CAAC,IAAK;EACZC,SAASR,8BAA8B,IAAA;CAC3C,CAAA,CACH,CAAA;CAGL,OAAOK;AACX;AAEA,SAAgBC,kBAAkBH,OAAkBC,UAAiC,CAAC,GAAC;CACnF,MAAMC,KAAKI,sBAAsBN,OAAO,IAAA;CACxC,IAAI,CAACE,IACD;CAGJD,QAAQN,SAASM,QAAQN,UAAU;CACnC,IAAIM,QAAQN,UAAU,CAACA,OAAOO,EAAAA,GAC1B;CAGJ,OAAOA;AACX;AAEA,SAAgBI,sBAAsBN,OAAkBQ,KAAW;CAC/D,MAAMC,QAAQT,MAAMU,OAAOF;CAC3B,IAAI,OAAOC,UAAU,YAAYA,MAAME,WAAW,GAC9C;CAGJ,OAAOF;AACX;AAEA,SAAgBG,4BAA4BZ,OAAkBQ,KAAW;CACrE,MAAMC,QAAQH,sBAAsBN,OAAOQ,GAAAA;CAC3C,IAAI,OAAOC,UAAU,aACjB,MAAM,IAAIb,aAAa,CACnBE,gBAAgB;EACZM,MAAM,CAACI,GAAI;EACXH,SAASR,8BAA8BW,GAAAA;CAC3C,CAAA,CACH,CAAA;CAGL,OAAOC;AACX"}
|
|
@@ -11,9 +11,9 @@ import "../../middleware/index.mjs";
|
|
|
11
11
|
import { resolveAccountConsoleRef } from "./ref.mjs";
|
|
12
12
|
import { getURLBasePath } from "@authup/kit";
|
|
13
13
|
import { InternalError } from "@authup/errors";
|
|
14
|
+
import { CodeTransformation, isCodeTransformation } from "typeorm-extension";
|
|
14
15
|
import path from "node:path";
|
|
15
16
|
import { useRequestQuery } from "@routup/basic/query";
|
|
16
|
-
import { CodeTransformation, isCodeTransformation } from "typeorm-extension";
|
|
17
17
|
import { locateUpSync } from "locter";
|
|
18
18
|
import fs from "node:fs";
|
|
19
19
|
//#region src/adapters/http/ui/account-console/module.ts
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
-
import { Client } from "@authup/core-http-kit";
|
|
5
4
|
import { FetchTransport, fetch } from "hapic";
|
|
5
|
+
import { Client } from "@authup/core-http-kit";
|
|
6
6
|
//#region src/adapters/http/ui/auth-console/http-client.ts
|
|
7
7
|
/**
|
|
8
8
|
* Build a rewriter that maps URLs under the public base URL
|
|
@@ -12,8 +12,8 @@ import { UI_HTTP_CLIENT_FACTORY_STORE_KEY } from "../../middleware/built-in/ui-h
|
|
|
12
12
|
import "../../middleware/index.mjs";
|
|
13
13
|
import { getURLBasePath } from "@authup/kit";
|
|
14
14
|
import { InternalError, isError } from "@authup/errors";
|
|
15
|
-
import path from "node:path";
|
|
16
15
|
import { CodeTransformation, isCodeTransformation } from "typeorm-extension";
|
|
16
|
+
import path from "node:path";
|
|
17
17
|
import { read } from "locter";
|
|
18
18
|
import fs from "node:fs";
|
|
19
19
|
//#region src/adapters/http/ui/auth-console/module.ts
|
|
@@ -6,7 +6,7 @@ import type { ConsolePackageOptions } from './types.ts';
|
|
|
6
6
|
* Bump alongside `apps/client-auth-console/src/contract.ts` whenever a
|
|
7
7
|
* change breaks a package built against the previous shape.
|
|
8
8
|
*/
|
|
9
|
-
export declare const AUTH_CONSOLE_CONTRACT_VERSION =
|
|
9
|
+
export declare const AUTH_CONSOLE_CONTRACT_VERSION = 2;
|
|
10
10
|
/**
|
|
11
11
|
* The marker the account console's index.html must carry. It is that
|
|
12
12
|
* console's entire runtime contract: without it the injected
|
|
@@ -16,7 +16,7 @@ import fs from "node:fs";
|
|
|
16
16
|
*
|
|
17
17
|
* Bump alongside `apps/client-auth-console/src/contract.ts` whenever a
|
|
18
18
|
* change breaks a package built against the previous shape.
|
|
19
|
-
*/ const AUTH_CONSOLE_CONTRACT_VERSION =
|
|
19
|
+
*/ const AUTH_CONSOLE_CONTRACT_VERSION = 2;
|
|
20
20
|
/**
|
|
21
21
|
* The marker the account console's index.html must carry. It is that
|
|
22
22
|
* console's entire runtime contract: without it the injected
|
|
@@ -56,7 +56,7 @@ async function assertAuthConsoleContract(packagePath) {
|
|
|
56
56
|
}
|
|
57
57
|
if (typeof module.render !== "function") throw new AuthupError(`The auth console bundle "${entry}" does not export a render() function.`);
|
|
58
58
|
const version = typeof module.CONTRACT_VERSION === "undefined" ? 1 : module.CONTRACT_VERSION;
|
|
59
|
-
if (version !==
|
|
59
|
+
if (version !== 2) throw new AuthupError(`The auth console package at "${packagePath}" implements render-contract version ${version}, but this authup requires 2. Rebuild it against the current @authup/client-auth-console contract.`);
|
|
60
60
|
}
|
|
61
61
|
function assertAccountConsoleContract(packagePath) {
|
|
62
62
|
const distPath = resolveAccountConsoleDistPath();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.mjs","names":["AuthupError","normalizeError","read","fs","path","resolveAccountConsoleDistPath","setAccountConsolePackagePath","resolveAuthConsoleDistPath","setAuthConsolePackagePath","AUTH_CONSOLE_CONTRACT_VERSION","AUTH_CONSOLE_CONTRACT_VERSION_IN_SYNC","ACCOUNT_CONSOLE_CONFIG_MARKER","bindConsolePackages","options","authConsolePath","accountConsolePath","assertAuthConsoleContract","assertAccountConsoleContract","packagePath","distPath","entry","join","module","e","reason","message","render","version","CONTRACT_VERSION","html","readFileSync","includes"],"sources":["../../../../../src/adapters/http/ui/console-packages/module.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 { AuthupError, normalizeError } from '@authup/errors';\nimport { read } from 'locter';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {\n resolveAccountConsoleDistPath,\n setAccountConsolePackagePath,\n} from '../account-console/index.ts';\nimport { resolveAuthConsoleDistPath, setAuthConsolePackagePath } from '../auth-console/index.ts';\n// Type position only (see AUTH_CONSOLE_CONTRACT_VERSION_IN_SYNC below), so\n// the runtime stays a dist-file read and the layering rule holds.\nimport type { CONTRACT_VERSION as AuthConsoleContractVersion } from '@authup/client-auth-console';\nimport type { ConsolePackageOptions } from './types.ts';\n\n/**\n * The render-contract version server-core compiles against. Must match the\n * `CONTRACT_VERSION` the auth console bundle exports.\n *\n * Bump alongside `apps/client-auth-console/src/contract.ts` whenever a\n * change breaks a package built against the previous shape.\n */\nexport const AUTH_CONSOLE_CONTRACT_VERSION =
|
|
1
|
+
{"version":3,"file":"module.mjs","names":["AuthupError","normalizeError","read","fs","path","resolveAccountConsoleDistPath","setAccountConsolePackagePath","resolveAuthConsoleDistPath","setAuthConsolePackagePath","AUTH_CONSOLE_CONTRACT_VERSION","AUTH_CONSOLE_CONTRACT_VERSION_IN_SYNC","ACCOUNT_CONSOLE_CONFIG_MARKER","bindConsolePackages","options","authConsolePath","accountConsolePath","assertAuthConsoleContract","assertAccountConsoleContract","packagePath","distPath","entry","join","module","e","reason","message","render","version","CONTRACT_VERSION","html","readFileSync","includes"],"sources":["../../../../../src/adapters/http/ui/console-packages/module.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 { AuthupError, normalizeError } from '@authup/errors';\nimport { read } from 'locter';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {\n resolveAccountConsoleDistPath,\n setAccountConsolePackagePath,\n} from '../account-console/index.ts';\nimport { resolveAuthConsoleDistPath, setAuthConsolePackagePath } from '../auth-console/index.ts';\n// Type position only (see AUTH_CONSOLE_CONTRACT_VERSION_IN_SYNC below), so\n// the runtime stays a dist-file read and the layering rule holds.\nimport type { CONTRACT_VERSION as AuthConsoleContractVersion } from '@authup/client-auth-console';\nimport type { ConsolePackageOptions } from './types.ts';\n\n/**\n * The render-contract version server-core compiles against. Must match the\n * `CONTRACT_VERSION` the auth console bundle exports.\n *\n * Bump alongside `apps/client-auth-console/src/contract.ts` whenever a\n * change breaks a package built against the previous shape.\n */\nexport const AUTH_CONSOLE_CONTRACT_VERSION = 2;\n\n/**\n * Compile-time link to the value this constant mirrors.\n *\n * The runtime assert below only fires for a SUBSTITUTED package, so a bump\n * on one side and not the other would otherwise go unnoticed until a\n * substituted console failed at boot in someone else's deployment. The\n * annotation costs nothing at runtime (types are erased) and fails this\n * package's build the moment the two drift.\n */\ntype AuthConsoleContractVersionInSync = typeof AuthConsoleContractVersion extends typeof AUTH_CONSOLE_CONTRACT_VERSION ?\n true :\n never;\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst AUTH_CONSOLE_CONTRACT_VERSION_IN_SYNC : AuthConsoleContractVersionInSync = true;\n\n/**\n * The marker the account console's index.html must carry. It is that\n * console's entire runtime contract: without it the injected\n * `window.__AUTHUP__` never lands and the SPA silently falls back to\n * deriving its API URL from the origin.\n */\nexport const ACCOUNT_CONSOLE_CONFIG_MARKER = '<!--account-config-->';\n\n/**\n * Bind the substituted console packages and verify they still fulfill the\n * contracts, before the first request rather than per render.\n *\n * Only runs for a package the operator actually substituted. With the\n * default resolution the console packages ship from this repo with linked\n * versions, so the assert would compare a constant against itself, and\n * loading the SSR bundle at boot would turn a missing build into a failed\n * start instead of an actionable error on the page.\n *\n * Fail-closed on a mismatch: the operator replaced the login and consent\n * IMPLEMENTATION (the prompt ladder, PKCE and state handling, MFA\n * ordering, redirect gating), so a contract drift must stop the container\n * rather than render subtly wrong auth pages.\n */\nexport async function bindConsolePackages(options: ConsolePackageOptions = {}) : Promise<void> {\n setAuthConsolePackagePath(options.authConsolePath);\n setAccountConsolePackagePath(options.accountConsolePath);\n\n if (options.authConsolePath) {\n await assertAuthConsoleContract(options.authConsolePath);\n }\n\n if (options.accountConsolePath) {\n assertAccountConsoleContract(options.accountConsolePath);\n }\n}\n\nasync function assertAuthConsoleContract(packagePath: string) : Promise<void> {\n const distPath = resolveAuthConsoleDistPath();\n if (!distPath) {\n throw new AuthupError(\n `The auth console package at \"${packagePath}\" carries no built bundle (expected dist/client/index.html).`,\n );\n }\n\n const entry = path.join(distPath, 'server', 'server.js');\n\n let module : Record<string, any>;\n try {\n module = await read(entry) as Record<string, any>;\n } catch (e) {\n const reason = normalizeError(e).message;\n\n throw new AuthupError(`The auth console render entry \"${entry}\" could not be loaded.\\n ${reason}`);\n }\n\n if (typeof module.render !== 'function') {\n throw new AuthupError(`The auth console bundle \"${entry}\" does not export a render() function.`);\n }\n\n // A bundle predating the export counts as version 1, the shape every\n // package built before the constant existed implements.\n const version = typeof module.CONTRACT_VERSION === 'undefined' ?\n 1 :\n module.CONTRACT_VERSION;\n\n if (version !== AUTH_CONSOLE_CONTRACT_VERSION) {\n throw new AuthupError(\n `The auth console package at \"${packagePath}\" implements render-contract version ${version}, but this authup requires ${AUTH_CONSOLE_CONTRACT_VERSION}. Rebuild it against the current @authup/client-auth-console contract.`,\n );\n }\n}\n\nfunction assertAccountConsoleContract(packagePath: string) : void {\n const distPath = resolveAccountConsoleDistPath();\n if (!distPath) {\n throw new AuthupError(\n `The account console package at \"${packagePath}\" carries no built bundle (expected dist/index.html).`,\n );\n }\n\n const entry = path.join(distPath, 'index.html');\n const html = fs.readFileSync(entry, 'utf-8');\n\n if (!html.includes(ACCOUNT_CONSOLE_CONFIG_MARKER)) {\n throw new AuthupError(\n `The account console shell \"${entry}\" carries no ${ACCOUNT_CONSOLE_CONFIG_MARKER} marker, so its runtime configuration cannot be injected.`,\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;GA4BA,MAAaS,gCAAgC;;;;;;GAuB7C,MAAaE,gCAAgC;;;;;;;;;;;;;;;GAiB7C,eAAsBC,oBAAoBC,UAAiC,CAAC,GAAC;CACzEL,0BAA0BK,QAAQC,eAAe;CACjDR,6BAA6BO,QAAQE,kBAAkB;CAEvD,IAAIF,QAAQC,iBACR,MAAME,0BAA0BH,QAAQC,eAAe;CAG3D,IAAID,QAAQE,oBACRE,6BAA6BJ,QAAQE,kBAAkB;AAE/D;AAEA,eAAeC,0BAA0BE,aAAmB;CACxD,MAAMC,WAAWZ,2BAAAA;CACjB,IAAI,CAACY,UACD,MAAM,IAAInB,YACN,gCAAgCkB,YAAY,6DAA6D;CAIjH,MAAME,QAAQhB,KAAKiB,KAAKF,UAAU,UAAU,WAAA;CAE5C,IAAIG;CACJ,IAAI;EACAA,SAAS,MAAMpB,KAAKkB,KAAAA;CACxB,SAASG,GAAG;EACR,MAAMC,SAASvB,eAAesB,CAAAA,CAAAA,CAAGE;EAEjC,MAAM,IAAIzB,YAAY,kCAAkCoB,MAAM,4BAA4BI,QAAQ;CACtG;CAEA,IAAI,OAAOF,OAAOI,WAAW,YACzB,MAAM,IAAI1B,YAAY,4BAA4BoB,MAAM,uCAAuC;CAKnG,MAAMO,UAAU,OAAOL,OAAOM,qBAAqB,cAC/C,IACAN,OAAOM;CAEX,IAAID,YAAAA,GACA,MAAM,IAAI3B,YACN,gCAAgCkB,YAAY,uCAAuCS,QAAQ,mGAAkI;AAGzO;AAEA,SAASV,6BAA6BC,aAAmB;CACrD,MAAMC,WAAWd,8BAAAA;CACjB,IAAI,CAACc,UACD,MAAM,IAAInB,YACN,mCAAmCkB,YAAY,sDAAsD;CAI7G,MAAME,QAAQhB,KAAKiB,KAAKF,UAAU,YAAA;CAGlC,IAAI,CAFShB,GAAG2B,aAAaV,OAAO,OAE/BS,CAAAA,CAAKE,SAAAA,uBAASpB,GACf,MAAM,IAAIX,YACN,8BAA8BoB,MAAM,eAAeT,8BAA8B,0DAA0D;AAGvJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../../../src/adapters/http/ui/shared/html.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAKxC,MAAM,MAAM,mBAAmB,GAAG;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,SAAS,GAAI,mBAAmB,CAK9E;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,mBAAmB,GAAI,MAAM,CAU3F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAI,MAAM,CAE1F;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAI,MAAM,CAWxE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAI,MAAM,CAEvE;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,GAAI,IAAI,
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../../../src/adapters/http/ui/shared/html.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAKxC,MAAM,MAAM,mBAAmB,GAAG;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,SAAS,GAAI,mBAAmB,CAK9E;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,mBAAmB,GAAI,MAAM,CAU3F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAI,MAAM,CAE1F;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAI,MAAM,CAWxE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAI,MAAM,CAEvE;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,GAAI,IAAI,CAW1D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAI,MAAM,CASzF;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAI,MAAM,CAMjE"}
|
|
@@ -77,6 +77,7 @@ const COLOR_MODE_COOKIE = "vc-color-mode";
|
|
|
77
77
|
event.response.headers.set("content-security-policy", "frame-ancestors 'none'");
|
|
78
78
|
event.response.headers.set("x-frame-options", "DENY");
|
|
79
79
|
event.response.headers.set("referrer-policy", "no-referrer");
|
|
80
|
+
event.response.headers.set("cache-control", "no-store");
|
|
80
81
|
}
|
|
81
82
|
/**
|
|
82
83
|
* Rewrite root-absolute asset references (script/link/preload tags emitted
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html.mjs","names":["useRequestCookie","LOCALE_COOKIE","COLOR_MODE_COOKIE","readUIClientPreferences","event","locale","colorMode","stampHtmlAttributes","html","preferences","htmlAttrs","test","replace","replaceTemplateMarker","marker","value","injectHeadContent","content","index","toLowerCase","indexOf","slice","stampDocumentTitle","title","applyUIPageHeaders","response","headers","set","rebaseAssetURLs","basePath","viteBase","RegExp","_match","attribute","serializeInlineScriptJSON","JSON","stringify"],"sources":["../../../../../src/adapters/http/ui/shared/html.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 { useRequestCookie } from '@routup/basic/cookie';\nimport type { IAppEvent } from 'routup';\nimport { LOCALE_COOKIE } from '../../request/helpers/locale.ts';\n\nconst COLOR_MODE_COOKIE = 'vc-color-mode';\n\nexport type UIClientPreferences = {\n locale?: string,\n colorMode?: string,\n};\n\n/**\n * Mirror @vuecs/nuxt's SSR plugins: resolve the shared cookies server-side\n * so the HTML shell already carries the `.dark`/`.light` class and lang\n * attribute (no flash) and the client app hydrates from the same values.\n * The cookies are shared between every console on the origin.\n */\nexport function readUIClientPreferences(event: IAppEvent) : UIClientPreferences {\n return {\n locale: useRequestCookie(event, LOCALE_COOKIE),\n colorMode: useRequestCookie(event, COLOR_MODE_COOKIE),\n };\n}\n\n/**\n * Stamp the resolved preferences onto the opening `<html>` tag. Matched by\n * pattern rather than an exact literal, so a reformatted tag / dev-mode\n * transformIndexHtml rewrite still gets the lang + color-mode attributes\n * (no silent FOUC).\n */\nexport function stampHtmlAttributes(html: string, preferences: UIClientPreferences) : string {\n let htmlAttrs = 'lang=\"en\"';\n if (preferences.locale && /^[a-zA-Z]{2,3}(-[a-zA-Z0-9]+)*$/.test(preferences.locale)) {\n htmlAttrs = `lang=\"${preferences.locale}\"`;\n }\n if (preferences.colorMode === 'dark' || preferences.colorMode === 'light') {\n htmlAttrs += ` class=\"${preferences.colorMode}\"`;\n }\n\n return html.replace(/<html\\b[^>]*>/i, () => `<html ${htmlAttrs}>`);\n}\n\n/**\n * Replace a template marker (`<!--app-html-->`, `<!--account-config-->`, ...)\n * with a rendered value.\n *\n * The replacement is passed as a FUNCTION on purpose. A string replacement\n * expands the `$&`, `` $` ``, `$'` and `$$` patterns, so a `$'` anywhere in\n * the value splices the template's own text back into the page. The values\n * spliced here carry raw request input (the SSR hydration payload reflects\n * query parameters), which made `?token=$'` return a page whose inline\n * payload script was no longer valid JavaScript. Escaping cannot prevent\n * this: the expansion happens after the value was built.\n */\nexport function replaceTemplateMarker(html: string, marker: string, value: string) : string {\n return html.replace(marker, () => value);\n}\n\n/**\n * Insert markup immediately before `</head>`.\n *\n * Deliberately not a template marker: injecting at the closing tag works\n * against console bundles that were built BEFORE this feature existed, so\n * server-core never silently loses theming when it runs against an older\n * console package. A shell without a `</head>` is returned unchanged.\n *\n * Function-replacement form for the same reason as replaceTemplateMarker.\n */\nexport function injectHeadContent(html: string, content: string) : string {\n if (!content) {\n return html;\n }\n\n const index = html.toLowerCase().indexOf('</head>');\n if (index === -1) {\n return html;\n }\n\n return html.slice(0, index) + content + html.slice(index);\n}\n\n/**\n * Replace the document title. The value must already be HTML-escaped by\n * the caller; matched by pattern so a reformatted tag still hits.\n */\nexport function stampDocumentTitle(html: string, title: string) : string {\n return html.replace(/<title\\b[^>]*>[\\s\\S]*?<\\/title>/i, () => `<title>${title}</title>`);\n}\n\n/**\n * Response headers every served console page shares.\n *\n * Clickjacking guard: the pages mutate state behind explicit clicks and\n * hydrate first-party session state, so framing them would make\n * click-gating defeatable via overlay attacks — deny embedding entirely\n * (iframe-based silent renew is therefore unsupported). The URLs routinely\n * carry sensitive query params (id_token_hint, code, redirect, state) —\n * never leak them via Referer.\n */\nexport function applyUIPageHeaders(event: IAppEvent) : void {\n event.response.headers.set('content-type', 'text/html; charset=utf-8');\n // The shell is stamped from the vc-locale / vc-color-mode cookies, so\n // it genuinely varies by them. It carried no Vary header at all.\n event.response.headers.set('vary', 'cookie');\n event.response.headers.set('content-security-policy', \"frame-ancestors 'none'\");\n event.response.headers.set('x-frame-options', 'DENY');\n event.response.headers.set('referrer-policy', 'no-referrer');\n}\n\n/**\n * Rewrite root-absolute asset references (script/link/preload tags emitted\n * with a fixed vite base, e.g. /public/ or /account/) so they carry the\n * path prefix under which authup is publicly served (e.g. /auth/public/...).\n * The reverse proxy is expected to strip the prefix before the request\n * reaches authup, so the assets middleware keeps serving at the fixed base.\n */\nexport function rebaseAssetURLs(html: string, basePath: string, viteBase: string) : string {\n if (!basePath) {\n return html;\n }\n\n return html.replace(\n new RegExp(`(src|href)=\"${viteBase.replace(/[.*+?^${}()|[\\]\\\\/]/g, '\\\\$&')}`, 'g'),\n (_match, attribute) => `${attribute}=\"${basePath}${viteBase}`,\n );\n}\n\n/**\n * Escape characters that would otherwise let a value break out of an inline\n * `<script>` context (`</script>`) or terminate the JS string literal via\n * the U+2028/U+2029 line separators. Every window-global config/payload a\n * console page inlines must pass through this — never rely on the VALUES\n * staying benign.\n */\nexport function serializeInlineScriptJSON(value: unknown) : string {\n return JSON.stringify(value)\n .replace(/</g, '\\\\u003c')\n .replace(/>/g, '\\\\u003e')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029');\n}\n"],"mappings":";;;;;;AAWA,MAAME,oBAAoB;;;;;;GAa1B,SAAgBC,wBAAwBC,OAAgB;CACpD,OAAO;EACHC,QAAQL,iBAAiBI,OAAOH,aAAAA;EAChCK,WAAWN,iBAAiBI,OAAOF,iBAAAA;CACvC;AACJ;;;;;;GAQA,SAAgBK,oBAAoBC,MAAcC,aAAgC;CAC9E,IAAIC,YAAY;CAChB,IAAID,YAAYJ,UAAU,kCAAkCM,KAAKF,YAAYJ,MAAM,GAC/EK,YAAY,SAASD,YAAYJ,OAAO;CAE5C,IAAII,YAAYH,cAAc,UAAUG,YAAYH,cAAc,SAC9DI,aAAa,WAAWD,YAAYH,UAAU;CAGlD,OAAOE,KAAKI,QAAQ,wBAAwB,SAASF,UAAU,EAAE;AACrE;;;;;;;;;;;;GAcA,SAAgBG,sBAAsBL,MAAcM,QAAgBC,OAAa;CAC7E,OAAOP,KAAKI,QAAQE,cAAcC,KAAAA;AACtC;;;;;;;;;;GAYA,SAAgBC,kBAAkBR,MAAcS,SAAe;CAC3D,IAAI,CAACA,SACD,OAAOT;CAGX,MAAMU,QAAQV,KAAKW,YAAW,CAAA,CAAGC,QAAQ,SAAA;CACzC,IAAIF,UAAU,IACV,OAAOV;CAGX,OAAOA,KAAKa,MAAM,GAAGH,KAAAA,IAASD,UAAUT,KAAKa,MAAMH,KAAAA;AACvD;;;;GAMA,SAAgBI,mBAAmBd,MAAce,OAAa;CAC1D,OAAOf,KAAKI,QAAQ,0CAA0C,UAAUW,MAAM,SAAS;AAC3F;;;;;;;;;;GAYA,SAAgBC,mBAAmBpB,OAAgB;CAC/CA,MAAMqB,SAASC,QAAQC,IAAI,gBAAgB,0BAAA;CAG3CvB,MAAMqB,SAASC,QAAQC,IAAI,QAAQ,QAAA;CACnCvB,MAAMqB,SAASC,QAAQC,IAAI,2BAA2B,wBAAA;CACtDvB,MAAMqB,SAASC,QAAQC,IAAI,mBAAmB,MAAA;CAC9CvB,MAAMqB,SAASC,QAAQC,IAAI,mBAAmB,aAAA;
|
|
1
|
+
{"version":3,"file":"html.mjs","names":["useRequestCookie","LOCALE_COOKIE","COLOR_MODE_COOKIE","readUIClientPreferences","event","locale","colorMode","stampHtmlAttributes","html","preferences","htmlAttrs","test","replace","replaceTemplateMarker","marker","value","injectHeadContent","content","index","toLowerCase","indexOf","slice","stampDocumentTitle","title","applyUIPageHeaders","response","headers","set","rebaseAssetURLs","basePath","viteBase","RegExp","_match","attribute","serializeInlineScriptJSON","JSON","stringify"],"sources":["../../../../../src/adapters/http/ui/shared/html.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 { useRequestCookie } from '@routup/basic/cookie';\nimport type { IAppEvent } from 'routup';\nimport { LOCALE_COOKIE } from '../../request/helpers/locale.ts';\n\nconst COLOR_MODE_COOKIE = 'vc-color-mode';\n\nexport type UIClientPreferences = {\n locale?: string,\n colorMode?: string,\n};\n\n/**\n * Mirror @vuecs/nuxt's SSR plugins: resolve the shared cookies server-side\n * so the HTML shell already carries the `.dark`/`.light` class and lang\n * attribute (no flash) and the client app hydrates from the same values.\n * The cookies are shared between every console on the origin.\n */\nexport function readUIClientPreferences(event: IAppEvent) : UIClientPreferences {\n return {\n locale: useRequestCookie(event, LOCALE_COOKIE),\n colorMode: useRequestCookie(event, COLOR_MODE_COOKIE),\n };\n}\n\n/**\n * Stamp the resolved preferences onto the opening `<html>` tag. Matched by\n * pattern rather than an exact literal, so a reformatted tag / dev-mode\n * transformIndexHtml rewrite still gets the lang + color-mode attributes\n * (no silent FOUC).\n */\nexport function stampHtmlAttributes(html: string, preferences: UIClientPreferences) : string {\n let htmlAttrs = 'lang=\"en\"';\n if (preferences.locale && /^[a-zA-Z]{2,3}(-[a-zA-Z0-9]+)*$/.test(preferences.locale)) {\n htmlAttrs = `lang=\"${preferences.locale}\"`;\n }\n if (preferences.colorMode === 'dark' || preferences.colorMode === 'light') {\n htmlAttrs += ` class=\"${preferences.colorMode}\"`;\n }\n\n return html.replace(/<html\\b[^>]*>/i, () => `<html ${htmlAttrs}>`);\n}\n\n/**\n * Replace a template marker (`<!--app-html-->`, `<!--account-config-->`, ...)\n * with a rendered value.\n *\n * The replacement is passed as a FUNCTION on purpose. A string replacement\n * expands the `$&`, `` $` ``, `$'` and `$$` patterns, so a `$'` anywhere in\n * the value splices the template's own text back into the page. The values\n * spliced here carry raw request input (the SSR hydration payload reflects\n * query parameters), which made `?token=$'` return a page whose inline\n * payload script was no longer valid JavaScript. Escaping cannot prevent\n * this: the expansion happens after the value was built.\n */\nexport function replaceTemplateMarker(html: string, marker: string, value: string) : string {\n return html.replace(marker, () => value);\n}\n\n/**\n * Insert markup immediately before `</head>`.\n *\n * Deliberately not a template marker: injecting at the closing tag works\n * against console bundles that were built BEFORE this feature existed, so\n * server-core never silently loses theming when it runs against an older\n * console package. A shell without a `</head>` is returned unchanged.\n *\n * Function-replacement form for the same reason as replaceTemplateMarker.\n */\nexport function injectHeadContent(html: string, content: string) : string {\n if (!content) {\n return html;\n }\n\n const index = html.toLowerCase().indexOf('</head>');\n if (index === -1) {\n return html;\n }\n\n return html.slice(0, index) + content + html.slice(index);\n}\n\n/**\n * Replace the document title. The value must already be HTML-escaped by\n * the caller; matched by pattern so a reformatted tag still hits.\n */\nexport function stampDocumentTitle(html: string, title: string) : string {\n return html.replace(/<title\\b[^>]*>[\\s\\S]*?<\\/title>/i, () => `<title>${title}</title>`);\n}\n\n/**\n * Response headers every served console page shares.\n *\n * Clickjacking guard: the pages mutate state behind explicit clicks and\n * hydrate first-party session state, so framing them would make\n * click-gating defeatable via overlay attacks — deny embedding entirely\n * (iframe-based silent renew is therefore unsupported). The URLs routinely\n * carry sensitive query params (id_token_hint, code, redirect, state) —\n * never leak them via Referer.\n */\nexport function applyUIPageHeaders(event: IAppEvent) : void {\n event.response.headers.set('content-type', 'text/html; charset=utf-8');\n // The shell is stamped from the vc-locale / vc-color-mode cookies, so\n // it genuinely varies by them. It carried no Vary header at all.\n event.response.headers.set('vary', 'cookie');\n event.response.headers.set('content-security-policy', \"frame-ancestors 'none'\");\n event.response.headers.set('x-frame-options', 'DENY');\n event.response.headers.set('referrer-policy', 'no-referrer');\n // Login pages, and the federated callback's interstitial carries a\n // fresh authorization code in its payload.\n event.response.headers.set('cache-control', 'no-store');\n}\n\n/**\n * Rewrite root-absolute asset references (script/link/preload tags emitted\n * with a fixed vite base, e.g. /public/ or /account/) so they carry the\n * path prefix under which authup is publicly served (e.g. /auth/public/...).\n * The reverse proxy is expected to strip the prefix before the request\n * reaches authup, so the assets middleware keeps serving at the fixed base.\n */\nexport function rebaseAssetURLs(html: string, basePath: string, viteBase: string) : string {\n if (!basePath) {\n return html;\n }\n\n return html.replace(\n new RegExp(`(src|href)=\"${viteBase.replace(/[.*+?^${}()|[\\]\\\\/]/g, '\\\\$&')}`, 'g'),\n (_match, attribute) => `${attribute}=\"${basePath}${viteBase}`,\n );\n}\n\n/**\n * Escape characters that would otherwise let a value break out of an inline\n * `<script>` context (`</script>`) or terminate the JS string literal via\n * the U+2028/U+2029 line separators. Every window-global config/payload a\n * console page inlines must pass through this — never rely on the VALUES\n * staying benign.\n */\nexport function serializeInlineScriptJSON(value: unknown) : string {\n return JSON.stringify(value)\n .replace(/</g, '\\\\u003c')\n .replace(/>/g, '\\\\u003e')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029');\n}\n"],"mappings":";;;;;;AAWA,MAAME,oBAAoB;;;;;;GAa1B,SAAgBC,wBAAwBC,OAAgB;CACpD,OAAO;EACHC,QAAQL,iBAAiBI,OAAOH,aAAAA;EAChCK,WAAWN,iBAAiBI,OAAOF,iBAAAA;CACvC;AACJ;;;;;;GAQA,SAAgBK,oBAAoBC,MAAcC,aAAgC;CAC9E,IAAIC,YAAY;CAChB,IAAID,YAAYJ,UAAU,kCAAkCM,KAAKF,YAAYJ,MAAM,GAC/EK,YAAY,SAASD,YAAYJ,OAAO;CAE5C,IAAII,YAAYH,cAAc,UAAUG,YAAYH,cAAc,SAC9DI,aAAa,WAAWD,YAAYH,UAAU;CAGlD,OAAOE,KAAKI,QAAQ,wBAAwB,SAASF,UAAU,EAAE;AACrE;;;;;;;;;;;;GAcA,SAAgBG,sBAAsBL,MAAcM,QAAgBC,OAAa;CAC7E,OAAOP,KAAKI,QAAQE,cAAcC,KAAAA;AACtC;;;;;;;;;;GAYA,SAAgBC,kBAAkBR,MAAcS,SAAe;CAC3D,IAAI,CAACA,SACD,OAAOT;CAGX,MAAMU,QAAQV,KAAKW,YAAW,CAAA,CAAGC,QAAQ,SAAA;CACzC,IAAIF,UAAU,IACV,OAAOV;CAGX,OAAOA,KAAKa,MAAM,GAAGH,KAAAA,IAASD,UAAUT,KAAKa,MAAMH,KAAAA;AACvD;;;;GAMA,SAAgBI,mBAAmBd,MAAce,OAAa;CAC1D,OAAOf,KAAKI,QAAQ,0CAA0C,UAAUW,MAAM,SAAS;AAC3F;;;;;;;;;;GAYA,SAAgBC,mBAAmBpB,OAAgB;CAC/CA,MAAMqB,SAASC,QAAQC,IAAI,gBAAgB,0BAAA;CAG3CvB,MAAMqB,SAASC,QAAQC,IAAI,QAAQ,QAAA;CACnCvB,MAAMqB,SAASC,QAAQC,IAAI,2BAA2B,wBAAA;CACtDvB,MAAMqB,SAASC,QAAQC,IAAI,mBAAmB,MAAA;CAC9CvB,MAAMqB,SAASC,QAAQC,IAAI,mBAAmB,aAAA;CAG9CvB,MAAMqB,SAASC,QAAQC,IAAI,iBAAiB,UAAA;AAChD;;;;;;;GASA,SAAgBC,gBAAgBpB,MAAcqB,UAAkBC,UAAgB;CAC5E,IAAI,CAACD,UACD,OAAOrB;CAGX,OAAOA,KAAKI,QACR,IAAImB,OAAO,eAAeD,SAASlB,QAAQ,wBAAwB,MAAA,KAAW,GAAA,IAC7EoB,QAAQC,cAAc,GAAGA,UAAU,IAAIJ,WAAWC,UAAU;AAErE;;;;;;;GASA,SAAgBI,0BAA0BnB,OAAc;CACpD,OAAOoB,KAAKC,UAAUrB,KAAAA,CAAAA,CACjBH,QAAQ,MAAM,SAAA,CAAA,CACdA,QAAQ,MAAM,SAAA,CAAA,CACdA,QAAQ,WAAW,SAAA,CAAA,CACnBA,QAAQ,WAAW,SAAA;AAC5B"}
|
package/dist/app/index.mjs
CHANGED
|
@@ -51,6 +51,8 @@ import { IdentityInjectionKey } from "./modules/identity/constants.mjs";
|
|
|
51
51
|
import { IdentityProviderAttributeMappingRepository } from "./modules/identity/repositories/provider/mapper/attribute.mjs";
|
|
52
52
|
import { IdentityProviderPermissionMappingRepository } from "./modules/identity/repositories/provider/mapper/permission.mjs";
|
|
53
53
|
import { IdentityProviderRoleMappingRepository } from "./modules/identity/repositories/provider/mapper/role.mjs";
|
|
54
|
+
import { CacheIdentityPrefix } from "./modules/identity/repositories/constants.mjs";
|
|
55
|
+
import { IdentityProviderAccountLinkStore } from "./modules/identity/repositories/provider/link.mjs";
|
|
54
56
|
import { ClientIdentityRepository } from "./modules/identity/repositories/client.mjs";
|
|
55
57
|
import { UserIdentityRepository } from "./modules/identity/repositories/user.mjs";
|
|
56
58
|
import { LDAPInjectionKey } from "./modules/ldap/constants.mjs";
|
|
@@ -70,4 +72,4 @@ import { RuntimeModule } from "./modules/runtime/module.mjs";
|
|
|
70
72
|
import "./modules/index.mjs";
|
|
71
73
|
import { ApplicationBuilder } from "./builder.mjs";
|
|
72
74
|
import { createApplication } from "./factory.mjs";
|
|
73
|
-
export { ApplicationBuilder, AuthenticationInjectionKey, AuthenticationModule, CacheInjectionKey, CacheModule, ClientIdentityRepository, ClientPermissionRepositoryAdapter, ClientRepositoryAdapter, ClientRoleRepositoryAdapter, ClientScopeRepositoryAdapter, ComponentsModule, CompositeProvisioningSource, ConfigEnvironmentVariableName, ConfigInjectionKey, ConfigModule, DatabaseInjectionKey, DatabaseModule, DefaultProvisioningSource, EventRepositoryAdapter, FileProvisioningSource, HTTPInjectionKey, HTTPModule, IdentityInjectionKey, IdentityModule, IdentityProviderAccountRepositoryAdapter, IdentityProviderAttributeMappingRepository, IdentityProviderPermissionMappingRepository, IdentityProviderRepositoryAdapter, IdentityProviderRoleMappingRepository, IdentityProviderRoleMappingRepositoryAdapter, KeyRepositoryAdapter, LDAPInjectionKey, LazyWildcardRealmProvisioner, LdapModule, LoggerInjectionKey, LoggerModule, MailInjectionKey, MailModule, MailTemplateRendererInjectionKey, MetricsInjectionKey, ModuleName, OAuth2InjectionToken, OAuth2Module, PermissionDatabaseProvider, PermissionPolicyRepositoryAdapter, PermissionRepositoryAdapter, PolicyRepositoryAdapter, PromAuthFlowMetrics, ProvisionerModule, ProvisioningInjectionKey, RealmRepositoryAdapter, RoleAttributeRepositoryAdapter, RolePermissionRepositoryAdapter, RoleRepositoryAdapter, RuntimeModule, ScopeRepositoryAdapter, SessionRepository, TrustAnchorRepositoryAdapter, UserAttributeRepositoryAdapter, UserAuthenticatorRepositoryAdapter, UserIdentityRepository, UserPermissionRepositoryAdapter, UserRepositoryAdapter, UserRoleRepositoryAdapter, createApplication, expandToOrigins, getAppOrigins, readConfig, readConfigRaw, readConfigRawFromEnv, readConfigRawFromFS };
|
|
75
|
+
export { ApplicationBuilder, AuthenticationInjectionKey, AuthenticationModule, CacheIdentityPrefix, CacheInjectionKey, CacheModule, ClientIdentityRepository, ClientPermissionRepositoryAdapter, ClientRepositoryAdapter, ClientRoleRepositoryAdapter, ClientScopeRepositoryAdapter, ComponentsModule, CompositeProvisioningSource, ConfigEnvironmentVariableName, ConfigInjectionKey, ConfigModule, DatabaseInjectionKey, DatabaseModule, DefaultProvisioningSource, EventRepositoryAdapter, FileProvisioningSource, HTTPInjectionKey, HTTPModule, IdentityInjectionKey, IdentityModule, IdentityProviderAccountLinkStore, IdentityProviderAccountRepositoryAdapter, IdentityProviderAttributeMappingRepository, IdentityProviderPermissionMappingRepository, IdentityProviderRepositoryAdapter, IdentityProviderRoleMappingRepository, IdentityProviderRoleMappingRepositoryAdapter, KeyRepositoryAdapter, LDAPInjectionKey, LazyWildcardRealmProvisioner, LdapModule, LoggerInjectionKey, LoggerModule, MailInjectionKey, MailModule, MailTemplateRendererInjectionKey, MetricsInjectionKey, ModuleName, OAuth2InjectionToken, OAuth2Module, PermissionDatabaseProvider, PermissionPolicyRepositoryAdapter, PermissionRepositoryAdapter, PolicyRepositoryAdapter, PromAuthFlowMetrics, ProvisionerModule, ProvisioningInjectionKey, RealmRepositoryAdapter, RoleAttributeRepositoryAdapter, RolePermissionRepositoryAdapter, RoleRepositoryAdapter, RuntimeModule, ScopeRepositoryAdapter, SessionRepository, TrustAnchorRepositoryAdapter, UserAttributeRepositoryAdapter, UserAuthenticatorRepositoryAdapter, UserIdentityRepository, UserPermissionRepositoryAdapter, UserRepositoryAdapter, UserRoleRepositoryAdapter, createApplication, expandToOrigins, getAppOrigins, readConfig, readConfigRaw, readConfigRawFromEnv, readConfigRawFromFS };
|
|
@@ -2,8 +2,8 @@ import "node:path";
|
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { ConfigEnvironmentVariableName } from "../constants.mjs";
|
|
5
|
-
import { oneOf, read, readArray, readBool, readInt } from "envix";
|
|
6
5
|
import { hasEnvDataSourceOptions, readDataSourceOptionsFromEnv } from "typeorm-extension";
|
|
6
|
+
import { oneOf, read, readArray, readBool, readInt } from "envix";
|
|
7
7
|
//#region src/app/modules/config/read/env.ts
|
|
8
8
|
const BOOLEAN_TRUE_VALUES = /* @__PURE__ */ new Set([
|
|
9
9
|
"true",
|
|
@@ -2,7 +2,7 @@ import type { Event } from '@authup/core-kit';
|
|
|
2
2
|
import type { IQuery } from '@rapiq/core';
|
|
3
3
|
import type { Repository } from 'typeorm';
|
|
4
4
|
import type { EntityRepositoryFindManyResult } from '@authup/server-kit';
|
|
5
|
-
import type { EventCountRecentFilter, EventFindManyOptions, IEventRepository } from '../../../../../core/index.ts';
|
|
5
|
+
import type { EventCountRecentFilter, EventDeleteExpiredOptions, EventFindManyOptions, IEventRepository } from '../../../../../core/index.ts';
|
|
6
6
|
export declare class EventRepositoryAdapter implements IEventRepository {
|
|
7
7
|
private readonly repository;
|
|
8
8
|
constructor(repository: Repository<Event>);
|
|
@@ -11,6 +11,6 @@ export declare class EventRepositoryAdapter implements IEventRepository {
|
|
|
11
11
|
findOneById(id: string): Promise<Event | null>;
|
|
12
12
|
findMany(query: IQuery, options?: EventFindManyOptions): Promise<EntityRepositoryFindManyResult<Event>>;
|
|
13
13
|
countRecent(filter: EventCountRecentFilter): Promise<number>;
|
|
14
|
-
deleteExpired(now: string): Promise<number>;
|
|
14
|
+
deleteExpired(now: string, options?: EventDeleteExpiredOptions): Promise<number>;
|
|
15
15
|
}
|
|
16
16
|
//# sourceMappingURL=repository.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../../../../../src/app/modules/database/repositories/event/repository.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAG1C,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,KAAK,EACR,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,EACnB,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../../../../../src/app/modules/database/repositories/event/repository.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAG1C,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,KAAK,EACR,sBAAsB,EACtB,yBAAyB,EACzB,oBAAoB,EACpB,gBAAgB,EACnB,MAAM,8BAA8B,CAAC;AAItC,qBAAa,sBAAuB,YAAW,gBAAgB;IAC3D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;gBAEnC,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC;IAIzC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK;IAI7B,IAAI,CAAC,MAAM,EAAE,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAInC,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IAI9C,QAAQ,CACV,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,oBAAyB,GACnC,OAAO,CAAC,8BAA8B,CAAC,KAAK,CAAC,CAAC;IAoD3C,WAAW,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC;IAmC5D,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,yBAA8B,GAAG,OAAO,CAAC,MAAM,CAAC;CA+C7F"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
+
import { EVENT_RETENTION_SWEEP_BATCH_SIZE } from "../../../../../core/entities/event/constants.mjs";
|
|
5
|
+
import "../../../../../core/index.mjs";
|
|
4
6
|
import { applyQuery, redactFieldConditions } from "../query.mjs";
|
|
5
7
|
import { applyRealmScopeSelect } from "../helpers.mjs";
|
|
6
|
-
import { LessThan } from "typeorm";
|
|
8
|
+
import { In, LessThan } from "typeorm";
|
|
7
9
|
//#region src/app/modules/database/repositories/event/repository.ts
|
|
8
10
|
var EventRepositoryAdapter = class {
|
|
9
11
|
repository;
|
|
@@ -62,11 +64,26 @@ var EventRepositoryAdapter = class {
|
|
|
62
64
|
else qb.andWhere("event.realmId = :realmId", { realmId: filter.realmId });
|
|
63
65
|
return qb.getCount();
|
|
64
66
|
}
|
|
65
|
-
async deleteExpired(now) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
async deleteExpired(now, options = {}) {
|
|
68
|
+
const requested = options.batchSize;
|
|
69
|
+
const batchSize = typeof requested === "number" && Number.isSafeInteger(requested) && requested > 0 ? requested : EVENT_RETENTION_SWEEP_BATCH_SIZE;
|
|
70
|
+
let total = 0;
|
|
71
|
+
for (;;) {
|
|
72
|
+
const rows = await this.repository.find({
|
|
73
|
+
select: { id: true },
|
|
74
|
+
where: {
|
|
75
|
+
expiring: true,
|
|
76
|
+
expiresAt: LessThan(now)
|
|
77
|
+
},
|
|
78
|
+
take: batchSize
|
|
79
|
+
});
|
|
80
|
+
if (rows.length === 0) break;
|
|
81
|
+
const result = await this.repository.delete({ id: In(rows.map((row) => row.id)) });
|
|
82
|
+
total += result.affected ?? rows.length;
|
|
83
|
+
if (result.affected === 0) break;
|
|
84
|
+
if (rows.length < batchSize) break;
|
|
85
|
+
}
|
|
86
|
+
return total;
|
|
70
87
|
}
|
|
71
88
|
};
|
|
72
89
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository.mjs","names":["LessThan","applyQuery","redactFieldConditions","applyRealmScopeSelect","EventRepositoryAdapter","repository","create","data","save","entity","findOneById","id","findOneBy","findMany","query","options","qb","createQueryBuilder","pagination","owner","andWhere","ownerActorId","actorId","ownerActorType","actorType","realmId","routeRealmId","visibility","constraints","parameters","realmIds","filter","length","push","visibleRealmIds","includes","visibleActorId","visibleActorType","join","entities","total","getManyAndCount","meta","countRecent","since","Date","toISOString","replace","where","name","actorName","requestIpAddress","getCount","deleteExpired","now","result","delete","expiring","expiresAt","affected"],"sources":["../../../../../../src/app/modules/database/repositories/event/repository.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 { Event } from '@authup/core-kit';\nimport type { IQuery } from '@rapiq/core';\nimport type { Repository } from 'typeorm';\nimport { LessThan } from 'typeorm';\nimport { applyQuery, redactFieldConditions } from '../query.ts';\nimport type { EntityRepositoryFindManyResult } from '@authup/server-kit';\nimport type {\n EventCountRecentFilter,\n EventFindManyOptions,\n IEventRepository,\n} from '../../../../../core/index.ts';\nimport { applyRealmScopeSelect } from '../helpers.ts';\n\nexport class EventRepositoryAdapter implements IEventRepository {\n private readonly repository: Repository<Event>;\n\n constructor(repository: Repository<Event>) {\n this.repository = repository;\n }\n\n create(data: Partial<Event>): Event {\n return this.repository.create(data);\n }\n\n async save(entity: Event): Promise<Event> {\n return this.repository.save(entity);\n }\n\n async findOneById(id: string): Promise<Event | null> {\n return this.repository.findOneBy({ id });\n }\n\n async findMany(\n query: IQuery,\n options: EventFindManyOptions = {},\n ): Promise<EntityRepositoryFindManyResult<Event>> {\n const qb = this.repository.createQueryBuilder('event');\n\n const { pagination } = applyQuery(qb, query);\n\n applyRealmScopeSelect(qb, 'event', ['actorId', 'actorType']);\n\n if (options.owner) {\n // mandatory constraint — not overridable by a rapiq filter\n qb.andWhere('event.actorId = :ownerActorId AND event.actorType = :ownerActorType', {\n ownerActorId: options.owner.actorId,\n ownerActorType: options.owner.actorType,\n });\n }\n\n if (options.realmId) {\n qb.andWhere('event.realmId = :routeRealmId', { routeRealmId: options.realmId });\n }\n\n if (options.visibility) {\n const constraints: string[] = [];\n const parameters: Record<string, unknown> = {};\n const realmIds = options.visibility.realmIds\n .filter((realmId): realmId is string => realmId !== null);\n\n if (realmIds.length > 0) {\n constraints.push('event.realmId IN (:...visibleRealmIds)');\n parameters.visibleRealmIds = realmIds;\n }\n if (options.visibility.realmIds.includes(null)) {\n constraints.push('event.realmId IS NULL');\n }\n if (options.visibility.owner) {\n constraints.push('(event.actorId = :visibleActorId AND event.actorType = :visibleActorType)');\n parameters.visibleActorId = options.visibility.owner.actorId;\n parameters.visibleActorType = options.visibility.owner.actorType;\n }\n\n qb.andWhere(`(${constraints.length > 0 ? constraints.join(' OR ') : '1 = 0'})`, parameters);\n }\n\n const [entities, total] = await qb.getManyAndCount();\n\n return {\n data: redactFieldConditions(query, entities),\n meta: {\n total,\n ...pagination,\n },\n };\n }\n\n async countRecent(filter: EventCountRecentFilter): Promise<number> {\n // created_at is stamped by the DATABASE server's clock (assumed UTC —\n // the shipped compose files and deployment posture; a non-UTC DB\n // server shifts the window regardless of what we bind), while a bound\n // Date object is serialized by the pg/mysql drivers in the HOST's\n // local timezone — on a non-UTC host that shifts the window by the\n // UTC offset (postgres: `timestamp without time zone` discards the\n // offset marker entirely). Bind a UTC wall-clock literal instead:\n // pg/mysql cast it as a wall-clock timestamp, sqlite compares it\n // lexicographically against the same format `datetime('now')` stores.\n const since = new Date(filter.since).toISOString().replace('T', ' ').replace('Z', '');\n\n const qb = this.repository.createQueryBuilder('event')\n .where('event.name = :name', { name: filter.name })\n .andWhere('event.createdAt > :since', { since });\n\n if (filter.actorName) {\n qb.andWhere('event.actorName = :actorName', { actorName: filter.actorName });\n }\n\n if (filter.requestIpAddress) {\n qb.andWhere('event.requestIpAddress = :requestIpAddress', { requestIpAddress: filter.requestIpAddress });\n }\n\n if (typeof filter.realmId !== 'undefined') {\n if (filter.realmId === null) {\n qb.andWhere('event.realmId IS NULL');\n } else {\n qb.andWhere('event.realmId = :realmId', { realmId: filter.realmId });\n }\n }\n\n return qb.getCount();\n }\n\n async deleteExpired(now: string): Promise<number> {\n const result = await this.repository.delete({\n expiring: true,\n expiresAt: LessThan(now),\n });\n\n return result.affected ?? 0;\n }\n}\n"],"mappings":";;;;;;;AAoBA,IAAaI,yBAAb,MAAaA;CACQC;CAEjB,YAAYA,YAA+B;EACvC,KAAKA,aAAaA;CACtB;CAEAC,OAAOC,MAA6B;EAChC,OAAO,KAAKF,WAAWC,OAAOC,IAAAA;CAClC;CAEA,MAAMC,KAAKC,QAA+B;EACtC,OAAO,KAAKJ,WAAWG,KAAKC,MAAAA;CAChC;CAEA,MAAMC,YAAYC,IAAmC;EACjD,OAAO,KAAKN,WAAWO,UAAU,EAAED,GAAG,CAAA;CAC1C;CAEA,MAAME,SACFC,OACAC,UAAgC,CAAC,GACa;EAC9C,MAAMC,KAAK,KAAKX,WAAWY,mBAAmB,OAAA;EAE9C,MAAM,EAAEC,eAAejB,WAAWe,IAAIF,KAAAA;EAEtCX,sBAAsBa,IAAI,SAAS,CAAC,WAAW,WAAY,CAAA;EAE3D,IAAID,QAAQI,OAERH,GAAGI,SAAS,uEAAuE;GAC/EC,cAAcN,QAAQI,MAAMG;GAC5BC,gBAAgBR,QAAQI,MAAMK;EAClC,CAAA;EAGJ,IAAIT,QAAQU,SACRT,GAAGI,SAAS,iCAAiC,EAAEM,cAAcX,QAAQU,QAAQ,CAAA;EAGjF,IAAIV,QAAQY,YAAY;GACpB,MAAMC,cAAwB,CAAA;GAC9B,MAAMC,aAAsC,CAAC;GAC7C,MAAMC,WAAWf,QAAQY,WAAWG,SAC/BC,QAAQN,YAA+BA,YAAY,IAAA;GAExD,IAAIK,SAASE,SAAS,GAAG;IACrBJ,YAAYK,KAAK,wCAAA;IACjBJ,WAAWK,kBAAkBJ;GACjC;GACA,IAAIf,QAAQY,WAAWG,SAASK,SAAS,IAAA,GACrCP,YAAYK,KAAK,uBAAA;GAErB,IAAIlB,QAAQY,WAAWR,OAAO;IAC1BS,YAAYK,KAAK,2EAAA;IACjBJ,WAAWO,iBAAiBrB,QAAQY,WAAWR,MAAMG;IACrDO,WAAWQ,mBAAmBtB,QAAQY,WAAWR,MAAMK;GAC3D;GAEAR,GAAGI,SAAS,IAAIQ,YAAYI,SAAS,IAAIJ,YAAYU,KAAK,MAAA,IAAU,QAAQ,IAAIT,UAAAA;EACpF;EAEA,MAAM,CAACU,UAAUC,SAAS,MAAMxB,GAAGyB,gBAAe;EAElD,OAAO;GACHlC,MAAML,sBAAsBY,OAAOyB,QAAAA;GACnCG,MAAM;IACFF;IACA,GAAGtB;GACP;EACJ;CACJ;CAEA,MAAMyB,YAAYZ,QAAiD;EAU/D,MAAMa,QAAQ,IAAIC,KAAKd,OAAOa,KAAK,CAAA,CAAEE,YAAW,CAAA,CAAGC,QAAQ,KAAK,GAAA,CAAA,CAAKA,QAAQ,KAAK,EAAA;EAElF,MAAM/B,KAAK,KAAKX,WAAWY,mBAAmB,OAAA,CAAA,CACzC+B,MAAM,sBAAsB,EAAEC,MAAMlB,OAAOkB,KAAK,CAAA,CAAA,CAChD7B,SAAS,4BAA4B,EAAEwB,MAAM,CAAA;EAElD,IAAIb,OAAOmB,WACPlC,GAAGI,SAAS,gCAAgC,EAAE8B,WAAWnB,OAAOmB,UAAU,CAAA;EAG9E,IAAInB,OAAOoB,kBACPnC,GAAGI,SAAS,8CAA8C,EAAE+B,kBAAkBpB,OAAOoB,iBAAiB,CAAA;EAG1G,IAAI,OAAOpB,OAAON,YAAY,aAC1B,IAAIM,OAAON,YAAY,MACnBT,GAAGI,SAAS,uBAAA;OAEZJ,GAAGI,SAAS,4BAA4B,EAAEK,SAASM,OAAON,QAAQ,CAAA;EAI1E,OAAOT,GAAGoC,SAAQ;CACtB;CAEA,MAAMC,cAAcC,KAA8B;EAM9C,QAAOC,MALc,KAAKlD,WAAWmD,OAAO;GACxCC,UAAU;GACVC,WAAW1D,SAASsD,GAAAA;EACxB,CAAA,EAAA,CAEcK,YAAY;CAC9B;AACJ"}
|
|
1
|
+
{"version":3,"file":"repository.mjs","names":["In","LessThan","applyQuery","redactFieldConditions","EVENT_RETENTION_SWEEP_BATCH_SIZE","applyRealmScopeSelect","EventRepositoryAdapter","repository","create","data","save","entity","findOneById","id","findOneBy","findMany","query","options","qb","createQueryBuilder","pagination","owner","andWhere","ownerActorId","actorId","ownerActorType","actorType","realmId","routeRealmId","visibility","constraints","parameters","realmIds","filter","length","push","visibleRealmIds","includes","visibleActorId","visibleActorType","join","entities","total","getManyAndCount","meta","countRecent","since","Date","toISOString","replace","where","name","actorName","requestIpAddress","getCount","deleteExpired","now","requested","batchSize","Number","isSafeInteger","rows","find","select","expiring","expiresAt","take","result","delete","map","row","affected"],"sources":["../../../../../../src/app/modules/database/repositories/event/repository.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 { Event } from '@authup/core-kit';\nimport type { IQuery } from '@rapiq/core';\nimport type { Repository } from 'typeorm';\nimport { In, LessThan } from 'typeorm';\nimport { applyQuery, redactFieldConditions } from '../query.ts';\nimport type { EntityRepositoryFindManyResult } from '@authup/server-kit';\nimport type {\n EventCountRecentFilter,\n EventDeleteExpiredOptions,\n EventFindManyOptions,\n IEventRepository,\n} from '../../../../../core/index.ts';\nimport { EVENT_RETENTION_SWEEP_BATCH_SIZE } from '../../../../../core/index.ts';\nimport { applyRealmScopeSelect } from '../helpers.ts';\n\nexport class EventRepositoryAdapter implements IEventRepository {\n private readonly repository: Repository<Event>;\n\n constructor(repository: Repository<Event>) {\n this.repository = repository;\n }\n\n create(data: Partial<Event>): Event {\n return this.repository.create(data);\n }\n\n async save(entity: Event): Promise<Event> {\n return this.repository.save(entity);\n }\n\n async findOneById(id: string): Promise<Event | null> {\n return this.repository.findOneBy({ id });\n }\n\n async findMany(\n query: IQuery,\n options: EventFindManyOptions = {},\n ): Promise<EntityRepositoryFindManyResult<Event>> {\n const qb = this.repository.createQueryBuilder('event');\n\n const { pagination } = applyQuery(qb, query);\n\n applyRealmScopeSelect(qb, 'event', ['actorId', 'actorType']);\n\n if (options.owner) {\n // mandatory constraint — not overridable by a rapiq filter\n qb.andWhere('event.actorId = :ownerActorId AND event.actorType = :ownerActorType', {\n ownerActorId: options.owner.actorId,\n ownerActorType: options.owner.actorType,\n });\n }\n\n if (options.realmId) {\n qb.andWhere('event.realmId = :routeRealmId', { routeRealmId: options.realmId });\n }\n\n if (options.visibility) {\n const constraints: string[] = [];\n const parameters: Record<string, unknown> = {};\n const realmIds = options.visibility.realmIds\n .filter((realmId): realmId is string => realmId !== null);\n\n if (realmIds.length > 0) {\n constraints.push('event.realmId IN (:...visibleRealmIds)');\n parameters.visibleRealmIds = realmIds;\n }\n if (options.visibility.realmIds.includes(null)) {\n constraints.push('event.realmId IS NULL');\n }\n if (options.visibility.owner) {\n constraints.push('(event.actorId = :visibleActorId AND event.actorType = :visibleActorType)');\n parameters.visibleActorId = options.visibility.owner.actorId;\n parameters.visibleActorType = options.visibility.owner.actorType;\n }\n\n qb.andWhere(`(${constraints.length > 0 ? constraints.join(' OR ') : '1 = 0'})`, parameters);\n }\n\n const [entities, total] = await qb.getManyAndCount();\n\n return {\n data: redactFieldConditions(query, entities),\n meta: {\n total,\n ...pagination,\n },\n };\n }\n\n async countRecent(filter: EventCountRecentFilter): Promise<number> {\n // created_at is stamped by the DATABASE server's clock (assumed UTC —\n // the shipped compose files and deployment posture; a non-UTC DB\n // server shifts the window regardless of what we bind), while a bound\n // Date object is serialized by the pg/mysql drivers in the HOST's\n // local timezone — on a non-UTC host that shifts the window by the\n // UTC offset (postgres: `timestamp without time zone` discards the\n // offset marker entirely). Bind a UTC wall-clock literal instead:\n // pg/mysql cast it as a wall-clock timestamp, sqlite compares it\n // lexicographically against the same format `datetime('now')` stores.\n const since = new Date(filter.since).toISOString().replace('T', ' ').replace('Z', '');\n\n const qb = this.repository.createQueryBuilder('event')\n .where('event.name = :name', { name: filter.name })\n .andWhere('event.createdAt > :since', { since });\n\n if (filter.actorName) {\n qb.andWhere('event.actorName = :actorName', { actorName: filter.actorName });\n }\n\n if (filter.requestIpAddress) {\n qb.andWhere('event.requestIpAddress = :requestIpAddress', { requestIpAddress: filter.requestIpAddress });\n }\n\n if (typeof filter.realmId !== 'undefined') {\n if (filter.realmId === null) {\n qb.andWhere('event.realmId IS NULL');\n } else {\n qb.andWhere('event.realmId = :realmId', { realmId: filter.realmId });\n }\n }\n\n return qb.getCount();\n }\n\n async deleteExpired(now: string, options: EventDeleteExpiredOptions = {}): Promise<number> {\n // A non-positive or non-integral size must never reach `take`: typeorm\n // ignores a falsy one, which would silently restore the single\n // unbounded DELETE this batching exists to prevent, and the rest reach\n // the driver as invalid SQL. Fall back to the default instead.\n const requested = options.batchSize;\n const batchSize = typeof requested === 'number' &&\n Number.isSafeInteger(requested) &&\n requested > 0 ?\n requested :\n EVENT_RETENTION_SWEEP_BATCH_SIZE;\n\n let total = 0;\n\n for (;;) {\n const rows = await this.repository.find({\n select: { id: true },\n where: {\n expiring: true,\n expiresAt: LessThan(now),\n },\n take: batchSize,\n });\n\n if (rows.length === 0) {\n break;\n }\n\n const result = await this.repository.delete({ id: In(rows.map((row) => row.id)) });\n\n // A driver that does not report affected rows still made\n // progress, so count the batch rather than returning 0.\n total += result.affected ?? rows.length;\n\n // Another replica's sweep already owns these rows. Stop rather\n // than re-selecting them; the next tick picks up whatever is left.\n if (result.affected === 0) {\n break;\n }\n\n if (rows.length < batchSize) {\n break;\n }\n }\n\n return total;\n }\n}\n"],"mappings":"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"}
|
package/dist/app/modules/database/repositories/identity-provider-account/repository.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../../../../../src/app/modules/database/repositories/identity-provider-account/repository.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../../../../../src/app/modules/database/repositories/identity-provider-account/repository.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAEhE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,KAAK,EACR,UAAU,EACV,WAAW,EACX,UAAU,EACb,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,6BAA6B,EAAE,MAAM,mDAAmD,CAAC;AAGlG,OAAO,KAAK,EACR,kCAAkC,EAClC,sCAAsC,EACtC,wBAAwB,EAC3B,MAAM,8BAA8B,CAAC;AAEtC,qBAAa,wCAAyC,YAAW,kCAAkC;IAC/F,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC;IAEjC,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC,6BAA6B,CAAC,CAAC;gBAEpD,UAAU,EAAE,UAAU;IAK5B,QAAQ,CACV,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,sCAA2C,GACrD,OAAO,CAAC,8BAA8B,CAAC,uBAAuB,CAAC,CAAC;IAuC7D,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC;IAIhE,aAAa,CAAC,MAAM,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAsC5F,yBAAyB,CAAC,QAAQ,EAAE,wBAAwB,GAAG,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC;IAUtG,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,uBAAuB,CAAC,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAiBpF,MAAM,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;CAG/D"}
|
|
@@ -6,6 +6,9 @@ import "../../../../../adapters/database/helpers/index.mjs";
|
|
|
6
6
|
import { IdentityProviderAccountEntity } from "../../../../../adapters/database/domains/identity-provider-account/entity.mjs";
|
|
7
7
|
import "../../../../../adapters/database/domains/index.mjs";
|
|
8
8
|
import { applyQuery, redactFieldConditions } from "../query.mjs";
|
|
9
|
+
import { isUniqueConstraintDatabaseError } from "../../../../../adapters/database/errors/driver.mjs";
|
|
10
|
+
import "../../../../../adapters/database/errors/index.mjs";
|
|
11
|
+
import { EntityConflictError } from "@authup/errors";
|
|
9
12
|
//#region src/app/modules/database/repositories/identity-provider-account/repository.ts
|
|
10
13
|
var IdentityProviderAccountRepositoryAdapter = class {
|
|
11
14
|
dataSource;
|
|
@@ -57,7 +60,12 @@ var IdentityProviderAccountRepositoryAdapter = class {
|
|
|
57
60
|
});
|
|
58
61
|
}
|
|
59
62
|
async save(entity) {
|
|
60
|
-
|
|
63
|
+
try {
|
|
64
|
+
return await this.repository.save(entity);
|
|
65
|
+
} catch (e) {
|
|
66
|
+
if (isUniqueConstraintDatabaseError(e)) throw new EntityConflictError({ entity: "identity provider account" });
|
|
67
|
+
throw e;
|
|
68
|
+
}
|
|
61
69
|
}
|
|
62
70
|
async remove(entity) {
|
|
63
71
|
await this.repository.remove(entity);
|