@robelest/convex-auth 0.0.4-preview.21 → 0.0.4-preview.23
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/authorization/index.d.ts +1 -1
- package/dist/authorization/index.js +1 -1
- package/dist/authorization/index.js.map +1 -1
- package/dist/client/index.d.ts +1 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +36 -39
- package/dist/client/index.js.map +1 -1
- package/dist/component/client/index.d.ts +1 -2
- package/dist/component/convex.config.d.ts +2 -2
- package/dist/component/convex.config.d.ts.map +1 -1
- package/dist/component/model.d.ts +5 -5
- package/dist/component/model.d.ts.map +1 -1
- package/dist/component/public/enterprise/audit.d.ts.map +1 -1
- package/dist/component/public/enterprise/audit.js.map +1 -1
- package/dist/component/public/enterprise/core.d.ts.map +1 -1
- package/dist/component/public/enterprise/core.js.map +1 -1
- package/dist/component/public/enterprise/domains.d.ts.map +1 -1
- package/dist/component/public/enterprise/domains.js.map +1 -1
- package/dist/component/public/enterprise/scim.d.ts.map +1 -1
- package/dist/component/public/enterprise/scim.js.map +1 -1
- package/dist/component/public/enterprise/secrets.d.ts.map +1 -1
- package/dist/component/public/enterprise/secrets.js.map +1 -1
- package/dist/component/public/enterprise/webhooks.d.ts.map +1 -1
- package/dist/component/public/enterprise/webhooks.js.map +1 -1
- package/dist/component/public/factors/devices.d.ts.map +1 -1
- package/dist/component/public/factors/devices.js.map +1 -1
- package/dist/component/public/factors/passkeys.d.ts.map +1 -1
- package/dist/component/public/factors/passkeys.js.map +1 -1
- package/dist/component/public/factors/totp.d.ts.map +1 -1
- package/dist/component/public/factors/totp.js.map +1 -1
- package/dist/component/public/groups/core.js.map +1 -1
- package/dist/component/public/groups/invites.d.ts.map +1 -1
- package/dist/component/public/groups/invites.js.map +1 -1
- package/dist/component/public/groups/members.d.ts.map +1 -1
- package/dist/component/public/groups/members.js.map +1 -1
- package/dist/component/public/identity/accounts.d.ts.map +1 -1
- package/dist/component/public/identity/accounts.js.map +1 -1
- package/dist/component/public/identity/codes.d.ts.map +1 -1
- package/dist/component/public/identity/codes.js.map +1 -1
- package/dist/component/public/identity/sessions.d.ts.map +1 -1
- package/dist/component/public/identity/sessions.js.map +1 -1
- package/dist/component/public/identity/tokens.d.ts.map +1 -1
- package/dist/component/public/identity/tokens.js.map +1 -1
- package/dist/component/public/identity/users.d.ts.map +1 -1
- package/dist/component/public/identity/users.js.map +1 -1
- package/dist/component/public/identity/verifiers.d.ts.map +1 -1
- package/dist/component/public/identity/verifiers.js.map +1 -1
- package/dist/component/public/security/keys.d.ts.map +1 -1
- package/dist/component/public/security/keys.js.map +1 -1
- package/dist/component/public/security/limits.d.ts.map +1 -1
- package/dist/component/public/security/limits.js.map +1 -1
- package/dist/component/schema.d.ts +39 -39
- package/dist/component/server/auth.d.ts +95 -52
- package/dist/component/server/auth.d.ts.map +1 -1
- package/dist/component/server/auth.js +63 -43
- package/dist/component/server/auth.js.map +1 -1
- package/dist/component/server/core.js +116 -235
- package/dist/component/server/core.js.map +1 -1
- package/dist/component/server/crypto.js +25 -7
- package/dist/component/server/crypto.js.map +1 -1
- package/dist/component/server/device.js +58 -15
- package/dist/component/server/device.js.map +1 -1
- package/dist/component/server/enterprise/domain.js +148 -59
- package/dist/component/server/enterprise/domain.js.map +1 -1
- package/dist/component/server/enterprise/http.js +36 -15
- package/dist/component/server/enterprise/http.js.map +1 -1
- package/dist/component/server/enterprise/oidc.js +1 -1
- package/dist/component/server/http.js +26 -21
- package/dist/component/server/http.js.map +1 -1
- package/dist/component/server/identity.js +5 -2
- package/dist/component/server/identity.js.map +1 -1
- package/dist/component/server/limits.js +21 -30
- package/dist/component/server/limits.js.map +1 -1
- package/dist/component/server/mutations/account.js +12 -10
- package/dist/component/server/mutations/account.js.map +1 -1
- package/dist/component/server/mutations/code.js +5 -2
- package/dist/component/server/mutations/code.js.map +1 -1
- package/dist/component/server/mutations/invalidate.js +1 -1
- package/dist/component/server/mutations/invalidate.js.map +1 -1
- package/dist/component/server/mutations/oauth.js +10 -4
- package/dist/component/server/mutations/oauth.js.map +1 -1
- package/dist/component/server/mutations/refresh.js +2 -2
- package/dist/component/server/mutations/refresh.js.map +1 -1
- package/dist/component/server/mutations/register.js +46 -42
- package/dist/component/server/mutations/register.js.map +1 -1
- package/dist/component/server/mutations/retrieve.js +21 -25
- package/dist/component/server/mutations/retrieve.js.map +1 -1
- package/dist/component/server/mutations/signature.js +10 -4
- package/dist/component/server/mutations/signature.js.map +1 -1
- package/dist/component/server/mutations/signout.js.map +1 -1
- package/dist/component/server/mutations/store.js +9 -24
- package/dist/component/server/mutations/store.js.map +1 -1
- package/dist/component/server/mutations/verifier.js.map +1 -1
- package/dist/component/server/mutations/verify.js +1 -1
- package/dist/component/server/mutations/verify.js.map +1 -1
- package/dist/component/server/oauth.js +53 -16
- package/dist/component/server/oauth.js.map +1 -1
- package/dist/component/server/passkey.js +115 -31
- package/dist/component/server/passkey.js.map +1 -1
- package/dist/component/server/redirects.js +9 -3
- package/dist/component/server/redirects.js.map +1 -1
- package/dist/component/server/refresh.js +10 -7
- package/dist/component/server/refresh.js.map +1 -1
- package/dist/component/server/runtime.d.ts +3 -3
- package/dist/component/server/runtime.d.ts.map +1 -1
- package/dist/component/server/runtime.js +62 -20
- package/dist/component/server/runtime.js.map +1 -1
- package/dist/component/server/signin.js +34 -10
- package/dist/component/server/signin.js.map +1 -1
- package/dist/component/server/totp.js +79 -19
- package/dist/component/server/totp.js.map +1 -1
- package/dist/component/server/types.d.ts +12 -20
- package/dist/component/server/types.d.ts.map +1 -1
- package/dist/component/server/types.js.map +1 -1
- package/dist/component/server/users.js +6 -3
- package/dist/component/server/users.js.map +1 -1
- package/dist/component/server/utils.js +10 -4
- package/dist/component/server/utils.js.map +1 -1
- package/dist/core/types.d.ts +14 -22
- package/dist/core/types.d.ts.map +1 -1
- package/dist/factors/device.js +8 -9
- package/dist/factors/device.js.map +1 -1
- package/dist/factors/passkey.js +18 -21
- package/dist/factors/passkey.js.map +1 -1
- package/dist/providers/password.js +66 -81
- package/dist/providers/password.js.map +1 -1
- package/dist/runtime/invite.js +2 -8
- package/dist/runtime/invite.js.map +1 -1
- package/dist/server/auth.d.ts +95 -52
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +63 -43
- package/dist/server/auth.js.map +1 -1
- package/dist/server/core.d.ts +71 -159
- package/dist/server/core.d.ts.map +1 -1
- package/dist/server/core.js +116 -235
- package/dist/server/core.js.map +1 -1
- package/dist/server/crypto.d.ts.map +1 -1
- package/dist/server/crypto.js +25 -7
- package/dist/server/crypto.js.map +1 -1
- package/dist/server/device.js +58 -15
- package/dist/server/device.js.map +1 -1
- package/dist/server/enterprise/domain.d.ts +0 -8
- package/dist/server/enterprise/domain.d.ts.map +1 -1
- package/dist/server/enterprise/domain.js +148 -59
- package/dist/server/enterprise/domain.js.map +1 -1
- package/dist/server/enterprise/http.d.ts.map +1 -1
- package/dist/server/enterprise/http.js +35 -14
- package/dist/server/enterprise/http.js.map +1 -1
- package/dist/server/http.d.ts +2 -2
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +25 -20
- package/dist/server/http.js.map +1 -1
- package/dist/server/identity.js +5 -2
- package/dist/server/identity.js.map +1 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/server/limits.js +21 -30
- package/dist/server/limits.js.map +1 -1
- package/dist/server/mounts.d.ts +26 -64
- package/dist/server/mounts.d.ts.map +1 -1
- package/dist/server/mounts.js +45 -106
- package/dist/server/mounts.js.map +1 -1
- package/dist/server/mutations/account.d.ts +8 -9
- package/dist/server/mutations/account.d.ts.map +1 -1
- package/dist/server/mutations/account.js +11 -9
- package/dist/server/mutations/account.js.map +1 -1
- package/dist/server/mutations/code.d.ts +13 -13
- package/dist/server/mutations/code.d.ts.map +1 -1
- package/dist/server/mutations/code.js +5 -2
- package/dist/server/mutations/code.js.map +1 -1
- package/dist/server/mutations/invalidate.d.ts +4 -4
- package/dist/server/mutations/invalidate.d.ts.map +1 -1
- package/dist/server/mutations/invalidate.js.map +1 -1
- package/dist/server/mutations/oauth.d.ts +12 -10
- package/dist/server/mutations/oauth.d.ts.map +1 -1
- package/dist/server/mutations/oauth.js +9 -3
- package/dist/server/mutations/oauth.js.map +1 -1
- package/dist/server/mutations/refresh.d.ts +3 -3
- package/dist/server/mutations/refresh.d.ts.map +1 -1
- package/dist/server/mutations/refresh.js +1 -1
- package/dist/server/mutations/refresh.js.map +1 -1
- package/dist/server/mutations/register.d.ts +11 -11
- package/dist/server/mutations/register.d.ts.map +1 -1
- package/dist/server/mutations/register.js +45 -41
- package/dist/server/mutations/register.js.map +1 -1
- package/dist/server/mutations/retrieve.d.ts +6 -6
- package/dist/server/mutations/retrieve.d.ts.map +1 -1
- package/dist/server/mutations/retrieve.js +20 -24
- package/dist/server/mutations/retrieve.js.map +1 -1
- package/dist/server/mutations/signature.d.ts +6 -7
- package/dist/server/mutations/signature.d.ts.map +1 -1
- package/dist/server/mutations/signature.js +9 -3
- package/dist/server/mutations/signature.js.map +1 -1
- package/dist/server/mutations/signin.d.ts +5 -5
- package/dist/server/mutations/signin.d.ts.map +1 -1
- package/dist/server/mutations/signout.js.map +1 -1
- package/dist/server/mutations/store.d.ts +97 -97
- package/dist/server/mutations/store.d.ts.map +1 -1
- package/dist/server/mutations/store.js +8 -23
- package/dist/server/mutations/store.js.map +1 -1
- package/dist/server/mutations/verifier.js.map +1 -1
- package/dist/server/mutations/verify.d.ts +10 -10
- package/dist/server/mutations/verify.d.ts.map +1 -1
- package/dist/server/mutations/verify.js.map +1 -1
- package/dist/server/oauth.js +53 -16
- package/dist/server/oauth.js.map +1 -1
- package/dist/server/passkey.d.ts +2 -2
- package/dist/server/passkey.d.ts.map +1 -1
- package/dist/server/passkey.js +114 -30
- package/dist/server/passkey.js.map +1 -1
- package/dist/server/redirects.js +9 -3
- package/dist/server/redirects.js.map +1 -1
- package/dist/server/refresh.js +10 -7
- package/dist/server/refresh.js.map +1 -1
- package/dist/server/runtime.d.ts +14 -14
- package/dist/server/runtime.d.ts.map +1 -1
- package/dist/server/runtime.js +61 -19
- package/dist/server/runtime.js.map +1 -1
- package/dist/server/signin.js +34 -10
- package/dist/server/signin.js.map +1 -1
- package/dist/server/ssr.d.ts.map +1 -1
- package/dist/server/ssr.js +175 -184
- package/dist/server/ssr.js.map +1 -1
- package/dist/server/totp.js +78 -18
- package/dist/server/totp.js.map +1 -1
- package/dist/server/types.d.ts +13 -21
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js.map +1 -1
- package/dist/server/users.js +6 -3
- package/dist/server/users.js.map +1 -1
- package/dist/server/utils.js +10 -4
- package/dist/server/utils.js.map +1 -1
- package/package.json +2 -6
- package/src/authorization/index.ts +1 -1
- package/src/cli/index.ts +1 -1
- package/src/client/core/types.ts +14 -14
- package/src/client/factors/device.ts +10 -12
- package/src/client/factors/passkey.ts +23 -26
- package/src/client/index.ts +54 -64
- package/src/client/runtime/invite.ts +5 -7
- package/src/component/index.ts +1 -0
- package/src/component/public/enterprise/audit.ts +6 -1
- package/src/component/public/enterprise/core.ts +1 -0
- package/src/component/public/enterprise/domains.ts +5 -1
- package/src/component/public/enterprise/scim.ts +1 -0
- package/src/component/public/enterprise/secrets.ts +1 -0
- package/src/component/public/enterprise/webhooks.ts +1 -0
- package/src/component/public/factors/devices.ts +1 -0
- package/src/component/public/factors/passkeys.ts +1 -0
- package/src/component/public/factors/totp.ts +1 -0
- package/src/component/public/groups/core.ts +1 -1
- package/src/component/public/groups/invites.ts +7 -1
- package/src/component/public/groups/members.ts +1 -0
- package/src/component/public/identity/accounts.ts +1 -0
- package/src/component/public/identity/codes.ts +1 -0
- package/src/component/public/identity/sessions.ts +1 -0
- package/src/component/public/identity/tokens.ts +1 -0
- package/src/component/public/identity/users.ts +1 -0
- package/src/component/public/identity/verifiers.ts +1 -0
- package/src/component/public/security/keys.ts +1 -0
- package/src/component/public/security/limits.ts +1 -0
- package/src/providers/password.ts +89 -110
- package/src/server/auth.ts +177 -111
- package/src/server/core.ts +197 -233
- package/src/server/crypto.ts +31 -29
- package/src/server/device.ts +65 -32
- package/src/server/enterprise/domain.ts +158 -170
- package/src/server/enterprise/http.ts +46 -39
- package/src/server/http.ts +36 -30
- package/src/server/identity.ts +5 -5
- package/src/server/index.ts +2 -0
- package/src/server/limits.ts +53 -80
- package/src/server/mounts.ts +47 -74
- package/src/server/mutations/account.ts +22 -36
- package/src/server/mutations/code.ts +6 -6
- package/src/server/mutations/invalidate.ts +1 -1
- package/src/server/mutations/oauth.ts +14 -8
- package/src/server/mutations/refresh.ts +5 -4
- package/src/server/mutations/register.ts +87 -132
- package/src/server/mutations/retrieve.ts +44 -44
- package/src/server/mutations/signature.ts +13 -6
- package/src/server/mutations/signout.ts +1 -1
- package/src/server/mutations/store.ts +16 -31
- package/src/server/mutations/verifier.ts +1 -1
- package/src/server/mutations/verify.ts +3 -5
- package/src/server/oauth.ts +60 -69
- package/src/server/passkey.ts +567 -517
- package/src/server/redirects.ts +10 -6
- package/src/server/refresh.ts +14 -18
- package/src/server/runtime.ts +70 -55
- package/src/server/signin.ts +44 -37
- package/src/server/ssr.ts +390 -407
- package/src/server/totp.ts +85 -35
- package/src/server/types.ts +19 -22
- package/src/server/users.ts +7 -6
- package/src/server/utils.ts +10 -12
- package/dist/component/server/authError.js +0 -34
- package/dist/component/server/authError.js.map +0 -1
- package/dist/component/server/errors.d.ts +0 -1
- package/dist/component/server/errors.js +0 -137
- package/dist/component/server/errors.js.map +0 -1
- package/dist/server/authError.d.ts +0 -46
- package/dist/server/authError.d.ts.map +0 -1
- package/dist/server/authError.js +0 -34
- package/dist/server/authError.js.map +0 -1
- package/dist/server/errors.d.ts +0 -177
- package/dist/server/errors.d.ts.map +0 -1
- package/dist/server/errors.js +0 -212
- package/dist/server/errors.js.map +0 -1
- package/src/server/authError.ts +0 -44
- package/src/server/errors.ts +0 -290
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","names":["serializeCookie","state"],"sources":["../../../src/server/enterprise/http.ts"],"sourcesContent":["import type { GenericActionCtx, HttpRouter } from \"convex/server\";\nimport { serialize as serializeCookie } from \"cookie\";\n\nimport { redirectToParamCookie, useRedirectToParam } from \"../cookies\";\nimport { isAuthError } from \"../errors\";\nimport { Fx } from \"@robelest/fx\";\n\nimport { AuthError } from \"../authError\";\nimport { addSSORoutes, convertErrorsToResponse, getCookies } from \"../http\";\nimport type { SSORuntimeRoute } from \"../http\";\nimport { createOAuthAuthorizationURL, handleOAuthCallback } from \"../oauth\";\nimport { redirectAbsoluteUrl, setURLSearchParam } from \"../redirects\";\nimport { createEnterpriseOidcRuntime } from \"./oidc\";\nimport {\n createEnterpriseSamlMetadataXml,\n createEnterpriseSamlSignInRequest,\n createSamlPostBindingResponse,\n encodeEnterpriseSamlRelayState,\n parseEnterpriseSamlLoginResponse,\n parseEnterpriseSamlLogoutMessage,\n profileFromSamlExtract,\n validateEnterpriseSamlLoginRelayState,\n} from \"./saml\";\nimport {\n parseScimListRequest,\n scimError,\n scimJson,\n serializeScimGroup,\n serializeScimUser,\n} from \"./scim\";\nimport {\n enterpriseSamlProviderId,\n SCIM_GROUP_SCHEMA_ID,\n SCIM_USER_SCHEMA_ID,\n} from \"./shared\";\n\nexport type EnterpriseHttpRuntimeDeps = {\n http: HttpRouter;\n hasSSO: boolean;\n auth: any;\n config: any;\n routeBase: string;\n requireEnv: (name: string) => string;\n loadActiveEnterpriseSamlOrThrow: any;\n loadEnterpriseOidcOrThrow: any;\n getEnterpriseScimContext: any;\n getPolicyFromEnterprise: any;\n normalizeEnterprisePolicy: any;\n recordEnterpriseAuditEvent: any;\n emitEnterpriseWebhookDeliveries: any;\n generateRandomString: (length: number, alphabet: string) => string;\n inviteTokenAlphabet: string;\n callUserOAuth: any;\n callVerifierSignature: any;\n};\n\nexport function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {\n if (!deps.hasSSO) {\n return;\n }\n\n const {\n http,\n auth,\n config,\n requireEnv,\n loadActiveEnterpriseSamlOrThrow,\n loadEnterpriseOidcOrThrow,\n getEnterpriseScimContext,\n getPolicyFromEnterprise,\n recordEnterpriseAuditEvent,\n emitEnterpriseWebhookDeliveries,\n generateRandomString,\n inviteTokenAlphabet: INVITE_TOKEN_ALPHABET,\n callUserOAuth,\n callVerifierSignature,\n } = deps;\n const ENTERPRISE_CONTROL_ROUTE_BASE = deps.routeBase;\n\n type ScimState = {\n ctx: any;\n request: Request;\n url: URL;\n parsedPath: Awaited<\n ReturnType<typeof getEnterpriseScimContext>\n >[\"parsedPath\"];\n enterprise: Awaited<\n ReturnType<typeof getEnterpriseScimContext>\n >[\"enterprise\"];\n scimConfig: Awaited<\n ReturnType<typeof getEnterpriseScimContext>\n >[\"scimConfig\"];\n policy: any;\n recordScimEvent: (\n eventType: string,\n ok: boolean,\n subjectType: string,\n subjectId?: string,\n metadata?: Record<string, unknown>,\n ) => Promise<void>;\n };\n\n type ScimHandler = (state: ScimState) => Promise<Response>;\n\n const SCIM_SCHEMAS = [\n {\n id: SCIM_USER_SCHEMA_ID,\n name: \"User\",\n description: \"User Account\",\n attributes: [\n { name: \"userName\", type: \"string\", required: true },\n { name: \"displayName\", type: \"string\" },\n { name: \"active\", type: \"boolean\" },\n { name: \"emails\", type: \"complex\", multiValued: true },\n ],\n },\n {\n id: SCIM_GROUP_SCHEMA_ID,\n name: \"Group\",\n description: \"Group\",\n attributes: [\n { name: \"displayName\", type: \"string\", required: true },\n { name: \"members\", type: \"complex\", multiValued: true },\n ],\n },\n ] as const;\n\n const SCIM_RESOURCE_TYPES = [\n {\n id: \"User\",\n name: \"User\",\n endpoint: \"/Users\",\n schema: SCIM_USER_SCHEMA_ID,\n },\n {\n id: \"Group\",\n name: \"Group\",\n endpoint: \"/Groups\",\n schema: SCIM_GROUP_SCHEMA_ID,\n },\n ] as const;\n\n const handleStaticScimCollection = <T extends { id?: string; name?: string }>(\n items: readonly T[],\n resourceId: string | undefined,\n opts: { by: \"id\" | \"name\"; notFound: string },\n ) => {\n if (resourceId !== undefined) {\n const item = items.find(\n (entry) => entry[opts.by] === decodeURIComponent(resourceId),\n );\n return item ? scimJson(item) : scimError(404, \"notFound\", opts.notFound);\n }\n return scimJson({\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n Resources: items,\n totalResults: items.length,\n startIndex: 1,\n itemsPerPage: items.length,\n });\n };\n\n const filterScimCollection = <T>(\n items: T[],\n filter: ReturnType<typeof parseScimListRequest>[\"filter\"],\n filters: Record<string, (item: T, value: string) => boolean>,\n ) => {\n if (!filter) {\n return items;\n }\n const predicate = filters[filter.attribute];\n if (!predicate) {\n throw new Error(\"Unsupported SCIM filter.\");\n }\n return items.filter((item) => predicate(item, filter.value));\n };\n\n const paginateScimCollection = <T>(\n items: T[],\n listRequest: ReturnType<typeof parseScimListRequest>,\n ) => {\n const start = listRequest.startIndex - 1;\n return items.slice(start, start + listRequest.count);\n };\n\n const requireScimResourceId = (\n resourceId: string | undefined,\n label: string,\n ) => {\n if (!resourceId) {\n return scimError(400, \"invalidPath\", `${label} resource ID is required.`);\n }\n return null;\n };\n\n const readScimJson = async (request: Request) =>\n (await request.json()) as Record<string, any>;\n\n const handleSamlAcs = async (\n ctx: GenericActionCtx<any>,\n request: Request,\n runtimeRoute: SSORuntimeRoute,\n ) =>\n Fx.run(\n Fx.gen(function* () {\n yield* Fx.guard(\n runtimeRoute.protocol !== \"saml\" ||\n runtimeRoute.rest.length !== 1 ||\n runtimeRoute.rest[0] !== \"acs\",\n Fx.fail(\n new AuthError(\n \"INVALID_PARAMETERS\",\n \"Invalid enterprise runtime path.\",\n ).toConvexError(),\n ),\n );\n\n const enterpriseId = runtimeRoute.enterpriseId;\n const { loaded, enterprise, saml } = yield* Fx.from({\n ok: () => loadActiveEnterpriseSamlOrThrow(ctx, enterpriseId),\n err: (e) => e,\n });\n\n const parsedResponse = yield* Fx.from({\n ok: () =>\n parseEnterpriseSamlLoginResponse({\n request,\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: { kind: \"enterprise\", id: enterprise._id },\n config: loaded.config,\n }),\n err: (e) =>\n new AuthError(\n \"OAUTH_PROVIDER_ERROR\",\n `SAML response parse failed: ${e instanceof Error ? e.message : String(e)}`,\n ).toConvexError(),\n });\n\n yield* Fx.from({\n ok: () => {\n validateEnterpriseSamlLoginRelayState({\n relayState: parsedResponse.relayState,\n source: { kind: \"enterprise\", id: enterprise._id },\n inResponseTo:\n parsedResponse.parsed.extract?.response?.inResponseTo,\n });\n return Promise.resolve();\n },\n err: () =>\n new AuthError(\n \"OAUTH_INVALID_STATE\",\n \"SAML RelayState did not match the pending login request.\",\n ).toConvexError(),\n });\n\n const { samlAttributes, samlSessionIndex, ...userProfile } =\n profileFromSamlExtract(\n parsedResponse.parsed.extract,\n saml.attributeMapping,\n );\n const profile = userProfile as Record<string, unknown> & {\n id: string;\n };\n\n const maybeRedirectTo = useRedirectToParam(\n enterpriseSamlProviderId(enterprise._id),\n getCookies(request),\n );\n\n const verificationCode = yield* Fx.from({\n ok: () =>\n callUserOAuth(ctx, {\n provider: enterpriseSamlProviderId(enterprise._id),\n providerAccountId: profile.id,\n profile,\n signature: parsedResponse.relayState.signature,\n accountExtend: {\n identity: {\n protocol: \"saml\",\n enterpriseId: enterprise._id,\n subject: profile.id,\n entityId:\n typeof saml.entityId === \"string\"\n ? saml.entityId\n : undefined,\n },\n saml: {\n attributes: samlAttributes,\n sessionIndex: samlSessionIndex,\n },\n },\n }),\n err: (e) => e,\n });\n\n const destinationUrl = yield* Fx.from({\n ok: () =>\n redirectAbsoluteUrl(config, {\n redirectTo:\n maybeRedirectTo?.redirectTo ??\n (typeof parsedResponse.relayState.redirectTo === \"string\"\n ? parsedResponse.relayState.redirectTo\n : undefined),\n }),\n err: (e) => e,\n });\n\n const vurl = setURLSearchParam(\n destinationUrl,\n \"code\",\n verificationCode,\n );\n const vheaders = new Headers({ Location: vurl });\n vheaders.set(\"Cache-Control\", \"must-revalidate\");\n for (const { name, value, options } of maybeRedirectTo !== null\n ? [maybeRedirectTo.updatedCookie]\n : []) {\n vheaders.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return new Response(null, { status: 302, headers: vheaders });\n }).pipe(Fx.recover((e) => Fx.fatal(e))),\n );\n\n const handleSamlSlo = async (\n ctx: GenericActionCtx<any>,\n request: Request,\n runtimeRoute: SSORuntimeRoute,\n ) => {\n if (\n runtimeRoute.protocol !== \"saml\" ||\n runtimeRoute.rest.length !== 1 ||\n runtimeRoute.rest[0] !== \"slo\"\n ) {\n throw new AuthError(\n \"INVALID_PARAMETERS\",\n \"Invalid enterprise runtime path.\",\n ).toConvexError();\n }\n const { loaded, enterprise } = await loadActiveEnterpriseSamlOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n const parsedMessage = await parseEnterpriseSamlLogoutMessage({\n request,\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: { kind: \"enterprise\", id: enterprise._id },\n config: loaded.config,\n });\n if (parsedMessage.hasSamlRequest && parsedMessage.parsedRequest) {\n const responseContext = (\n parsedMessage.runtime.sp as any\n ).createLogoutResponse(\n parsedMessage.runtime.idp as any,\n parsedMessage.parsedRequest.extract,\n parsedMessage.binding as any,\n parsedMessage.relayState ?? \"\",\n ) as any;\n if (parsedMessage.binding === \"redirect\") {\n return new Response(null, {\n status: 302,\n headers: { Location: responseContext.context },\n });\n }\n return createSamlPostBindingResponse({\n endpoint: responseContext.entityEndpoint,\n parameter: \"SAMLResponse\",\n value: responseContext.context,\n relayState: parsedMessage.relayState,\n });\n }\n if (parsedMessage.hasSamlResponse) {\n return new Response(null, { status: 204 });\n }\n throw new AuthError(\n \"INVALID_PARAMETERS\",\n \"Missing SAML logout payload.\",\n ).toConvexError();\n };\n\n const handleScimRequest = async (\n ctx: GenericActionCtx<any>,\n request: Request,\n ) => {\n try {\n const { scimConfig, enterprise, parsedPath } =\n await getEnterpriseScimContext(ctx, request);\n const url = new URL(request.url);\n const state: ScimState = {\n ctx,\n request,\n url,\n parsedPath,\n enterprise,\n scimConfig,\n policy: getPolicyFromEnterprise(enterprise),\n recordScimEvent: async (\n eventType,\n ok,\n subjectType,\n subjectId,\n metadata,\n ) => {\n const auditEventId = await recordEnterpriseAuditEvent(ctx, {\n enterpriseId: enterprise._id,\n groupId: enterprise.groupId,\n eventType,\n actorType: \"scim\",\n subjectType,\n subjectId,\n ok,\n metadata,\n });\n await emitEnterpriseWebhookDeliveries(ctx, {\n enterpriseId: enterprise._id,\n eventType,\n auditEventId,\n payload: {\n enterpriseId: enterprise._id,\n subjectId,\n metadata,\n },\n });\n },\n };\n\n const handleUsersGet: ScimHandler = async (state) => {\n const members = await auth.member.list(state.ctx, {\n where: { groupId: state.enterprise.groupId },\n limit: 100,\n });\n const identities = await state.ctx.runQuery(\n config.component.public.enterpriseScimIdentityListByEnterprise,\n { enterpriseId: state.enterprise._id },\n );\n const identityByUserId = new Map(\n identities\n .filter((identity: any) => identity.userId !== undefined)\n .map((identity: any) => [identity.userId, identity]),\n );\n const users = (\n await Promise.all(\n members.items.map(async (member: any) => {\n const user = await auth.user.get(state.ctx, member.userId);\n return user\n ? {\n user,\n member,\n identity: identityByUserId.get(user._id),\n }\n : null;\n }),\n )\n ).filter(Boolean) as Array<{\n user: any;\n member: any;\n identity?: any;\n }>;\n const listRequest = parseScimListRequest(state.url);\n const filtered = filterScimCollection(users, listRequest.filter, {\n id: (item: { user: any }, value: string) => item.user._id === value,\n externalId: (item: { identity?: any }, value: string) =>\n item.identity?.externalId === value,\n userName: (item: { user: any }, value: string) =>\n item.user.email === value,\n \"emails.value\": (item: { user: any }, value: string) =>\n item.user.email === value,\n active: (item: { identity?: any; member: any }, value: string) =>\n String(item.identity?.active ?? item.member.status === \"active\") ===\n value,\n });\n if (state.parsedPath.resourceId) {\n const resource = filtered.find(\n ({ user }) => user._id === state.parsedPath.resourceId,\n );\n return resource\n ? scimJson(\n serializeScimUser({\n id: resource.user._id,\n user: resource.user,\n externalId: resource.identity?.externalId,\n location: `${state.url.origin}${state.url.pathname.replace(/\\/[^/]+$/, \"\")}/${resource.user._id}`,\n active:\n resource.identity?.active ??\n resource.member.status === \"active\",\n }),\n 200,\n {\n Location: `${state.url.origin}${state.url.pathname.replace(/\\/[^/]+$/, \"\")}/${resource.user._id}`,\n },\n )\n : scimError(404, \"notFound\", \"User not found.\");\n }\n const paged = paginateScimCollection(filtered, listRequest);\n await state.recordScimEvent(\n \"enterprise.scim.read\",\n true,\n \"enterprise_scim\",\n state.scimConfig._id,\n );\n return scimJson({\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n Resources: paged.map(({ user, identity, member }) =>\n serializeScimUser({\n id: user._id,\n user,\n externalId: identity?.externalId,\n location: `${state.url.origin}${state.url.pathname}/${user._id}`,\n active: identity?.active ?? member.status === \"active\",\n }),\n ),\n totalResults: filtered.length,\n startIndex: listRequest.startIndex,\n itemsPerPage: paged.length,\n });\n };\n\n const handleUsersPost: ScimHandler = async (state) => {\n const body = await readScimJson(state.request);\n const primaryEmail = Array.isArray(body.emails)\n ? (body.emails.find((entry) => entry.primary === true)?.value ??\n body.emails[0]?.value)\n : undefined;\n const phone = Array.isArray(body.phoneNumbers)\n ? body.phoneNumbers[0]?.value\n : undefined;\n const userId = (await state.ctx.runMutation(\n config.component.public.userInsert,\n {\n data: {\n name: body.displayName ?? body.name?.formatted,\n email: primaryEmail ?? body.userName,\n ...(typeof (primaryEmail ?? body.userName) === \"string\"\n ? { emailVerificationTime: Date.now() }\n : {}),\n phone,\n ...(typeof phone === \"string\"\n ? { phoneVerificationTime: Date.now() }\n : {}),\n },\n },\n )) as string;\n try {\n await auth.member.create(state.ctx, {\n groupId: state.enterprise.groupId,\n userId,\n roleIds: state.policy.provisioning.jit.defaultRoleIds,\n status: body.active === false ? \"inactive\" : \"active\",\n });\n } catch {}\n if (typeof body.externalId === \"string\") {\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityUpsert,\n {\n enterpriseId: state.enterprise._id,\n groupId: state.enterprise.groupId,\n resourceType: \"user\",\n externalId: body.externalId,\n userId,\n active: body.active !== false,\n raw: body,\n lastProvisionedAt: Date.now(),\n },\n );\n }\n await state.recordScimEvent(\n \"enterprise.scim.user.created\",\n true,\n \"user\",\n userId,\n );\n const createdUser = await auth.user.get(state.ctx, userId);\n const location = `${state.url.origin}${state.url.pathname}/${userId}`;\n return scimJson(\n serializeScimUser({\n id: userId,\n user: createdUser ?? {},\n externalId: body.externalId,\n location,\n active: body.active !== false,\n }),\n 201,\n { Location: location },\n );\n };\n\n const handleUsersUpsert: ScimHandler = async (state) => {\n const missing = requireScimResourceId(\n state.parsedPath.resourceId,\n \"User\",\n );\n if (missing) return missing;\n const userId = state.parsedPath.resourceId!;\n const existingUser = await auth.user.get(state.ctx, userId);\n if (!existingUser) {\n return scimError(404, \"notFound\", \"User not found.\");\n }\n const body = await readScimJson(state.request);\n const patchData: Record<string, unknown> = {};\n let nextActive: boolean | undefined;\n if (state.request.method === \"PUT\") {\n patchData.name = body.displayName ?? body.name?.formatted;\n patchData.email =\n body.userName ??\n (Array.isArray(body.emails) ? body.emails[0]?.value : undefined);\n patchData.phone = Array.isArray(body.phoneNumbers)\n ? body.phoneNumbers[0]?.value\n : undefined;\n if (typeof patchData.email === \"string\") {\n patchData.emailVerificationTime = Date.now();\n }\n if (typeof patchData.phone === \"string\") {\n patchData.phoneVerificationTime = Date.now();\n }\n } else {\n for (const operation of Array.isArray(body.Operations)\n ? body.Operations\n : []) {\n if (operation.path === \"active\") {\n nextActive = operation.value;\n }\n if (\n operation.path === \"displayName\" ||\n operation.path === \"name.formatted\"\n ) {\n patchData.name = operation.value;\n }\n if (\n operation.path === \"userName\" ||\n operation.path === \"emails.value\"\n ) {\n patchData.email = operation.value;\n if (typeof operation.value === \"string\") {\n patchData.emailVerificationTime = Date.now();\n }\n }\n if (operation.path === \"phoneNumbers.value\") {\n patchData.phone = operation.value;\n if (typeof operation.value === \"string\") {\n patchData.phoneVerificationTime = Date.now();\n }\n }\n }\n }\n await state.ctx.runMutation(config.component.public.userPatch, {\n userId,\n data: patchData,\n });\n const resolution = await auth.member.resolve(state.ctx, {\n groupId: state.enterprise.groupId,\n userId,\n });\n if (resolution.membership) {\n await auth.member.update(state.ctx, resolution.membership._id, {\n status:\n body.active === false || nextActive === false\n ? \"inactive\"\n : \"active\",\n });\n }\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityUpsert,\n {\n enterpriseId: state.enterprise._id,\n groupId: state.enterprise.groupId,\n resourceType: \"user\",\n externalId:\n typeof body.externalId === \"string\"\n ? body.externalId\n : ((\n await state.ctx.runQuery(\n config.component.public\n .enterpriseScimIdentityGetByEnterpriseAndUser,\n {\n enterpriseId: state.enterprise._id,\n userId,\n },\n )\n )?.externalId ?? userId),\n userId,\n active: body.active !== false && nextActive !== false,\n raw: body,\n lastProvisionedAt: Date.now(),\n },\n );\n await state.recordScimEvent(\n \"enterprise.scim.user.updated\",\n true,\n \"user\",\n userId,\n );\n const updatedUser = await auth.user.get(state.ctx, userId);\n const location = `${state.url.origin}${state.url.pathname}`;\n return scimJson(\n serializeScimUser({\n id: userId,\n user: updatedUser ?? existingUser,\n externalId:\n typeof body.externalId === \"string\" ? body.externalId : undefined,\n location,\n active: body.active !== false && nextActive !== false,\n }),\n 200,\n { Location: location },\n );\n };\n\n const handleUsersDelete: ScimHandler = async (state) => {\n const missing = requireScimResourceId(\n state.parsedPath.resourceId,\n \"User\",\n );\n if (missing) return missing;\n const userId = state.parsedPath.resourceId!;\n const resolution = await auth.member.resolve(state.ctx, {\n groupId: state.enterprise.groupId,\n userId,\n });\n if (resolution.membership) {\n await auth.member.delete(state.ctx, resolution.membership._id);\n }\n const identity = await state.ctx.runQuery(\n config.component.public.enterpriseScimIdentityGetByEnterpriseAndUser,\n {\n enterpriseId: state.enterprise._id,\n userId,\n },\n );\n if (identity) {\n if (state.policy.provisioning.deprovision.mode === \"hard\") {\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityDelete,\n { identityId: identity._id },\n );\n } else {\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityUpsert,\n {\n enterpriseId: identity.enterpriseId,\n groupId: identity.groupId,\n resourceType: identity.resourceType,\n externalId: identity.externalId,\n userId: identity.userId,\n mappedGroupId: identity.mappedGroupId,\n active: false,\n raw: identity.raw,\n lastProvisionedAt: Date.now(),\n },\n );\n }\n }\n await state.recordScimEvent(\n \"enterprise.scim.user.deleted\",\n true,\n \"user\",\n userId,\n );\n return new Response(null, { status: 204 });\n };\n\n const handleGroupsGet: ScimHandler = async (state) => {\n const groupsList = await auth.group.list(state.ctx, {\n where: { parentGroupId: state.enterprise.groupId },\n limit: 100,\n });\n const identities = await state.ctx.runQuery(\n config.component.public.enterpriseScimIdentityListByEnterprise,\n { enterpriseId: state.enterprise._id },\n );\n const identityByGroupId = new Map(\n identities\n .filter((identity: any) => identity.mappedGroupId !== undefined)\n .map((identity: any) => [identity.mappedGroupId, identity]),\n );\n const groups = groupsList.items.map((group: any) => ({\n group,\n identity: identityByGroupId.get(group._id),\n }));\n const listRequest = parseScimListRequest(state.url);\n const filtered = filterScimCollection<{\n group: any;\n identity?: any;\n }>(groups, listRequest.filter, {\n id: (item: { group: any }, value: string) => item.group._id === value,\n externalId: (item: { identity?: any }, value: string) =>\n item.identity?.externalId === value,\n displayName: (item: { group: any }, value: string) =>\n item.group.name === value,\n });\n if (state.parsedPath.resourceId) {\n const resource = filtered.find(\n ({ group }) => group._id === state.parsedPath.resourceId,\n );\n if (!resource) {\n return scimError(404, \"notFound\", \"Group not found.\");\n }\n const members = (\n await auth.member.list(state.ctx, {\n where: {\n groupId: resource.group._id,\n status: \"active\",\n },\n limit: 100,\n })\n ).items.map((member: any) => ({ value: member.userId }));\n const location = `${state.url.origin}${state.url.pathname.replace(/\\/[^/]+$/, \"\")}/${resource.group._id}`;\n return scimJson(\n serializeScimGroup({\n id: resource.group._id,\n group: resource.group,\n externalId: resource.identity?.externalId,\n location,\n members,\n }),\n 200,\n { Location: location },\n );\n }\n const paged = paginateScimCollection(filtered, listRequest);\n return scimJson({\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n Resources: paged.map(({ group, identity }) =>\n serializeScimGroup({\n id: group._id,\n group,\n externalId: identity?.externalId,\n location: `${state.url.origin}${state.url.pathname}/${group._id}`,\n }),\n ),\n totalResults: filtered.length,\n startIndex: listRequest.startIndex,\n itemsPerPage: paged.length,\n });\n };\n\n const handleGroupsPost: ScimHandler = async (state) => {\n const body = await readScimJson(state.request);\n const { groupId } = await auth.group.create(state.ctx, {\n name: String(body.displayName ?? \"Group\"),\n parentGroupId: state.enterprise.groupId,\n type: \"organization\",\n });\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityUpsert,\n {\n enterpriseId: state.enterprise._id,\n groupId: state.enterprise.groupId,\n resourceType: \"group\",\n externalId: body.externalId ?? groupId,\n mappedGroupId: groupId,\n active: true,\n raw: body,\n lastProvisionedAt: Date.now(),\n },\n );\n for (const member of Array.isArray(body.members) ? body.members : []) {\n try {\n await auth.member.create(state.ctx, {\n groupId,\n userId: String(member.value),\n roleIds: state.policy.provisioning.jit.defaultRoleIds,\n status: \"active\",\n });\n } catch {}\n }\n await state.recordScimEvent(\n \"enterprise.scim.group.created\",\n true,\n \"group\",\n groupId,\n );\n const group = await auth.group.get(state.ctx, groupId);\n const location = `${state.url.origin}${state.url.pathname}/${groupId}`;\n return scimJson(\n serializeScimGroup({\n id: groupId,\n group: group ?? {},\n externalId: body.externalId,\n location,\n members: (\n await auth.member.list(state.ctx, {\n where: { groupId, status: \"active\" },\n limit: 100,\n })\n ).items.map((member: any) => ({ value: member.userId })),\n }),\n 201,\n { Location: location },\n );\n };\n\n const handleGroupsPatch: ScimHandler = async (state) => {\n const missing = requireScimResourceId(\n state.parsedPath.resourceId,\n \"Group\",\n );\n if (missing) return missing;\n const groupId = state.parsedPath.resourceId!;\n const body = await readScimJson(state.request);\n for (const operation of Array.isArray(body.Operations)\n ? body.Operations\n : []) {\n if (operation.path === \"displayName\") {\n await auth.group.update(state.ctx, groupId, {\n name: operation.value,\n });\n }\n if (operation.path === \"members\" && operation.op === \"add\") {\n for (const member of Array.isArray(operation.value)\n ? operation.value\n : []) {\n try {\n await auth.member.create(state.ctx, {\n groupId,\n userId: String(member.value),\n roleIds: state.policy.provisioning.jit.defaultRoleIds,\n status: \"active\",\n });\n } catch {}\n }\n }\n if (operation.path === \"members\" && operation.op === \"replace\") {\n const currentMembers = (\n await auth.member.list(state.ctx, {\n where: { groupId, status: \"active\" },\n limit: 100,\n })\n ).items as Array<{ _id: string; userId: string }>;\n const currentUserIds = new Set<string>(\n currentMembers.map((member) => member.userId),\n );\n const nextUserIds = new Set<string>(\n (Array.isArray(operation.value) ? operation.value : []).map(\n (member: any) => String(member.value),\n ),\n );\n for (const member of currentMembers) {\n if (!nextUserIds.has(member.userId)) {\n await auth.member.delete(state.ctx, member._id);\n }\n }\n for (const userId of nextUserIds.values()) {\n if (!currentUserIds.has(userId)) {\n try {\n await auth.member.create(state.ctx, {\n groupId,\n userId,\n roleIds: state.policy.provisioning.jit.defaultRoleIds,\n status: \"active\",\n });\n } catch {}\n }\n }\n }\n if (\n typeof operation.path === \"string\" &&\n operation.op === \"remove\" &&\n operation.path.startsWith(\"members[\")\n ) {\n const match = operation.path.match(\n /^members\\[value eq \"([^\"]+)\"\\]$/,\n );\n const userId = match?.[1];\n if (userId) {\n const resolution = await auth.member.resolve(\n state.ctx,\n { groupId, userId },\n );\n if (resolution.membership) {\n await auth.member.delete(\n state.ctx,\n resolution.membership._id,\n );\n }\n }\n }\n }\n await state.recordScimEvent(\n \"enterprise.scim.group.updated\",\n true,\n \"group\",\n groupId,\n );\n const group = await auth.group.get(state.ctx, groupId);\n const location = `${state.url.origin}${state.url.pathname}`;\n const members = (\n await auth.member.list(state.ctx, {\n where: { groupId, status: \"active\" },\n limit: 100,\n })\n ).items as Array<{ userId: string }>;\n return scimJson(\n serializeScimGroup({\n id: groupId,\n group: group ?? {},\n location,\n members: members.map((member) => ({\n value: member.userId,\n })),\n }),\n 200,\n { Location: location },\n );\n };\n\n const handleGroupsDelete: ScimHandler = async (state) => {\n const missing = requireScimResourceId(\n state.parsedPath.resourceId,\n \"Group\",\n );\n if (missing) return missing;\n const groupId = state.parsedPath.resourceId!;\n await auth.group.delete(state.ctx, groupId);\n const identity = await state.ctx.runQuery(\n config.component.public.enterpriseScimIdentityGetByMappedGroup,\n { mappedGroupId: groupId },\n );\n if (identity) {\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityDelete,\n { identityId: identity._id },\n );\n }\n await state.recordScimEvent(\n \"enterprise.scim.group.deleted\",\n true,\n \"group\",\n groupId,\n );\n return new Response(null, { status: 204 });\n };\n\n const scimHandlers: Record<\n string,\n Partial<Record<string, ScimHandler>>\n > = {\n ServiceProviderConfig: {\n GET: async () =>\n scimJson({\n schemas: [\n \"urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig\",\n ],\n patch: { supported: true },\n bulk: {\n supported: false,\n maxOperations: 0,\n maxPayloadSize: 0,\n },\n filter: { supported: true, maxResults: 100 },\n changePassword: { supported: false },\n sort: { supported: false },\n etag: { supported: false },\n authenticationSchemes: [\n {\n type: \"oauthbearertoken\",\n name: \"Bearer Token\",\n description:\n \"Use the SCIM token generated by Convex Auth enterprise.\",\n },\n ],\n }),\n },\n Schemas: {\n GET: async (state) =>\n handleStaticScimCollection(\n SCIM_SCHEMAS,\n state.parsedPath.resourceId,\n {\n by: \"id\",\n notFound: \"Schema not found.\",\n },\n ),\n },\n ResourceTypes: {\n GET: async (state) =>\n handleStaticScimCollection(\n SCIM_RESOURCE_TYPES,\n state.parsedPath.resourceId,\n { by: \"name\", notFound: \"Resource type not found.\" },\n ),\n },\n Users: {\n GET: handleUsersGet,\n POST: handleUsersPost,\n PATCH: handleUsersUpsert,\n PUT: handleUsersUpsert,\n DELETE: handleUsersDelete,\n },\n Groups: {\n GET: handleGroupsGet,\n POST: handleGroupsPost,\n PATCH: handleGroupsPatch,\n DELETE: handleGroupsDelete,\n },\n };\n\n const handler =\n scimHandlers[state.parsedPath.resource]?.[state.request.method];\n return handler\n ? await handler(state)\n : scimError(404, \"notFound\", \"SCIM resource not found.\");\n } catch (error) {\n if (\n error instanceof Error &&\n error.message === \"Unsupported SCIM filter.\"\n ) {\n return scimError(400, \"invalidFilter\", error.message);\n }\n if (isAuthError(error)) {\n const code = error.data.code as string;\n const status =\n code === \"MISSING_BEARER_TOKEN\" || code === \"INVALID_API_KEY\"\n ? 401\n : 400;\n return scimError(status, code, error.data.message);\n }\n throw error;\n }\n };\n\n addSSORoutes(http, {\n routeBase: ENTERPRISE_CONTROL_ROUTE_BASE,\n convertErrorsToResponse,\n handleSamlMetadata: async (ctx, _request, runtimeRoute) => {\n const { loaded } = await loadActiveEnterpriseSamlOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n return new Response(\n createEnterpriseSamlMetadataXml({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: loaded.source,\n config: loaded.config,\n }),\n {\n status: 200,\n headers: { \"Content-Type\": \"application/xml\" },\n },\n );\n },\n handleSamlSignIn: async (ctx, request, runtimeRoute) => {\n const url = new URL(request.url);\n const verifier = url.searchParams.get(\"code\");\n if (!verifier) {\n throw new AuthError(\"OAUTH_MISSING_VERIFIER\").toConvexError();\n }\n const { loaded, enterprise } = await loadActiveEnterpriseSamlOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n const state = generateRandomString(24, INVITE_TOKEN_ALPHABET);\n const signInRequest = createEnterpriseSamlSignInRequest({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: { kind: \"enterprise\", id: enterprise._id },\n config: loaded.config,\n state,\n signature: `saml ${enterprise._id} pending ${state}`,\n redirectTo: url.searchParams.get(\"redirectTo\") ?? undefined,\n });\n const signature = `saml ${enterprise._id} ${signInRequest.requestId} ${state}`;\n await callVerifierSignature(ctx, { verifier, signature });\n const redirectTo = url.searchParams.get(\"redirectTo\");\n const redirectCookies =\n redirectTo !== null\n ? [\n redirectToParamCookie(\n enterpriseSamlProviderId(enterprise._id),\n redirectTo,\n ),\n ]\n : [];\n const relayState = encodeEnterpriseSamlRelayState({\n source: { kind: \"enterprise\", id: enterprise._id },\n signature,\n requestId: signInRequest.requestId,\n state,\n redirectTo: url.searchParams.get(\"redirectTo\") ?? undefined,\n });\n if (signInRequest.binding === \"redirect\" && signInRequest.redirectUrl) {\n const redirectUrl = new URL(signInRequest.redirectUrl);\n redirectUrl.searchParams.set(\"RelayState\", relayState);\n const headers = new Headers({\n Location: redirectUrl.toString(),\n });\n for (const { name, value, options } of redirectCookies as any) {\n headers.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return new Response(null, { status: 302, headers });\n }\n const response = createSamlPostBindingResponse({\n endpoint: signInRequest.post!.endpoint,\n parameter: \"SAMLRequest\",\n value: signInRequest.post!.value,\n relayState,\n });\n for (const { name, value, options } of redirectCookies as any) {\n response.headers.append(\n \"Set-Cookie\",\n serializeCookie(name, value, options),\n );\n }\n return response;\n },\n handleOidcSignIn: async (ctx, request, runtimeRoute) => {\n const url = new URL(request.url);\n const verifier = url.searchParams.get(\"code\");\n if (!verifier) {\n throw new AuthError(\"OAUTH_MISSING_VERIFIER\").toConvexError();\n }\n const { enterprise, oidc } = await loadEnterpriseOidcOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n const { providerId, provider, oauthConfig } =\n await createEnterpriseOidcRuntime({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n enterpriseId: enterprise._id,\n oidc,\n });\n const { redirect, cookies, signature } =\n await createOAuthAuthorizationURL(providerId, provider, oauthConfig);\n await callVerifierSignature(ctx, { verifier, signature });\n const redirectTo = url.searchParams.get(\"redirectTo\");\n const headers_ = new Headers({ Location: redirect });\n for (const { name, value, options } of [\n ...cookies,\n ...(redirectTo !== null\n ? [redirectToParamCookie(providerId, redirectTo)]\n : []),\n ] as any) {\n headers_.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return new Response(null, {\n status: 302,\n headers: headers_,\n });\n },\n handleOidcCallback: async (ctx, request, runtimeRoute) => {\n const url = new URL(request.url);\n const { enterprise, oidc } = await loadEnterpriseOidcOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n const { providerId, provider, oauthConfig } =\n await createEnterpriseOidcRuntime({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n enterpriseId: enterprise._id,\n oidc,\n });\n const cookies = getCookies(request);\n const maybeRedirectTo = useRedirectToParam(providerId, cookies);\n const destinationUrl = await redirectAbsoluteUrl(config, {\n redirectTo: maybeRedirectTo?.redirectTo,\n });\n const params = url.searchParams;\n const result = (await Fx.run(\n handleOAuthCallback(\n providerId,\n provider,\n oauthConfig,\n Object.fromEntries(params.entries()),\n cookies,\n ),\n )) as any;\n const extraFields = oidc.extraFields as\n | Record<string, string>\n | undefined;\n let profile = result.profile as Record<string, unknown>;\n if (extraFields && typeof profile === \"object\" && profile) {\n const extend: Record<string, unknown> = {};\n for (const [claimName, fieldName] of Object.entries(extraFields)) {\n if (claimName in profile) {\n extend[fieldName] = profile[claimName];\n }\n }\n if (Object.keys(extend).length > 0) {\n profile = { ...profile, extend };\n }\n }\n\n const verificationCode = await callUserOAuth(ctx, {\n provider: providerId,\n providerAccountId: result.providerAccountId,\n profile,\n signature: result.signature,\n accountExtend: {\n identity: {\n protocol: \"oidc\",\n enterpriseId: enterprise._id,\n subject: result.providerAccountId,\n issuer: typeof oidc.issuer === \"string\" ? oidc.issuer : undefined,\n discoveryUrl:\n typeof oidc.discoveryUrl === \"string\"\n ? oidc.discoveryUrl\n : undefined,\n },\n },\n });\n const headers = new Headers({\n Location: setURLSearchParam(destinationUrl, \"code\", verificationCode),\n });\n for (const { name, value, options } of result.cookies) {\n headers.append(\n \"Set-Cookie\",\n serializeCookie(name, value, options as any),\n );\n }\n if (maybeRedirectTo) {\n headers.append(\n \"Set-Cookie\",\n serializeCookie(\n maybeRedirectTo.updatedCookie.name,\n maybeRedirectTo.updatedCookie.value,\n maybeRedirectTo.updatedCookie.options as any,\n ),\n );\n }\n return new Response(null, { status: 302, headers });\n },\n handleSamlAcs,\n handleSamlSlo,\n handleScimRequest,\n scimError,\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"http.js","names":["serializeCookie","state"],"sources":["../../../src/server/enterprise/http.ts"],"sourcesContent":["import { Fx } from \"@robelest/fx\";\nimport { Cv } from \"@robelest/fx/convex\";\nimport type { GenericActionCtx, HttpRouter } from \"convex/server\";\nimport { ConvexError } from \"convex/values\";\nimport { serialize as serializeCookie } from \"cookie\";\n\nimport { redirectToParamCookie, useRedirectToParam } from \"../cookies\";\nimport { addSSORoutes, convertErrorsToResponse, getCookies } from \"../http\";\nimport type { SSORuntimeRoute } from \"../http\";\nimport { createOAuthAuthorizationURL, handleOAuthCallback } from \"../oauth\";\nimport { redirectAbsoluteUrl, setURLSearchParam } from \"../redirects\";\nimport { createEnterpriseOidcRuntime } from \"./oidc\";\nimport {\n createEnterpriseSamlMetadataXml,\n createEnterpriseSamlSignInRequest,\n createSamlPostBindingResponse,\n encodeEnterpriseSamlRelayState,\n parseEnterpriseSamlLoginResponse,\n parseEnterpriseSamlLogoutMessage,\n profileFromSamlExtract,\n validateEnterpriseSamlLoginRelayState,\n} from \"./saml\";\nimport {\n parseScimListRequest,\n scimError,\n scimJson,\n serializeScimGroup,\n serializeScimUser,\n} from \"./scim\";\nimport {\n enterpriseSamlProviderId,\n SCIM_GROUP_SCHEMA_ID,\n SCIM_USER_SCHEMA_ID,\n} from \"./shared\";\n\nexport type EnterpriseHttpRuntimeDeps = {\n http: HttpRouter;\n hasSSO: boolean;\n auth: any;\n config: any;\n routeBase: string;\n requireEnv: (name: string) => string;\n loadActiveEnterpriseSamlOrThrow: any;\n loadEnterpriseOidcOrThrow: any;\n getEnterpriseScimContext: any;\n getPolicyFromEnterprise: any;\n normalizeEnterprisePolicy: any;\n recordEnterpriseAuditEvent: any;\n emitEnterpriseWebhookDeliveries: any;\n generateRandomString: (length: number, alphabet: string) => string;\n inviteTokenAlphabet: string;\n callUserOAuth: any;\n callVerifierSignature: any;\n};\n\nexport function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {\n if (!deps.hasSSO) {\n return;\n }\n\n const {\n http,\n auth,\n config,\n requireEnv,\n loadActiveEnterpriseSamlOrThrow,\n loadEnterpriseOidcOrThrow,\n getEnterpriseScimContext,\n getPolicyFromEnterprise,\n recordEnterpriseAuditEvent,\n emitEnterpriseWebhookDeliveries,\n generateRandomString,\n inviteTokenAlphabet: INVITE_TOKEN_ALPHABET,\n callUserOAuth,\n callVerifierSignature,\n } = deps;\n const ENTERPRISE_CONTROL_ROUTE_BASE = deps.routeBase;\n\n type ScimState = {\n ctx: any;\n request: Request;\n url: URL;\n parsedPath: Awaited<\n ReturnType<typeof getEnterpriseScimContext>\n >[\"parsedPath\"];\n enterprise: Awaited<\n ReturnType<typeof getEnterpriseScimContext>\n >[\"enterprise\"];\n scimConfig: Awaited<\n ReturnType<typeof getEnterpriseScimContext>\n >[\"scimConfig\"];\n policy: any;\n recordScimEvent: (\n eventType: string,\n ok: boolean,\n subjectType: string,\n subjectId?: string,\n metadata?: Record<string, unknown>,\n ) => Promise<void>;\n };\n\n type ScimHandler = (state: ScimState) => Promise<Response>;\n\n const SCIM_SCHEMAS = [\n {\n id: SCIM_USER_SCHEMA_ID,\n name: \"User\",\n description: \"User Account\",\n attributes: [\n { name: \"userName\", type: \"string\", required: true },\n { name: \"displayName\", type: \"string\" },\n { name: \"active\", type: \"boolean\" },\n { name: \"emails\", type: \"complex\", multiValued: true },\n ],\n },\n {\n id: SCIM_GROUP_SCHEMA_ID,\n name: \"Group\",\n description: \"Group\",\n attributes: [\n { name: \"displayName\", type: \"string\", required: true },\n { name: \"members\", type: \"complex\", multiValued: true },\n ],\n },\n ] as const;\n\n const SCIM_RESOURCE_TYPES = [\n {\n id: \"User\",\n name: \"User\",\n endpoint: \"/Users\",\n schema: SCIM_USER_SCHEMA_ID,\n },\n {\n id: \"Group\",\n name: \"Group\",\n endpoint: \"/Groups\",\n schema: SCIM_GROUP_SCHEMA_ID,\n },\n ] as const;\n\n const handleStaticScimCollection = <T extends { id?: string; name?: string }>(\n items: readonly T[],\n resourceId: string | undefined,\n opts: { by: \"id\" | \"name\"; notFound: string },\n ) => {\n if (resourceId !== undefined) {\n const item = items.find(\n (entry) => entry[opts.by] === decodeURIComponent(resourceId),\n );\n return item ? scimJson(item) : scimError(404, \"notFound\", opts.notFound);\n }\n return scimJson({\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n Resources: items,\n totalResults: items.length,\n startIndex: 1,\n itemsPerPage: items.length,\n });\n };\n\n const filterScimCollection = <T>(\n items: T[],\n filter: ReturnType<typeof parseScimListRequest>[\"filter\"],\n filters: Record<string, (item: T, value: string) => boolean>,\n ) => {\n if (!filter) {\n return items;\n }\n const predicate = filters[filter.attribute];\n if (!predicate) {\n throw new Error(\"Unsupported SCIM filter.\");\n }\n return items.filter((item) => predicate(item, filter.value));\n };\n\n const paginateScimCollection = <T>(\n items: T[],\n listRequest: ReturnType<typeof parseScimListRequest>,\n ) => {\n const start = listRequest.startIndex - 1;\n return items.slice(start, start + listRequest.count);\n };\n\n const requireScimResourceId = (\n resourceId: string | undefined,\n label: string,\n ) => {\n if (!resourceId) {\n return scimError(400, \"invalidPath\", `${label} resource ID is required.`);\n }\n return null;\n };\n\n const readScimJson = async (request: Request) =>\n (await request.json()) as Record<string, any>;\n\n const handleSamlAcs = async (\n ctx: GenericActionCtx<any>,\n request: Request,\n runtimeRoute: SSORuntimeRoute,\n ) =>\n Fx.run(\n Fx.gen(function* () {\n yield* Fx.guard(\n runtimeRoute.protocol !== \"saml\" ||\n runtimeRoute.rest.length !== 1 ||\n runtimeRoute.rest[0] !== \"acs\",\n Cv.fail({\n code: \"INVALID_PARAMETERS\",\n message: \"Invalid enterprise runtime path.\",\n }),\n );\n\n const enterpriseId = runtimeRoute.enterpriseId;\n const { loaded, enterprise, saml } = yield* Fx.from({\n ok: () => loadActiveEnterpriseSamlOrThrow(ctx, enterpriseId),\n err: (e) => e,\n });\n\n const parsedResponse = yield* Fx.from({\n ok: () =>\n parseEnterpriseSamlLoginResponse({\n request,\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: { kind: \"enterprise\", id: enterprise._id },\n config: loaded.config,\n }),\n err: (e) =>\n Cv.error({\n code: \"OAUTH_PROVIDER_ERROR\",\n message: `SAML response parse failed: ${e instanceof Error ? e.message : String(e)}`,\n }),\n });\n\n yield* Fx.from({\n ok: () => {\n validateEnterpriseSamlLoginRelayState({\n relayState: parsedResponse.relayState,\n source: { kind: \"enterprise\", id: enterprise._id },\n inResponseTo:\n parsedResponse.parsed.extract?.response?.inResponseTo,\n });\n return Promise.resolve();\n },\n err: () =>\n Cv.error({\n code: \"OAUTH_INVALID_STATE\",\n message:\n \"SAML RelayState did not match the pending login request.\",\n }),\n });\n\n const { samlAttributes, samlSessionIndex, ...userProfile } =\n profileFromSamlExtract(\n parsedResponse.parsed.extract,\n saml.attributeMapping,\n );\n const profile = userProfile as Record<string, unknown> & {\n id: string;\n };\n\n const maybeRedirectTo = useRedirectToParam(\n enterpriseSamlProviderId(enterprise._id),\n getCookies(request),\n );\n\n const verificationCode = yield* Fx.from({\n ok: () =>\n callUserOAuth(ctx, {\n provider: enterpriseSamlProviderId(enterprise._id),\n providerAccountId: profile.id,\n profile,\n signature: parsedResponse.relayState.signature,\n accountExtend: {\n identity: {\n protocol: \"saml\",\n enterpriseId: enterprise._id,\n subject: profile.id,\n entityId:\n typeof saml.entityId === \"string\"\n ? saml.entityId\n : undefined,\n },\n saml: {\n attributes: samlAttributes,\n sessionIndex: samlSessionIndex,\n },\n },\n }),\n err: (e) => e,\n });\n\n const destinationUrl = yield* Fx.from({\n ok: () =>\n redirectAbsoluteUrl(config, {\n redirectTo:\n maybeRedirectTo?.redirectTo ??\n (typeof parsedResponse.relayState.redirectTo === \"string\"\n ? parsedResponse.relayState.redirectTo\n : undefined),\n }),\n err: (e) => e,\n });\n\n const vurl = setURLSearchParam(\n destinationUrl,\n \"code\",\n verificationCode,\n );\n const vheaders = new Headers({ Location: vurl });\n vheaders.set(\"Cache-Control\", \"must-revalidate\");\n for (const { name, value, options } of maybeRedirectTo !== null\n ? [maybeRedirectTo.updatedCookie]\n : []) {\n vheaders.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return new Response(null, { status: 302, headers: vheaders });\n }).pipe(Fx.recover((e) => Fx.fatal(e))),\n );\n\n const handleSamlSlo = async (\n ctx: GenericActionCtx<any>,\n request: Request,\n runtimeRoute: SSORuntimeRoute,\n ) => {\n if (\n runtimeRoute.protocol !== \"saml\" ||\n runtimeRoute.rest.length !== 1 ||\n runtimeRoute.rest[0] !== \"slo\"\n ) {\n throw Cv.error({\n code: \"INVALID_PARAMETERS\",\n message: \"Invalid enterprise runtime path.\",\n });\n }\n const { loaded, enterprise } = await loadActiveEnterpriseSamlOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n const parsedMessage = await parseEnterpriseSamlLogoutMessage({\n request,\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: { kind: \"enterprise\", id: enterprise._id },\n config: loaded.config,\n });\n if (parsedMessage.hasSamlRequest && parsedMessage.parsedRequest) {\n const responseContext = (\n parsedMessage.runtime.sp as any\n ).createLogoutResponse(\n parsedMessage.runtime.idp as any,\n parsedMessage.parsedRequest.extract,\n parsedMessage.binding as any,\n parsedMessage.relayState ?? \"\",\n ) as any;\n if (parsedMessage.binding === \"redirect\") {\n return new Response(null, {\n status: 302,\n headers: { Location: responseContext.context },\n });\n }\n return createSamlPostBindingResponse({\n endpoint: responseContext.entityEndpoint,\n parameter: \"SAMLResponse\",\n value: responseContext.context,\n relayState: parsedMessage.relayState,\n });\n }\n if (parsedMessage.hasSamlResponse) {\n return new Response(null, { status: 204 });\n }\n throw Cv.error({\n code: \"INVALID_PARAMETERS\",\n message: \"Missing SAML logout payload.\",\n });\n };\n\n const handleScimRequest = async (\n ctx: GenericActionCtx<any>,\n request: Request,\n ) => {\n try {\n const { scimConfig, enterprise, parsedPath } =\n await getEnterpriseScimContext(ctx, request);\n const url = new URL(request.url);\n const state: ScimState = {\n ctx,\n request,\n url,\n parsedPath,\n enterprise,\n scimConfig,\n policy: getPolicyFromEnterprise(enterprise),\n recordScimEvent: async (\n eventType,\n ok,\n subjectType,\n subjectId,\n metadata,\n ) => {\n const auditEventId = await recordEnterpriseAuditEvent(ctx, {\n enterpriseId: enterprise._id,\n groupId: enterprise.groupId,\n eventType,\n actorType: \"scim\",\n subjectType,\n subjectId,\n ok,\n metadata,\n });\n await emitEnterpriseWebhookDeliveries(ctx, {\n enterpriseId: enterprise._id,\n eventType,\n auditEventId,\n payload: {\n enterpriseId: enterprise._id,\n subjectId,\n metadata,\n },\n });\n },\n };\n\n const handleUsersGet: ScimHandler = async (state) => {\n const members = await auth.member.list(state.ctx, {\n where: { groupId: state.enterprise.groupId },\n limit: 100,\n });\n const identities = await state.ctx.runQuery(\n config.component.public.enterpriseScimIdentityListByEnterprise,\n { enterpriseId: state.enterprise._id },\n );\n const identityByUserId = new Map(\n identities\n .filter((identity: any) => identity.userId !== undefined)\n .map((identity: any) => [identity.userId, identity]),\n );\n const users = (\n await Promise.all(\n members.items.map(async (member: any) => {\n const user = await auth.user.get(state.ctx, member.userId);\n return user\n ? {\n user,\n member,\n identity: identityByUserId.get(user._id),\n }\n : null;\n }),\n )\n ).filter(Boolean) as Array<{\n user: any;\n member: any;\n identity?: any;\n }>;\n const listRequest = parseScimListRequest(state.url);\n const filtered = filterScimCollection(users, listRequest.filter, {\n id: (item: { user: any }, value: string) => item.user._id === value,\n externalId: (item: { identity?: any }, value: string) =>\n item.identity?.externalId === value,\n userName: (item: { user: any }, value: string) =>\n item.user.email === value,\n \"emails.value\": (item: { user: any }, value: string) =>\n item.user.email === value,\n active: (item: { identity?: any; member: any }, value: string) =>\n String(item.identity?.active ?? item.member.status === \"active\") ===\n value,\n });\n if (state.parsedPath.resourceId) {\n const resource = filtered.find(\n ({ user }) => user._id === state.parsedPath.resourceId,\n );\n return resource\n ? scimJson(\n serializeScimUser({\n id: resource.user._id,\n user: resource.user,\n externalId: resource.identity?.externalId,\n location: `${state.url.origin}${state.url.pathname.replace(/\\/[^/]+$/, \"\")}/${resource.user._id}`,\n active:\n resource.identity?.active ??\n resource.member.status === \"active\",\n }),\n 200,\n {\n Location: `${state.url.origin}${state.url.pathname.replace(/\\/[^/]+$/, \"\")}/${resource.user._id}`,\n },\n )\n : scimError(404, \"notFound\", \"User not found.\");\n }\n const paged = paginateScimCollection(filtered, listRequest);\n await state.recordScimEvent(\n \"enterprise.scim.read\",\n true,\n \"enterprise_scim\",\n state.scimConfig._id,\n );\n return scimJson({\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n Resources: paged.map(({ user, identity, member }) =>\n serializeScimUser({\n id: user._id,\n user,\n externalId: identity?.externalId,\n location: `${state.url.origin}${state.url.pathname}/${user._id}`,\n active: identity?.active ?? member.status === \"active\",\n }),\n ),\n totalResults: filtered.length,\n startIndex: listRequest.startIndex,\n itemsPerPage: paged.length,\n });\n };\n\n const handleUsersPost: ScimHandler = async (state) => {\n const body = await readScimJson(state.request);\n const primaryEmail = Array.isArray(body.emails)\n ? (body.emails.find((entry) => entry.primary === true)?.value ??\n body.emails[0]?.value)\n : undefined;\n const phone = Array.isArray(body.phoneNumbers)\n ? body.phoneNumbers[0]?.value\n : undefined;\n const userId = (await state.ctx.runMutation(\n config.component.public.userInsert,\n {\n data: {\n name: body.displayName ?? body.name?.formatted,\n email: primaryEmail ?? body.userName,\n ...(typeof (primaryEmail ?? body.userName) === \"string\"\n ? { emailVerificationTime: Date.now() }\n : {}),\n phone,\n ...(typeof phone === \"string\"\n ? { phoneVerificationTime: Date.now() }\n : {}),\n },\n },\n )) as string;\n try {\n await auth.member.create(state.ctx, {\n groupId: state.enterprise.groupId,\n userId,\n roleIds: state.policy.provisioning.jit.defaultRoleIds,\n status: body.active === false ? \"inactive\" : \"active\",\n });\n } catch {}\n if (typeof body.externalId === \"string\") {\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityUpsert,\n {\n enterpriseId: state.enterprise._id,\n groupId: state.enterprise.groupId,\n resourceType: \"user\",\n externalId: body.externalId,\n userId,\n active: body.active !== false,\n raw: body,\n lastProvisionedAt: Date.now(),\n },\n );\n }\n await state.recordScimEvent(\n \"enterprise.scim.user.created\",\n true,\n \"user\",\n userId,\n );\n const createdUser = await auth.user.get(state.ctx, userId);\n const location = `${state.url.origin}${state.url.pathname}/${userId}`;\n return scimJson(\n serializeScimUser({\n id: userId,\n user: createdUser ?? {},\n externalId: body.externalId,\n location,\n active: body.active !== false,\n }),\n 201,\n { Location: location },\n );\n };\n\n const handleUsersUpsert: ScimHandler = async (state) => {\n const missing = requireScimResourceId(\n state.parsedPath.resourceId,\n \"User\",\n );\n if (missing) return missing;\n const userId = state.parsedPath.resourceId!;\n const existingUser = await auth.user.get(state.ctx, userId);\n if (!existingUser) {\n return scimError(404, \"notFound\", \"User not found.\");\n }\n const body = await readScimJson(state.request);\n const patchData: Record<string, unknown> = {};\n let nextActive: boolean | undefined;\n if (state.request.method === \"PUT\") {\n patchData.name = body.displayName ?? body.name?.formatted;\n patchData.email =\n body.userName ??\n (Array.isArray(body.emails) ? body.emails[0]?.value : undefined);\n patchData.phone = Array.isArray(body.phoneNumbers)\n ? body.phoneNumbers[0]?.value\n : undefined;\n if (typeof patchData.email === \"string\") {\n patchData.emailVerificationTime = Date.now();\n }\n if (typeof patchData.phone === \"string\") {\n patchData.phoneVerificationTime = Date.now();\n }\n } else {\n for (const operation of Array.isArray(body.Operations)\n ? body.Operations\n : []) {\n if (operation.path === \"active\") {\n nextActive = operation.value;\n }\n if (\n operation.path === \"displayName\" ||\n operation.path === \"name.formatted\"\n ) {\n patchData.name = operation.value;\n }\n if (\n operation.path === \"userName\" ||\n operation.path === \"emails.value\"\n ) {\n patchData.email = operation.value;\n if (typeof operation.value === \"string\") {\n patchData.emailVerificationTime = Date.now();\n }\n }\n if (operation.path === \"phoneNumbers.value\") {\n patchData.phone = operation.value;\n if (typeof operation.value === \"string\") {\n patchData.phoneVerificationTime = Date.now();\n }\n }\n }\n }\n await state.ctx.runMutation(config.component.public.userPatch, {\n userId,\n data: patchData,\n });\n const resolution = await auth.member.inspect(state.ctx, {\n groupId: state.enterprise.groupId,\n userId,\n });\n if (resolution.membership) {\n await auth.member.update(state.ctx, resolution.membership._id, {\n status:\n body.active === false || nextActive === false\n ? \"inactive\"\n : \"active\",\n });\n }\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityUpsert,\n {\n enterpriseId: state.enterprise._id,\n groupId: state.enterprise.groupId,\n resourceType: \"user\",\n externalId:\n typeof body.externalId === \"string\"\n ? body.externalId\n : ((\n await state.ctx.runQuery(\n config.component.public\n .enterpriseScimIdentityGetByEnterpriseAndUser,\n {\n enterpriseId: state.enterprise._id,\n userId,\n },\n )\n )?.externalId ?? userId),\n userId,\n active: body.active !== false && nextActive !== false,\n raw: body,\n lastProvisionedAt: Date.now(),\n },\n );\n await state.recordScimEvent(\n \"enterprise.scim.user.updated\",\n true,\n \"user\",\n userId,\n );\n const updatedUser = await auth.user.get(state.ctx, userId);\n const location = `${state.url.origin}${state.url.pathname}`;\n return scimJson(\n serializeScimUser({\n id: userId,\n user: updatedUser ?? existingUser,\n externalId:\n typeof body.externalId === \"string\" ? body.externalId : undefined,\n location,\n active: body.active !== false && nextActive !== false,\n }),\n 200,\n { Location: location },\n );\n };\n\n const handleUsersDelete: ScimHandler = async (state) => {\n const missing = requireScimResourceId(\n state.parsedPath.resourceId,\n \"User\",\n );\n if (missing) return missing;\n const userId = state.parsedPath.resourceId!;\n const resolution = await auth.member.inspect(state.ctx, {\n groupId: state.enterprise.groupId,\n userId,\n });\n if (resolution.membership) {\n await auth.member.delete(state.ctx, resolution.membership._id);\n }\n const identity = await state.ctx.runQuery(\n config.component.public.enterpriseScimIdentityGetByEnterpriseAndUser,\n {\n enterpriseId: state.enterprise._id,\n userId,\n },\n );\n if (identity) {\n if (state.policy.provisioning.deprovision.mode === \"hard\") {\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityDelete,\n { identityId: identity._id },\n );\n } else {\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityUpsert,\n {\n enterpriseId: identity.enterpriseId,\n groupId: identity.groupId,\n resourceType: identity.resourceType,\n externalId: identity.externalId,\n userId: identity.userId,\n mappedGroupId: identity.mappedGroupId,\n active: false,\n raw: identity.raw,\n lastProvisionedAt: Date.now(),\n },\n );\n }\n }\n await state.recordScimEvent(\n \"enterprise.scim.user.deleted\",\n true,\n \"user\",\n userId,\n );\n return new Response(null, { status: 204 });\n };\n\n const handleGroupsGet: ScimHandler = async (state) => {\n const groupsList = await auth.group.list(state.ctx, {\n where: { parentGroupId: state.enterprise.groupId },\n limit: 100,\n });\n const identities = await state.ctx.runQuery(\n config.component.public.enterpriseScimIdentityListByEnterprise,\n { enterpriseId: state.enterprise._id },\n );\n const identityByGroupId = new Map(\n identities\n .filter((identity: any) => identity.mappedGroupId !== undefined)\n .map((identity: any) => [identity.mappedGroupId, identity]),\n );\n const groups = groupsList.items.map((group: any) => ({\n group,\n identity: identityByGroupId.get(group._id),\n }));\n const listRequest = parseScimListRequest(state.url);\n const filtered = filterScimCollection<{\n group: any;\n identity?: any;\n }>(groups, listRequest.filter, {\n id: (item: { group: any }, value: string) => item.group._id === value,\n externalId: (item: { identity?: any }, value: string) =>\n item.identity?.externalId === value,\n displayName: (item: { group: any }, value: string) =>\n item.group.name === value,\n });\n if (state.parsedPath.resourceId) {\n const resource = filtered.find(\n ({ group }) => group._id === state.parsedPath.resourceId,\n );\n if (!resource) {\n return scimError(404, \"notFound\", \"Group not found.\");\n }\n const members = (\n await auth.member.list(state.ctx, {\n where: {\n groupId: resource.group._id,\n status: \"active\",\n },\n limit: 100,\n })\n ).items.map((member: any) => ({ value: member.userId }));\n const location = `${state.url.origin}${state.url.pathname.replace(/\\/[^/]+$/, \"\")}/${resource.group._id}`;\n return scimJson(\n serializeScimGroup({\n id: resource.group._id,\n group: resource.group,\n externalId: resource.identity?.externalId,\n location,\n members,\n }),\n 200,\n { Location: location },\n );\n }\n const paged = paginateScimCollection(filtered, listRequest);\n return scimJson({\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n Resources: paged.map(({ group, identity }) =>\n serializeScimGroup({\n id: group._id,\n group,\n externalId: identity?.externalId,\n location: `${state.url.origin}${state.url.pathname}/${group._id}`,\n }),\n ),\n totalResults: filtered.length,\n startIndex: listRequest.startIndex,\n itemsPerPage: paged.length,\n });\n };\n\n const handleGroupsPost: ScimHandler = async (state) => {\n const body = await readScimJson(state.request);\n const { groupId } = await auth.group.create(state.ctx, {\n name: String(body.displayName ?? \"Group\"),\n parentGroupId: state.enterprise.groupId,\n type: \"organization\",\n });\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityUpsert,\n {\n enterpriseId: state.enterprise._id,\n groupId: state.enterprise.groupId,\n resourceType: \"group\",\n externalId: body.externalId ?? groupId,\n mappedGroupId: groupId,\n active: true,\n raw: body,\n lastProvisionedAt: Date.now(),\n },\n );\n for (const member of Array.isArray(body.members) ? body.members : []) {\n try {\n await auth.member.create(state.ctx, {\n groupId,\n userId: String(member.value),\n roleIds: state.policy.provisioning.jit.defaultRoleIds,\n status: \"active\",\n });\n } catch {}\n }\n await state.recordScimEvent(\n \"enterprise.scim.group.created\",\n true,\n \"group\",\n groupId,\n );\n const group = await auth.group.get(state.ctx, groupId);\n const location = `${state.url.origin}${state.url.pathname}/${groupId}`;\n return scimJson(\n serializeScimGroup({\n id: groupId,\n group: group ?? {},\n externalId: body.externalId,\n location,\n members: (\n await auth.member.list(state.ctx, {\n where: { groupId, status: \"active\" },\n limit: 100,\n })\n ).items.map((member: any) => ({ value: member.userId })),\n }),\n 201,\n { Location: location },\n );\n };\n\n const handleGroupsPatch: ScimHandler = async (state) => {\n const missing = requireScimResourceId(\n state.parsedPath.resourceId,\n \"Group\",\n );\n if (missing) return missing;\n const groupId = state.parsedPath.resourceId!;\n const body = await readScimJson(state.request);\n for (const operation of Array.isArray(body.Operations)\n ? body.Operations\n : []) {\n if (operation.path === \"displayName\") {\n await auth.group.update(state.ctx, groupId, {\n name: operation.value,\n });\n }\n if (operation.path === \"members\" && operation.op === \"add\") {\n for (const member of Array.isArray(operation.value)\n ? operation.value\n : []) {\n try {\n await auth.member.create(state.ctx, {\n groupId,\n userId: String(member.value),\n roleIds: state.policy.provisioning.jit.defaultRoleIds,\n status: \"active\",\n });\n } catch {}\n }\n }\n if (operation.path === \"members\" && operation.op === \"replace\") {\n const currentMembers = (\n await auth.member.list(state.ctx, {\n where: { groupId, status: \"active\" },\n limit: 100,\n })\n ).items as Array<{ _id: string; userId: string }>;\n const currentUserIds = new Set<string>(\n currentMembers.map((member) => member.userId),\n );\n const nextUserIds = new Set<string>(\n (Array.isArray(operation.value) ? operation.value : []).map(\n (member: any) => String(member.value),\n ),\n );\n for (const member of currentMembers) {\n if (!nextUserIds.has(member.userId)) {\n await auth.member.delete(state.ctx, member._id);\n }\n }\n for (const userId of nextUserIds.values()) {\n if (!currentUserIds.has(userId)) {\n try {\n await auth.member.create(state.ctx, {\n groupId,\n userId,\n roleIds: state.policy.provisioning.jit.defaultRoleIds,\n status: \"active\",\n });\n } catch {}\n }\n }\n }\n if (\n typeof operation.path === \"string\" &&\n operation.op === \"remove\" &&\n operation.path.startsWith(\"members[\")\n ) {\n const match = operation.path.match(\n /^members\\[value eq \"([^\"]+)\"\\]$/,\n );\n const userId = match?.[1];\n if (userId) {\n const resolution = await auth.member.inspect(state.ctx, {\n groupId,\n userId,\n });\n if (resolution.membership) {\n await auth.member.delete(state.ctx, resolution.membership._id);\n }\n }\n }\n }\n await state.recordScimEvent(\n \"enterprise.scim.group.updated\",\n true,\n \"group\",\n groupId,\n );\n const group = await auth.group.get(state.ctx, groupId);\n const location = `${state.url.origin}${state.url.pathname}`;\n const members = (\n await auth.member.list(state.ctx, {\n where: { groupId, status: \"active\" },\n limit: 100,\n })\n ).items as Array<{ userId: string }>;\n return scimJson(\n serializeScimGroup({\n id: groupId,\n group: group ?? {},\n location,\n members: members.map((member) => ({\n value: member.userId,\n })),\n }),\n 200,\n { Location: location },\n );\n };\n\n const handleGroupsDelete: ScimHandler = async (state) => {\n const missing = requireScimResourceId(\n state.parsedPath.resourceId,\n \"Group\",\n );\n if (missing) return missing;\n const groupId = state.parsedPath.resourceId!;\n await auth.group.delete(state.ctx, groupId);\n const identity = await state.ctx.runQuery(\n config.component.public.enterpriseScimIdentityGetByMappedGroup,\n { mappedGroupId: groupId },\n );\n if (identity) {\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityDelete,\n { identityId: identity._id },\n );\n }\n await state.recordScimEvent(\n \"enterprise.scim.group.deleted\",\n true,\n \"group\",\n groupId,\n );\n return new Response(null, { status: 204 });\n };\n\n const scimHandlers: Record<\n string,\n Partial<Record<string, ScimHandler>>\n > = {\n ServiceProviderConfig: {\n GET: async () =>\n scimJson({\n schemas: [\n \"urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig\",\n ],\n patch: { supported: true },\n bulk: {\n supported: false,\n maxOperations: 0,\n maxPayloadSize: 0,\n },\n filter: { supported: true, maxResults: 100 },\n changePassword: { supported: false },\n sort: { supported: false },\n etag: { supported: false },\n authenticationSchemes: [\n {\n type: \"oauthbearertoken\",\n name: \"Bearer Token\",\n description:\n \"Use the SCIM token generated by Convex Auth enterprise.\",\n },\n ],\n }),\n },\n Schemas: {\n GET: async (state) =>\n handleStaticScimCollection(\n SCIM_SCHEMAS,\n state.parsedPath.resourceId,\n {\n by: \"id\",\n notFound: \"Schema not found.\",\n },\n ),\n },\n ResourceTypes: {\n GET: async (state) =>\n handleStaticScimCollection(\n SCIM_RESOURCE_TYPES,\n state.parsedPath.resourceId,\n { by: \"name\", notFound: \"Resource type not found.\" },\n ),\n },\n Users: {\n GET: handleUsersGet,\n POST: handleUsersPost,\n PATCH: handleUsersUpsert,\n PUT: handleUsersUpsert,\n DELETE: handleUsersDelete,\n },\n Groups: {\n GET: handleGroupsGet,\n POST: handleGroupsPost,\n PATCH: handleGroupsPatch,\n DELETE: handleGroupsDelete,\n },\n };\n\n const handler =\n scimHandlers[state.parsedPath.resource]?.[state.request.method];\n return handler\n ? await handler(state)\n : scimError(404, \"notFound\", \"SCIM resource not found.\");\n } catch (error) {\n if (\n error instanceof Error &&\n error.message === \"Unsupported SCIM filter.\"\n ) {\n return scimError(400, \"invalidFilter\", error.message);\n }\n if (\n error instanceof ConvexError &&\n typeof error.data === \"object\" &&\n error.data !== null &&\n \"code\" in error.data &&\n \"message\" in error.data\n ) {\n const code = error.data.code as string;\n const status =\n code === \"MISSING_BEARER_TOKEN\" || code === \"INVALID_API_KEY\"\n ? 401\n : 400;\n return scimError(status, code, error.data.message);\n }\n throw error;\n }\n };\n\n addSSORoutes(http, {\n routeBase: ENTERPRISE_CONTROL_ROUTE_BASE,\n convertErrorsToResponse,\n handleSamlMetadata: async (ctx, _request, runtimeRoute) => {\n const { loaded } = await loadActiveEnterpriseSamlOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n return new Response(\n createEnterpriseSamlMetadataXml({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: loaded.source,\n config: loaded.config,\n }),\n {\n status: 200,\n headers: { \"Content-Type\": \"application/xml\" },\n },\n );\n },\n handleSamlSignIn: async (ctx, request, runtimeRoute) => {\n const url = new URL(request.url);\n const verifier = url.searchParams.get(\"code\");\n if (!verifier) {\n throw Cv.error({\n code: \"OAUTH_MISSING_VERIFIER\",\n message: \"Missing sign-in verifier.\",\n });\n }\n const { loaded, enterprise } = await loadActiveEnterpriseSamlOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n const state = generateRandomString(24, INVITE_TOKEN_ALPHABET);\n const signInRequest = createEnterpriseSamlSignInRequest({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: { kind: \"enterprise\", id: enterprise._id },\n config: loaded.config,\n state,\n signature: `saml ${enterprise._id} pending ${state}`,\n redirectTo: url.searchParams.get(\"redirectTo\") ?? undefined,\n });\n const signature = `saml ${enterprise._id} ${signInRequest.requestId} ${state}`;\n await callVerifierSignature(ctx, { verifier, signature });\n const redirectTo = url.searchParams.get(\"redirectTo\");\n const redirectCookies =\n redirectTo !== null\n ? [\n redirectToParamCookie(\n enterpriseSamlProviderId(enterprise._id),\n redirectTo,\n ),\n ]\n : [];\n const relayState = encodeEnterpriseSamlRelayState({\n source: { kind: \"enterprise\", id: enterprise._id },\n signature,\n requestId: signInRequest.requestId,\n state,\n redirectTo: url.searchParams.get(\"redirectTo\") ?? undefined,\n });\n if (signInRequest.binding === \"redirect\" && signInRequest.redirectUrl) {\n const redirectUrl = new URL(signInRequest.redirectUrl);\n redirectUrl.searchParams.set(\"RelayState\", relayState);\n const headers = new Headers({\n Location: redirectUrl.toString(),\n });\n for (const { name, value, options } of redirectCookies as any) {\n headers.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return new Response(null, { status: 302, headers });\n }\n const response = createSamlPostBindingResponse({\n endpoint: signInRequest.post!.endpoint,\n parameter: \"SAMLRequest\",\n value: signInRequest.post!.value,\n relayState,\n });\n for (const { name, value, options } of redirectCookies as any) {\n response.headers.append(\n \"Set-Cookie\",\n serializeCookie(name, value, options),\n );\n }\n return response;\n },\n handleOidcSignIn: async (ctx, request, runtimeRoute) => {\n const url = new URL(request.url);\n const verifier = url.searchParams.get(\"code\");\n if (!verifier) {\n throw Cv.error({\n code: \"OAUTH_MISSING_VERIFIER\",\n message: \"Missing sign-in verifier.\",\n });\n }\n const { enterprise, oidc } = await loadEnterpriseOidcOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n const { providerId, provider, oauthConfig } =\n await createEnterpriseOidcRuntime({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n enterpriseId: enterprise._id,\n oidc,\n });\n const { redirect, cookies, signature } =\n await createOAuthAuthorizationURL(providerId, provider, oauthConfig);\n await callVerifierSignature(ctx, { verifier, signature });\n const redirectTo = url.searchParams.get(\"redirectTo\");\n const headers_ = new Headers({ Location: redirect });\n for (const { name, value, options } of [\n ...cookies,\n ...(redirectTo !== null\n ? [redirectToParamCookie(providerId, redirectTo)]\n : []),\n ] as any) {\n headers_.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return new Response(null, {\n status: 302,\n headers: headers_,\n });\n },\n handleOidcCallback: async (ctx, request, runtimeRoute) => {\n const url = new URL(request.url);\n const { enterprise, oidc } = await loadEnterpriseOidcOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n const { providerId, provider, oauthConfig } =\n await createEnterpriseOidcRuntime({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n enterpriseId: enterprise._id,\n oidc,\n });\n const cookies = getCookies(request);\n const maybeRedirectTo = useRedirectToParam(providerId, cookies);\n const destinationUrl = await redirectAbsoluteUrl(config, {\n redirectTo: maybeRedirectTo?.redirectTo,\n });\n const params = url.searchParams;\n const result = (await Fx.run(\n handleOAuthCallback(\n providerId,\n provider,\n oauthConfig,\n Object.fromEntries(params.entries()),\n cookies,\n ),\n )) as any;\n const extraFields = oidc.extraFields as\n | Record<string, string>\n | undefined;\n let profile = result.profile as Record<string, unknown>;\n if (extraFields && typeof profile === \"object\" && profile) {\n const extend: Record<string, unknown> = {};\n for (const [claimName, fieldName] of Object.entries(extraFields)) {\n if (claimName in profile) {\n extend[fieldName] = profile[claimName];\n }\n }\n if (Object.keys(extend).length > 0) {\n profile = { ...profile, extend };\n }\n }\n\n const verificationCode = await callUserOAuth(ctx, {\n provider: providerId,\n providerAccountId: result.providerAccountId,\n profile,\n signature: result.signature,\n accountExtend: {\n identity: {\n protocol: \"oidc\",\n enterpriseId: enterprise._id,\n subject: result.providerAccountId,\n issuer: typeof oidc.issuer === \"string\" ? oidc.issuer : undefined,\n discoveryUrl:\n typeof oidc.discoveryUrl === \"string\"\n ? oidc.discoveryUrl\n : undefined,\n },\n },\n });\n const headers = new Headers({\n Location: setURLSearchParam(destinationUrl, \"code\", verificationCode),\n });\n for (const { name, value, options } of result.cookies) {\n headers.append(\n \"Set-Cookie\",\n serializeCookie(name, value, options as any),\n );\n }\n if (maybeRedirectTo) {\n headers.append(\n \"Set-Cookie\",\n serializeCookie(\n maybeRedirectTo.updatedCookie.name,\n maybeRedirectTo.updatedCookie.value,\n maybeRedirectTo.updatedCookie.options as any,\n ),\n );\n }\n return new Response(null, { status: 302, headers });\n },\n handleSamlAcs,\n handleSamlSlo,\n handleScimRequest,\n scimError,\n });\n}\n"],"mappings":"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"}
|
package/dist/server/http.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CorsConfig, HttpKeyContext } from "./types.js";
|
|
2
|
-
import * as
|
|
2
|
+
import * as convex_server62 from "convex/server";
|
|
3
3
|
import { GenericActionCtx, GenericDataModel, HttpRouter } from "convex/server";
|
|
4
4
|
|
|
5
5
|
//#region src/server/http.d.ts
|
|
@@ -13,7 +13,7 @@ declare function createHttpAction(auth: {
|
|
|
13
13
|
action: string;
|
|
14
14
|
};
|
|
15
15
|
cors?: CorsConfig;
|
|
16
|
-
}) =>
|
|
16
|
+
}) => convex_server62.PublicHttpAction;
|
|
17
17
|
declare function createHttpRoute(wrapAction: ReturnType<typeof createHttpAction>): (http: {
|
|
18
18
|
route: (config: any) => void;
|
|
19
19
|
}, routeConfig: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","names":[],"sources":["../../src/server/http.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"http.d.ts","names":[],"sources":["../../src/server/http.ts"],"mappings":";;;;;iBAcgB,gBAAA,CAAiB,IAAA;EAC/B,GAAA;IAAO,MAAA,GAAS,GAAA,EAAK,gBAAA,OAAuB,MAAA,aAAmB,OAAA;EAAA;AAAA,KAG7D,OAAA,GACE,GAAA,EAAK,gBAAA,CAAiB,gBAAA,IAAoB,cAAA,EAC1C,OAAA,EAAS,OAAA,KACN,OAAA,CAAQ,QAAA,GAAW,MAAA,oBACxB,OAAA;EACE,KAAA;IAAU,QAAA;IAAkB,MAAA;EAAA;EAC5B,IAAA,GAAO,UAAA;AAAA,MAAU,eAAA,CAClB,gBAAA;AAAA,iBA6IW,eAAA,CACd,UAAA,EAAY,UAAA,QAAkB,gBAAA,KAG5B,IAAA;EAAQ,KAAA,GAAQ,MAAA;AAAA,GAChB,WAAA;EACE,IAAA;EACA,MAAA;EACA,OAAA,GACE,GAAA,EAAK,gBAAA,CAAiB,gBAAA,IAAoB,cAAA,EAC1C,OAAA,EAAS,OAAA,KACN,OAAA,CAAQ,QAAA,GAAW,MAAA;EACxB,KAAA;IAAU,QAAA;IAAkB,MAAA;EAAA;EAC5B,IAAA,GAAO,UAAA;AAAA;AAAA,iBA+BG,uBAAA,CACd,eAAA,UACA,MAAA,GAAS,GAAA,EAAK,gBAAA,OAAuB,OAAA,EAAS,OAAA,KAAY,OAAA,CAAQ,QAAA,KAEpD,GAAA,EAAK,gBAAA,OAAuB,OAAA,EAAS,OAAA,KAAO,OAAA,CAAA,QAAA;AAAA,iBAiD5C,UAAA,CACd,OAAA,EAAS,OAAA,GACR,MAAA;AAAA,KAIS,eAAA;EACV,QAAA;EACA,YAAA;EACA,QAAA;EACA,IAAA;AAAA;AAAA,iBA2Bc,eAAA,CACd,IAAA,EAAM,UAAA,EACN,IAAA;EACE,SAAA;EACA,OAAA;AAAA;AAAA,iBA0CY,aAAA,CACd,IAAA,EAAM,UAAA,EACN,IAAA;EACE,YAAA,GACE,GAAA,EAAK,gBAAA,OACL,OAAA,EAAS,OAAA,KACN,OAAA,CAAQ,QAAA;EACb,cAAA,GACE,GAAA,EAAK,gBAAA,OACL,OAAA,EAAS,OAAA,KACN,OAAA,CAAQ,QAAA;AAAA;AAAA,iBAwBD,YAAA,CACd,IAAA,EAAM,UAAA,EACN,IAAA;EACE,SAAA;EACA,uBAAA,SAAgC,uBAAA;EAChC,kBAAA,GACE,GAAA,EAAK,gBAAA,OACL,OAAA,EAAS,OAAA,EACT,KAAA,EAAO,eAAA,KACJ,OAAA,CAAQ,QAAA;EACb,gBAAA,GACE,GAAA,EAAK,gBAAA,OACL,OAAA,EAAS,OAAA,EACT,KAAA,EAAO,eAAA,KACJ,OAAA,CAAQ,QAAA;EACb,gBAAA,GACE,GAAA,EAAK,gBAAA,OACL,OAAA,EAAS,OAAA,EACT,KAAA,EAAO,eAAA,KACJ,OAAA,CAAQ,QAAA;EACb,kBAAA,GACE,GAAA,EAAK,gBAAA,OACL,OAAA,EAAS,OAAA,EACT,KAAA,EAAO,eAAA,KACJ,OAAA,CAAQ,QAAA;EACb,aAAA,GACE,GAAA,EAAK,gBAAA,OACL,OAAA,EAAS,OAAA,EACT,KAAA,EAAO,eAAA,KACJ,OAAA,CAAQ,QAAA;EACb,aAAA,GACE,GAAA,EAAK,gBAAA,OACL,OAAA,EAAS,OAAA,EACT,KAAA,EAAO,eAAA,KACJ,OAAA,CAAQ,QAAA;EACb,iBAAA,GACE,GAAA,EAAK,gBAAA,OACL,OAAA,EAAS,OAAA,KACN,OAAA,CAAQ,QAAA;EACb,SAAA,GAAY,MAAA,UAAgB,QAAA,UAAkB,MAAA,aAAmB,QAAA;AAAA"}
|
package/dist/server/http.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { isAuthError } from "./errors.js";
|
|
2
|
-
import { AuthError } from "./authError.js";
|
|
3
1
|
import { logError } from "./utils.js";
|
|
4
2
|
import { Fx } from "@robelest/fx";
|
|
3
|
+
import { Cv } from "@robelest/fx/convex";
|
|
5
4
|
import { httpActionGeneric } from "convex/server";
|
|
6
5
|
import { ConvexError } from "convex/values";
|
|
7
6
|
import { parse } from "cookie";
|
|
@@ -30,21 +29,15 @@ function createHttpAction(auth) {
|
|
|
30
29
|
}
|
|
31
30
|
});
|
|
32
31
|
const rawKey = authHeader.slice(7);
|
|
33
|
-
const keyResult = await Fx.run(Fx.
|
|
34
|
-
ok:
|
|
35
|
-
|
|
36
|
-
})
|
|
37
|
-
ok:
|
|
38
|
-
|
|
39
|
-
value: result$1
|
|
40
|
-
}),
|
|
41
|
-
err: (error) => ({
|
|
42
|
-
ok: false,
|
|
43
|
-
error
|
|
44
|
-
})
|
|
32
|
+
const keyResult = await Fx.run(Fx.attempt(() => auth.key.verify(genericCtx, rawKey), (result$1) => ({
|
|
33
|
+
ok: true,
|
|
34
|
+
value: result$1
|
|
35
|
+
}), (error) => ({
|
|
36
|
+
ok: false,
|
|
37
|
+
error
|
|
45
38
|
})));
|
|
46
39
|
if (!keyResult.ok) {
|
|
47
|
-
if (
|
|
40
|
+
if (keyResult.error instanceof ConvexError && typeof keyResult.error.data === "object" && keyResult.error.data !== null && "code" in keyResult.error.data && "message" in keyResult.error.data) {
|
|
48
41
|
const { code, message } = keyResult.error.data;
|
|
49
42
|
return new Response(JSON.stringify({
|
|
50
43
|
error: message,
|
|
@@ -142,7 +135,7 @@ function convertErrorsToResponse(errorStatusCode, action) {
|
|
|
142
135
|
ok: () => action(ctx, request),
|
|
143
136
|
err: (error) => error
|
|
144
137
|
}).pipe(Fx.recover((error) => {
|
|
145
|
-
if (
|
|
138
|
+
if (error instanceof ConvexError && typeof error.data === "object" && error.data !== null && "code" in error.data && "message" in error.data) return Fx.succeed(new Response(JSON.stringify({
|
|
146
139
|
code: error.data.code,
|
|
147
140
|
message: error.data.message
|
|
148
141
|
}), {
|
|
@@ -235,7 +228,10 @@ function addSSORoutes(http, deps) {
|
|
|
235
228
|
method: "GET",
|
|
236
229
|
handler: httpActionGeneric(deps.convertErrorsToResponse(400, async (ctx, request) => {
|
|
237
230
|
const route = parseEnterpriseRuntimeRoute(new URL(request.url).pathname, deps.routeBase);
|
|
238
|
-
if (!route) throw
|
|
231
|
+
if (!route) throw Cv.error({
|
|
232
|
+
code: "INVALID_PARAMETERS",
|
|
233
|
+
message: "Invalid enterprise runtime path."
|
|
234
|
+
});
|
|
239
235
|
if (route.protocol === "saml" && route.rest.length === 1) {
|
|
240
236
|
if (route.rest[0] === "metadata") return await deps.handleSamlMetadata(ctx, request, route);
|
|
241
237
|
if (route.rest[0] === "signin") return await deps.handleSamlSignIn(ctx, request, route);
|
|
@@ -247,7 +243,10 @@ function addSSORoutes(http, deps) {
|
|
|
247
243
|
if (route.rest[0] === "callback") return await deps.handleOidcCallback(ctx, request, route);
|
|
248
244
|
}
|
|
249
245
|
if (route.protocol === "scim" && route.rest[0] === "v2") return await deps.handleScimRequest(ctx, request);
|
|
250
|
-
throw
|
|
246
|
+
throw Cv.error({
|
|
247
|
+
code: "INVALID_PARAMETERS",
|
|
248
|
+
message: "Invalid enterprise runtime path."
|
|
249
|
+
});
|
|
251
250
|
}))
|
|
252
251
|
});
|
|
253
252
|
http.route({
|
|
@@ -260,7 +259,10 @@ function addSSORoutes(http, deps) {
|
|
|
260
259
|
if (route.rest[0] === "slo") return await deps.handleSamlSlo(ctx, request, route);
|
|
261
260
|
}
|
|
262
261
|
if (route?.protocol === "scim" && route.rest[0] === "v2") return await deps.handleScimRequest(ctx, request);
|
|
263
|
-
throw
|
|
262
|
+
throw Cv.error({
|
|
263
|
+
code: "INVALID_PARAMETERS",
|
|
264
|
+
message: "Invalid enterprise runtime path."
|
|
265
|
+
});
|
|
264
266
|
}))
|
|
265
267
|
});
|
|
266
268
|
http.route({
|
|
@@ -269,7 +271,10 @@ function addSSORoutes(http, deps) {
|
|
|
269
271
|
handler: httpActionGeneric(deps.convertErrorsToResponse(400, async (ctx, request) => {
|
|
270
272
|
const route = parseEnterpriseRuntimeRoute(new URL(request.url).pathname, deps.routeBase);
|
|
271
273
|
if (route?.protocol === "scim" && route.rest[0] === "v2") return await deps.handleScimRequest(ctx, request);
|
|
272
|
-
throw
|
|
274
|
+
throw Cv.error({
|
|
275
|
+
code: "INVALID_PARAMETERS",
|
|
276
|
+
message: "Invalid enterprise runtime path."
|
|
277
|
+
});
|
|
273
278
|
}))
|
|
274
279
|
});
|
|
275
280
|
for (const method of ["PATCH", "DELETE"]) http.route({
|
package/dist/server/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","names":["result","parseCookies"],"sources":["../../src/server/http.ts"],"sourcesContent":["import {\n GenericActionCtx,\n GenericDataModel,\n HttpRouter,\n httpActionGeneric,\n} from \"convex/server\";\nimport { ConvexError } from \"convex/values\";\nimport { parse as parseCookies } from \"cookie\";\n\nimport { isAuthError } from \"./errors\";\nimport { Fx } from \"@robelest/fx\";\n\nimport { AuthError } from \"./authError\";\nimport type { CorsConfig, HttpKeyContext } from \"./types\";\nimport { logError } from \"./utils\";\n\nexport function createHttpAction(auth: {\n key: { verify: (ctx: GenericActionCtx<any>, rawKey: string) => Promise<any> };\n}) {\n return (\n handler: (\n ctx: GenericActionCtx<GenericDataModel> & HttpKeyContext,\n request: Request,\n ) => Promise<Response | Record<string, unknown>>,\n options?: {\n scope?: { resource: string; action: string };\n cors?: CorsConfig;\n },\n ) => {\n const corsConfig = options?.cors ?? {};\n const corsHeaders: Record<string, string> = {\n \"Access-Control-Allow-Origin\": corsConfig.origin ?? \"*\",\n \"Access-Control-Allow-Methods\":\n corsConfig.methods ?? \"GET,POST,PUT,PATCH,DELETE,OPTIONS\",\n \"Access-Control-Allow-Headers\":\n corsConfig.headers ?? \"Content-Type,Authorization\",\n };\n\n return httpActionGeneric(async (genericCtx, request) => {\n return Fx.run(\n Fx.from({\n ok: async () => {\n const authHeader = request.headers.get(\"Authorization\");\n if (!authHeader?.startsWith(\"Bearer \")) {\n return new Response(\n JSON.stringify({\n error: \"Missing or malformed Authorization: Bearer header.\",\n code: \"MISSING_BEARER_TOKEN\",\n }),\n {\n status: 401,\n headers: {\n ...corsHeaders,\n \"Content-Type\": \"application/json\",\n },\n },\n );\n }\n const rawKey = authHeader.slice(7);\n\n const keyResult = await Fx.run(\n Fx.from({\n ok: () => auth.key.verify(genericCtx, rawKey),\n err: (error) => error,\n }).pipe(\n Fx.fold({\n ok: (result) => ({ ok: true, value: result }) as const,\n err: (error) => ({ ok: false, error }) as const,\n }),\n ),\n );\n\n if (!keyResult.ok) {\n if (isAuthError(keyResult.error)) {\n const { code, message } = keyResult.error.data as {\n code: string;\n message: string;\n };\n return new Response(JSON.stringify({ error: message, code }), {\n status: 403,\n headers: {\n ...corsHeaders,\n \"Content-Type\": \"application/json\",\n },\n });\n }\n throw keyResult.error;\n }\n\n if (\n options?.scope &&\n !keyResult.value.scopes.can(\n options.scope.resource,\n options.scope.action,\n )\n ) {\n return new Response(\n JSON.stringify({\n error: \"This API key does not have the required permissions.\",\n code: \"SCOPE_CHECK_FAILED\",\n }),\n {\n status: 403,\n headers: {\n ...corsHeaders,\n \"Content-Type\": \"application/json\",\n },\n },\n );\n }\n\n const enrichedCtx = Object.assign(genericCtx, {\n key: {\n userId: keyResult.value.userId,\n keyId: keyResult.value.keyId,\n scopes: keyResult.value.scopes,\n },\n });\n const result = await handler(enrichedCtx, request);\n\n if (result instanceof Response) {\n const headers = new Headers(result.headers);\n for (const [k, val] of Object.entries(corsHeaders)) {\n if (!headers.has(k)) headers.set(k, val);\n }\n return new Response(result.body, {\n status: result.status,\n statusText: result.statusText,\n headers,\n });\n }\n\n return new Response(JSON.stringify(result), {\n status: 200,\n headers: {\n ...corsHeaders,\n \"Content-Type\": \"application/json\",\n },\n });\n },\n err: (error) => error,\n }).pipe(\n Fx.recover((error) => {\n logError(error);\n return Fx.succeed(\n new Response(\n JSON.stringify({\n error: \"An unexpected error occurred.\",\n code: \"INTERNAL_ERROR\",\n }),\n {\n status: 500,\n headers: {\n ...corsHeaders,\n \"Content-Type\": \"application/json\",\n },\n },\n ),\n );\n }),\n ),\n );\n });\n };\n}\n\nexport function createHttpRoute(\n wrapAction: ReturnType<typeof createHttpAction>,\n) {\n return (\n http: { route: (config: any) => void },\n routeConfig: {\n path: string;\n method: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n handler: (\n ctx: GenericActionCtx<GenericDataModel> & HttpKeyContext,\n request: Request,\n ) => Promise<Response | Record<string, unknown>>;\n scope?: { resource: string; action: string };\n cors?: CorsConfig;\n },\n ) => {\n const corsConfig = routeConfig.cors ?? {};\n const corsHeaders: Record<string, string> = {\n \"Access-Control-Allow-Origin\": corsConfig.origin ?? \"*\",\n \"Access-Control-Allow-Methods\":\n corsConfig.methods ?? \"GET,POST,PUT,PATCH,DELETE,OPTIONS\",\n \"Access-Control-Allow-Headers\":\n corsConfig.headers ?? \"Content-Type,Authorization\",\n };\n\n http.route({\n path: routeConfig.path,\n method: \"OPTIONS\",\n handler: httpActionGeneric(async () => {\n return new Response(null, { status: 204, headers: corsHeaders });\n }),\n });\n\n http.route({\n path: routeConfig.path,\n method: routeConfig.method,\n handler: wrapAction(routeConfig.handler, {\n scope: routeConfig.scope,\n cors: routeConfig.cors,\n }),\n });\n };\n}\n\nexport function convertErrorsToResponse(\n errorStatusCode: number,\n action: (ctx: GenericActionCtx<any>, request: Request) => Promise<Response>,\n) {\n return async (ctx: GenericActionCtx<any>, request: Request) => {\n return Fx.run(\n Fx.from({\n ok: () => action(ctx, request),\n err: (error) => error,\n }).pipe(\n Fx.recover((error) => {\n if (isAuthError(error)) {\n return Fx.succeed(\n new Response(\n JSON.stringify({\n code: error.data.code,\n message: error.data.message,\n }),\n {\n status: errorStatusCode,\n headers: { \"Content-Type\": \"application/json\" },\n },\n ),\n );\n } else if (error instanceof ConvexError) {\n return Fx.succeed(\n new Response(null, {\n status: errorStatusCode,\n statusText:\n typeof error.data === \"string\" ? error.data : \"Error\",\n }),\n );\n } else {\n logError(error);\n return Fx.succeed(\n new Response(null, {\n status: 500,\n statusText: \"Internal Server Error\",\n }),\n );\n }\n }),\n ),\n );\n };\n}\n\nexport function getCookies(\n request: Request,\n): Record<string, string | undefined> {\n return parseCookies(request.headers.get(\"Cookie\") ?? \"\");\n}\n\nexport type SSORuntimeRoute = {\n pathname?: string;\n enterpriseId: string;\n protocol: \"oidc\" | \"saml\" | \"scim\";\n rest: string[];\n};\n\nfunction parseEnterpriseRuntimeRoute(\n pathname: string,\n routeBase: string,\n): SSORuntimeRoute | null {\n const runtimePrefix = `${routeBase}/`;\n const runtimeParts = pathname.startsWith(runtimePrefix)\n ? pathname.slice(runtimePrefix.length).split(\"/\").filter(Boolean)\n : [];\n const [runtimeEnterpriseId, protocol, ...rest] = runtimeParts;\n if (\n runtimeEnterpriseId === undefined ||\n (protocol !== \"oidc\" && protocol !== \"saml\" && protocol !== \"scim\") ||\n rest.length === 0\n ) {\n return null;\n }\n return {\n pathname,\n enterpriseId: runtimeEnterpriseId,\n protocol,\n rest,\n };\n}\n\nexport function addOpenIdRoutes(\n http: HttpRouter,\n deps: {\n getIssuer: () => string;\n getJwks: () => string;\n },\n) {\n const cacheControl =\n \"public, max-age=15, stale-while-revalidate=15, stale-if-error=86400\";\n\n http.route({\n path: \"/.well-known/openid-configuration\",\n method: \"GET\",\n handler: httpActionGeneric(async () => {\n const issuer = deps.getIssuer();\n return new Response(\n JSON.stringify({\n issuer,\n jwks_uri: `${issuer}/.well-known/jwks.json`,\n }),\n {\n status: 200,\n headers: {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": cacheControl,\n },\n },\n );\n }),\n });\n\n http.route({\n path: \"/.well-known/jwks.json\",\n method: \"GET\",\n handler: httpActionGeneric(async () => {\n return new Response(deps.getJwks(), {\n status: 200,\n headers: {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": cacheControl,\n },\n });\n }),\n });\n}\n\nexport function addAuthRoutes(\n http: HttpRouter,\n deps: {\n handleSignIn: (\n ctx: GenericActionCtx<any>,\n request: Request,\n ) => Promise<Response>;\n handleCallback: (\n ctx: GenericActionCtx<any>,\n request: Request,\n ) => Promise<Response>;\n },\n) {\n http.route({\n pathPrefix: \"/api/auth/signin/\",\n method: \"GET\",\n handler: httpActionGeneric(deps.handleSignIn),\n });\n\n const callbackHandler = httpActionGeneric(deps.handleCallback);\n\n http.route({\n pathPrefix: \"/api/auth/callback/\",\n method: \"GET\",\n handler: callbackHandler,\n });\n\n http.route({\n pathPrefix: \"/api/auth/callback/\",\n method: \"POST\",\n handler: callbackHandler,\n });\n}\n\nexport function addSSORoutes(\n http: HttpRouter,\n deps: {\n routeBase: string;\n convertErrorsToResponse: typeof convertErrorsToResponse;\n handleSamlMetadata: (\n ctx: GenericActionCtx<any>,\n request: Request,\n route: SSORuntimeRoute,\n ) => Promise<Response>;\n handleSamlSignIn: (\n ctx: GenericActionCtx<any>,\n request: Request,\n route: SSORuntimeRoute,\n ) => Promise<Response>;\n handleOidcSignIn: (\n ctx: GenericActionCtx<any>,\n request: Request,\n route: SSORuntimeRoute,\n ) => Promise<Response>;\n handleOidcCallback: (\n ctx: GenericActionCtx<any>,\n request: Request,\n route: SSORuntimeRoute,\n ) => Promise<Response>;\n handleSamlAcs: (\n ctx: GenericActionCtx<any>,\n request: Request,\n route: SSORuntimeRoute,\n ) => Promise<Response>;\n handleSamlSlo: (\n ctx: GenericActionCtx<any>,\n request: Request,\n route: SSORuntimeRoute,\n ) => Promise<Response>;\n handleScimRequest: (\n ctx: GenericActionCtx<any>,\n request: Request,\n ) => Promise<Response>;\n scimError: (status: number, scimType: string, detail: string) => Response;\n },\n) {\n const routePrefix = `${deps.routeBase}/`;\n\n http.route({\n pathPrefix: routePrefix,\n method: \"GET\",\n handler: httpActionGeneric(\n deps.convertErrorsToResponse(400, async (ctx, request) => {\n const route = parseEnterpriseRuntimeRoute(\n new URL(request.url).pathname,\n deps.routeBase,\n );\n if (!route) {\n throw new AuthError(\n \"INVALID_PARAMETERS\",\n \"Invalid enterprise runtime path.\",\n ).toConvexError();\n }\n if (route.protocol === \"saml\" && route.rest.length === 1) {\n if (route.rest[0] === \"metadata\") {\n return await deps.handleSamlMetadata(ctx, request, route);\n }\n if (route.rest[0] === \"signin\") {\n return await deps.handleSamlSignIn(ctx, request, route);\n }\n if (route.rest[0] === \"acs\") {\n return await deps.handleSamlAcs(ctx, request, route);\n }\n if (route.rest[0] === \"slo\") {\n return await deps.handleSamlSlo(ctx, request, route);\n }\n }\n if (route.protocol === \"oidc\" && route.rest.length === 1) {\n if (route.rest[0] === \"signin\") {\n return await deps.handleOidcSignIn(ctx, request, route);\n }\n if (route.rest[0] === \"callback\") {\n return await deps.handleOidcCallback(ctx, request, route);\n }\n }\n if (route.protocol === \"scim\" && route.rest[0] === \"v2\") {\n return await deps.handleScimRequest(ctx, request);\n }\n throw new AuthError(\n \"INVALID_PARAMETERS\",\n \"Invalid enterprise runtime path.\",\n ).toConvexError();\n }),\n ),\n });\n\n http.route({\n pathPrefix: routePrefix,\n method: \"POST\",\n handler: httpActionGeneric(\n deps.convertErrorsToResponse(400, async (ctx, request) => {\n const route = parseEnterpriseRuntimeRoute(\n new URL(request.url).pathname,\n deps.routeBase,\n );\n if (route?.protocol === \"saml\" && route.rest.length === 1) {\n if (route.rest[0] === \"acs\") {\n return await deps.handleSamlAcs(ctx, request, route);\n }\n if (route.rest[0] === \"slo\") {\n return await deps.handleSamlSlo(ctx, request, route);\n }\n }\n if (route?.protocol === \"scim\" && route.rest[0] === \"v2\") {\n return await deps.handleScimRequest(ctx, request);\n }\n throw new AuthError(\n \"INVALID_PARAMETERS\",\n \"Invalid enterprise runtime path.\",\n ).toConvexError();\n }),\n ),\n });\n\n http.route({\n pathPrefix: routePrefix,\n method: \"PUT\",\n handler: httpActionGeneric(\n deps.convertErrorsToResponse(400, async (ctx, request) => {\n const route = parseEnterpriseRuntimeRoute(\n new URL(request.url).pathname,\n deps.routeBase,\n );\n if (route?.protocol === \"scim\" && route.rest[0] === \"v2\") {\n return await deps.handleScimRequest(ctx, request);\n }\n throw new AuthError(\n \"INVALID_PARAMETERS\",\n \"Invalid enterprise runtime path.\",\n ).toConvexError();\n }),\n ),\n });\n\n for (const method of [\"PATCH\", \"DELETE\"] as const) {\n http.route({\n pathPrefix: routePrefix,\n method,\n handler: httpActionGeneric(async (ctx, request) => {\n const route = parseEnterpriseRuntimeRoute(\n new URL(request.url).pathname,\n deps.routeBase,\n );\n if (!route || route.protocol !== \"scim\" || route.rest[0] !== \"v2\") {\n return deps.scimError(404, \"notFound\", \"SCIM resource not found.\");\n }\n return await deps.handleScimRequest(ctx, request);\n }),\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"http.js","names":["result","parseCookies"],"sources":["../../src/server/http.ts"],"sourcesContent":["import { Fx } from \"@robelest/fx\";\nimport { Cv } from \"@robelest/fx/convex\";\nimport {\n GenericActionCtx,\n GenericDataModel,\n HttpRouter,\n httpActionGeneric,\n} from \"convex/server\";\nimport { ConvexError } from \"convex/values\";\nimport { parse as parseCookies } from \"cookie\";\n\nimport type { CorsConfig, HttpKeyContext } from \"./types\";\nimport { logError } from \"./utils\";\n\nexport function createHttpAction(auth: {\n key: { verify: (ctx: GenericActionCtx<any>, rawKey: string) => Promise<any> };\n}) {\n return (\n handler: (\n ctx: GenericActionCtx<GenericDataModel> & HttpKeyContext,\n request: Request,\n ) => Promise<Response | Record<string, unknown>>,\n options?: {\n scope?: { resource: string; action: string };\n cors?: CorsConfig;\n },\n ) => {\n const corsConfig = options?.cors ?? {};\n const corsHeaders: Record<string, string> = {\n \"Access-Control-Allow-Origin\": corsConfig.origin ?? \"*\",\n \"Access-Control-Allow-Methods\":\n corsConfig.methods ?? \"GET,POST,PUT,PATCH,DELETE,OPTIONS\",\n \"Access-Control-Allow-Headers\":\n corsConfig.headers ?? \"Content-Type,Authorization\",\n };\n\n return httpActionGeneric(async (genericCtx, request) => {\n return Fx.run(\n Fx.from({\n ok: async () => {\n const authHeader = request.headers.get(\"Authorization\");\n if (!authHeader?.startsWith(\"Bearer \")) {\n return new Response(\n JSON.stringify({\n error: \"Missing or malformed Authorization: Bearer header.\",\n code: \"MISSING_BEARER_TOKEN\",\n }),\n {\n status: 401,\n headers: {\n ...corsHeaders,\n \"Content-Type\": \"application/json\",\n },\n },\n );\n }\n const rawKey = authHeader.slice(7);\n\n const keyResult = await Fx.run(\n Fx.attempt(\n () => auth.key.verify(genericCtx, rawKey),\n (result) => ({ ok: true, value: result }) as const,\n (error) => ({ ok: false, error }) as const,\n ),\n );\n\n if (!keyResult.ok) {\n if (\n keyResult.error instanceof ConvexError &&\n typeof keyResult.error.data === \"object\" &&\n keyResult.error.data !== null &&\n \"code\" in keyResult.error.data &&\n \"message\" in keyResult.error.data\n ) {\n const { code, message } = keyResult.error.data as {\n code: string;\n message: string;\n };\n return new Response(JSON.stringify({ error: message, code }), {\n status: 403,\n headers: {\n ...corsHeaders,\n \"Content-Type\": \"application/json\",\n },\n });\n }\n throw keyResult.error;\n }\n\n if (\n options?.scope &&\n !keyResult.value.scopes.can(\n options.scope.resource,\n options.scope.action,\n )\n ) {\n return new Response(\n JSON.stringify({\n error: \"This API key does not have the required permissions.\",\n code: \"SCOPE_CHECK_FAILED\",\n }),\n {\n status: 403,\n headers: {\n ...corsHeaders,\n \"Content-Type\": \"application/json\",\n },\n },\n );\n }\n\n const enrichedCtx = Object.assign(genericCtx, {\n key: {\n userId: keyResult.value.userId,\n keyId: keyResult.value.keyId,\n scopes: keyResult.value.scopes,\n },\n });\n const result = await handler(enrichedCtx, request);\n\n if (result instanceof Response) {\n const headers = new Headers(result.headers);\n for (const [k, val] of Object.entries(corsHeaders)) {\n if (!headers.has(k)) headers.set(k, val);\n }\n return new Response(result.body, {\n status: result.status,\n statusText: result.statusText,\n headers,\n });\n }\n\n return new Response(JSON.stringify(result), {\n status: 200,\n headers: {\n ...corsHeaders,\n \"Content-Type\": \"application/json\",\n },\n });\n },\n err: (error) => error,\n }).pipe(\n Fx.recover((error) => {\n logError(error);\n return Fx.succeed(\n new Response(\n JSON.stringify({\n error: \"An unexpected error occurred.\",\n code: \"INTERNAL_ERROR\",\n }),\n {\n status: 500,\n headers: {\n ...corsHeaders,\n \"Content-Type\": \"application/json\",\n },\n },\n ),\n );\n }),\n ),\n );\n });\n };\n}\n\nexport function createHttpRoute(\n wrapAction: ReturnType<typeof createHttpAction>,\n) {\n return (\n http: { route: (config: any) => void },\n routeConfig: {\n path: string;\n method: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n handler: (\n ctx: GenericActionCtx<GenericDataModel> & HttpKeyContext,\n request: Request,\n ) => Promise<Response | Record<string, unknown>>;\n scope?: { resource: string; action: string };\n cors?: CorsConfig;\n },\n ) => {\n const corsConfig = routeConfig.cors ?? {};\n const corsHeaders: Record<string, string> = {\n \"Access-Control-Allow-Origin\": corsConfig.origin ?? \"*\",\n \"Access-Control-Allow-Methods\":\n corsConfig.methods ?? \"GET,POST,PUT,PATCH,DELETE,OPTIONS\",\n \"Access-Control-Allow-Headers\":\n corsConfig.headers ?? \"Content-Type,Authorization\",\n };\n\n http.route({\n path: routeConfig.path,\n method: \"OPTIONS\",\n handler: httpActionGeneric(async () => {\n return new Response(null, { status: 204, headers: corsHeaders });\n }),\n });\n\n http.route({\n path: routeConfig.path,\n method: routeConfig.method,\n handler: wrapAction(routeConfig.handler, {\n scope: routeConfig.scope,\n cors: routeConfig.cors,\n }),\n });\n };\n}\n\nexport function convertErrorsToResponse(\n errorStatusCode: number,\n action: (ctx: GenericActionCtx<any>, request: Request) => Promise<Response>,\n) {\n return async (ctx: GenericActionCtx<any>, request: Request) => {\n return Fx.run(\n Fx.from({\n ok: () => action(ctx, request),\n err: (error) => error,\n }).pipe(\n Fx.recover((error) => {\n if (\n error instanceof ConvexError &&\n typeof error.data === \"object\" &&\n error.data !== null &&\n \"code\" in error.data &&\n \"message\" in error.data\n ) {\n return Fx.succeed(\n new Response(\n JSON.stringify({\n code: error.data.code,\n message: error.data.message,\n }),\n {\n status: errorStatusCode,\n headers: { \"Content-Type\": \"application/json\" },\n },\n ),\n );\n } else if (error instanceof ConvexError) {\n return Fx.succeed(\n new Response(null, {\n status: errorStatusCode,\n statusText:\n typeof error.data === \"string\" ? error.data : \"Error\",\n }),\n );\n } else {\n logError(error);\n return Fx.succeed(\n new Response(null, {\n status: 500,\n statusText: \"Internal Server Error\",\n }),\n );\n }\n }),\n ),\n );\n };\n}\n\nexport function getCookies(\n request: Request,\n): Record<string, string | undefined> {\n return parseCookies(request.headers.get(\"Cookie\") ?? \"\");\n}\n\nexport type SSORuntimeRoute = {\n pathname?: string;\n enterpriseId: string;\n protocol: \"oidc\" | \"saml\" | \"scim\";\n rest: string[];\n};\n\nfunction parseEnterpriseRuntimeRoute(\n pathname: string,\n routeBase: string,\n): SSORuntimeRoute | null {\n const runtimePrefix = `${routeBase}/`;\n const runtimeParts = pathname.startsWith(runtimePrefix)\n ? pathname.slice(runtimePrefix.length).split(\"/\").filter(Boolean)\n : [];\n const [runtimeEnterpriseId, protocol, ...rest] = runtimeParts;\n if (\n runtimeEnterpriseId === undefined ||\n (protocol !== \"oidc\" && protocol !== \"saml\" && protocol !== \"scim\") ||\n rest.length === 0\n ) {\n return null;\n }\n return {\n pathname,\n enterpriseId: runtimeEnterpriseId,\n protocol,\n rest,\n };\n}\n\nexport function addOpenIdRoutes(\n http: HttpRouter,\n deps: {\n getIssuer: () => string;\n getJwks: () => string;\n },\n) {\n const cacheControl =\n \"public, max-age=15, stale-while-revalidate=15, stale-if-error=86400\";\n\n http.route({\n path: \"/.well-known/openid-configuration\",\n method: \"GET\",\n handler: httpActionGeneric(async () => {\n const issuer = deps.getIssuer();\n return new Response(\n JSON.stringify({\n issuer,\n jwks_uri: `${issuer}/.well-known/jwks.json`,\n }),\n {\n status: 200,\n headers: {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": cacheControl,\n },\n },\n );\n }),\n });\n\n http.route({\n path: \"/.well-known/jwks.json\",\n method: \"GET\",\n handler: httpActionGeneric(async () => {\n return new Response(deps.getJwks(), {\n status: 200,\n headers: {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": cacheControl,\n },\n });\n }),\n });\n}\n\nexport function addAuthRoutes(\n http: HttpRouter,\n deps: {\n handleSignIn: (\n ctx: GenericActionCtx<any>,\n request: Request,\n ) => Promise<Response>;\n handleCallback: (\n ctx: GenericActionCtx<any>,\n request: Request,\n ) => Promise<Response>;\n },\n) {\n http.route({\n pathPrefix: \"/api/auth/signin/\",\n method: \"GET\",\n handler: httpActionGeneric(deps.handleSignIn),\n });\n\n const callbackHandler = httpActionGeneric(deps.handleCallback);\n\n http.route({\n pathPrefix: \"/api/auth/callback/\",\n method: \"GET\",\n handler: callbackHandler,\n });\n\n http.route({\n pathPrefix: \"/api/auth/callback/\",\n method: \"POST\",\n handler: callbackHandler,\n });\n}\n\nexport function addSSORoutes(\n http: HttpRouter,\n deps: {\n routeBase: string;\n convertErrorsToResponse: typeof convertErrorsToResponse;\n handleSamlMetadata: (\n ctx: GenericActionCtx<any>,\n request: Request,\n route: SSORuntimeRoute,\n ) => Promise<Response>;\n handleSamlSignIn: (\n ctx: GenericActionCtx<any>,\n request: Request,\n route: SSORuntimeRoute,\n ) => Promise<Response>;\n handleOidcSignIn: (\n ctx: GenericActionCtx<any>,\n request: Request,\n route: SSORuntimeRoute,\n ) => Promise<Response>;\n handleOidcCallback: (\n ctx: GenericActionCtx<any>,\n request: Request,\n route: SSORuntimeRoute,\n ) => Promise<Response>;\n handleSamlAcs: (\n ctx: GenericActionCtx<any>,\n request: Request,\n route: SSORuntimeRoute,\n ) => Promise<Response>;\n handleSamlSlo: (\n ctx: GenericActionCtx<any>,\n request: Request,\n route: SSORuntimeRoute,\n ) => Promise<Response>;\n handleScimRequest: (\n ctx: GenericActionCtx<any>,\n request: Request,\n ) => Promise<Response>;\n scimError: (status: number, scimType: string, detail: string) => Response;\n },\n) {\n const routePrefix = `${deps.routeBase}/`;\n\n http.route({\n pathPrefix: routePrefix,\n method: \"GET\",\n handler: httpActionGeneric(\n deps.convertErrorsToResponse(400, async (ctx, request) => {\n const route = parseEnterpriseRuntimeRoute(\n new URL(request.url).pathname,\n deps.routeBase,\n );\n if (!route) {\n throw Cv.error({\n code: \"INVALID_PARAMETERS\",\n message: \"Invalid enterprise runtime path.\",\n });\n }\n if (route.protocol === \"saml\" && route.rest.length === 1) {\n if (route.rest[0] === \"metadata\") {\n return await deps.handleSamlMetadata(ctx, request, route);\n }\n if (route.rest[0] === \"signin\") {\n return await deps.handleSamlSignIn(ctx, request, route);\n }\n if (route.rest[0] === \"acs\") {\n return await deps.handleSamlAcs(ctx, request, route);\n }\n if (route.rest[0] === \"slo\") {\n return await deps.handleSamlSlo(ctx, request, route);\n }\n }\n if (route.protocol === \"oidc\" && route.rest.length === 1) {\n if (route.rest[0] === \"signin\") {\n return await deps.handleOidcSignIn(ctx, request, route);\n }\n if (route.rest[0] === \"callback\") {\n return await deps.handleOidcCallback(ctx, request, route);\n }\n }\n if (route.protocol === \"scim\" && route.rest[0] === \"v2\") {\n return await deps.handleScimRequest(ctx, request);\n }\n throw Cv.error({\n code: \"INVALID_PARAMETERS\",\n message: \"Invalid enterprise runtime path.\",\n });\n }),\n ),\n });\n\n http.route({\n pathPrefix: routePrefix,\n method: \"POST\",\n handler: httpActionGeneric(\n deps.convertErrorsToResponse(400, async (ctx, request) => {\n const route = parseEnterpriseRuntimeRoute(\n new URL(request.url).pathname,\n deps.routeBase,\n );\n if (route?.protocol === \"saml\" && route.rest.length === 1) {\n if (route.rest[0] === \"acs\") {\n return await deps.handleSamlAcs(ctx, request, route);\n }\n if (route.rest[0] === \"slo\") {\n return await deps.handleSamlSlo(ctx, request, route);\n }\n }\n if (route?.protocol === \"scim\" && route.rest[0] === \"v2\") {\n return await deps.handleScimRequest(ctx, request);\n }\n throw Cv.error({\n code: \"INVALID_PARAMETERS\",\n message: \"Invalid enterprise runtime path.\",\n });\n }),\n ),\n });\n\n http.route({\n pathPrefix: routePrefix,\n method: \"PUT\",\n handler: httpActionGeneric(\n deps.convertErrorsToResponse(400, async (ctx, request) => {\n const route = parseEnterpriseRuntimeRoute(\n new URL(request.url).pathname,\n deps.routeBase,\n );\n if (route?.protocol === \"scim\" && route.rest[0] === \"v2\") {\n return await deps.handleScimRequest(ctx, request);\n }\n throw Cv.error({\n code: \"INVALID_PARAMETERS\",\n message: \"Invalid enterprise runtime path.\",\n });\n }),\n ),\n });\n\n for (const method of [\"PATCH\", \"DELETE\"] as const) {\n http.route({\n pathPrefix: routePrefix,\n method,\n handler: httpActionGeneric(async (ctx, request) => {\n const route = parseEnterpriseRuntimeRoute(\n new URL(request.url).pathname,\n deps.routeBase,\n );\n if (!route || route.protocol !== \"scim\" || route.rest[0] !== \"v2\") {\n return deps.scimError(404, \"notFound\", \"SCIM resource not found.\");\n }\n return await deps.handleScimRequest(ctx, request);\n }),\n });\n }\n}\n"],"mappings":"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"}
|
package/dist/server/identity.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Cv } from "@robelest/fx/convex";
|
|
2
2
|
|
|
3
3
|
//#region src/server/identity.ts
|
|
4
4
|
/** @internal */
|
|
5
5
|
function userIdFromIdentitySubject(subject) {
|
|
6
6
|
const [userId, ...rest] = subject.split("|");
|
|
7
|
-
if (typeof userId !== "string" || userId.length === 0 || rest.length === 0 || rest.some((segment) => segment.length === 0)) throw
|
|
7
|
+
if (typeof userId !== "string" || userId.length === 0 || rest.length === 0 || rest.some((segment) => segment.length === 0)) throw Cv.error({
|
|
8
|
+
code: "INTERNAL_ERROR",
|
|
9
|
+
message: "Authenticated identity subject is malformed."
|
|
10
|
+
});
|
|
8
11
|
return userId;
|
|
9
12
|
}
|
|
10
13
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.js","names":[],"sources":["../../src/server/identity.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"identity.js","names":[],"sources":["../../src/server/identity.ts"],"sourcesContent":["import { Cv } from \"@robelest/fx/convex\";\n\n/** @internal */\nexport function userIdFromIdentitySubject(subject: string): string {\n const [userId, ...rest] = subject.split(\"|\");\n if (\n typeof userId !== \"string\" ||\n userId.length === 0 ||\n rest.length === 0 ||\n rest.some((segment) => segment.length === 0)\n ) {\n throw Cv.error({\n code: \"INTERNAL_ERROR\",\n message: \"Authenticated identity subject is malformed.\",\n });\n }\n return userId;\n}\n"],"mappings":";;;;AAGA,SAAgB,0BAA0B,SAAyB;CACjE,MAAM,CAAC,QAAQ,GAAG,QAAQ,QAAQ,MAAM,IAAI;AAC5C,KACE,OAAO,WAAW,YAClB,OAAO,WAAW,KAClB,KAAK,WAAW,KAChB,KAAK,MAAM,YAAY,QAAQ,WAAW,EAAE,CAE5C,OAAM,GAAG,MAAM;EACb,MAAM;EACN,SAAS;EACV,CAAC;AAEJ,QAAO"}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuthApi, AuthApiBase, AuthConfig, AuthCtx, ConvexAuthResult, InferAuth, InferClientApi, UserDoc, createAuth } from "./auth.js";
|
|
1
|
+
import { AuthApi, AuthApiBase, AuthConfig, AuthContext, AuthCtx, AuthCtxConfig, ConvexAuthResult, InferAuth, InferClientApi, UserDoc, createAuth } from "./auth.js";
|
|
2
2
|
import { EnterpriseAdminAuthorizationInput, EnterpriseAdminPermission, EnterpriseAuthorizer, EnterpriseMountOptions, enterprise, scim, sso } from "./mounts.js";
|
|
3
3
|
import { AuthCookie, AuthCookieConfig, AuthCookies, RefreshResult, ServerOptions, authCookieNames, parseAuthCookies, serializeAuthCookies, server, shouldProxyAuthAction, structuredAuthCookies } from "./ssr.js";
|
|
4
|
-
export { type AuthApi, type AuthApiBase, type AuthConfig, type AuthCookie, type AuthCookieConfig, type AuthCookies, AuthCtx, type ConvexAuthResult, type EnterpriseAdminAuthorizationInput, type EnterpriseAdminPermission, type EnterpriseAuthorizer, type EnterpriseMountOptions, type InferAuth, type InferClientApi, type RefreshResult, type ServerOptions, type UserDoc, authCookieNames, createAuth, enterprise, parseAuthCookies, scim, serializeAuthCookies, server, shouldProxyAuthAction, sso, structuredAuthCookies };
|
|
4
|
+
export { type AuthApi, type AuthApiBase, type AuthConfig, type AuthContext, type AuthCookie, type AuthCookieConfig, type AuthCookies, AuthCtx, type AuthCtxConfig, type ConvexAuthResult, type EnterpriseAdminAuthorizationInput, type EnterpriseAdminPermission, type EnterpriseAuthorizer, type EnterpriseMountOptions, type InferAuth, type InferClientApi, type RefreshResult, type ServerOptions, type UserDoc, authCookieNames, createAuth, enterprise, parseAuthCookies, scim, serializeAuthCookies, server, shouldProxyAuthAction, sso, structuredAuthCookies };
|