@open-mercato/enterprise 0.6.6-develop.5612.1.d382eb2f33 → 0.6.6-develop.5619.1.29f01e2c42
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/modules/security/api/i18n.js +3 -0
- package/dist/modules/security/api/i18n.js.map +2 -2
- package/dist/modules/security/api/mfa/prepare/route.js +6 -1
- package/dist/modules/security/api/mfa/prepare/route.js.map +2 -2
- package/dist/modules/security/api/mfa/verify/route.js +7 -1
- package/dist/modules/security/api/mfa/verify/route.js.map +2 -2
- package/dist/modules/security/api/sudo/prepare/route.js +6 -1
- package/dist/modules/security/api/sudo/prepare/route.js.map +2 -2
- package/dist/modules/security/api/users/mfa/compliance/route.js +4 -2
- package/dist/modules/security/api/users/mfa/compliance/route.js.map +2 -2
- package/dist/modules/security/commands/createEnforcementPolicy.js +6 -4
- package/dist/modules/security/commands/createEnforcementPolicy.js.map +2 -2
- package/dist/modules/security/commands/deleteEnforcementPolicy.js +6 -4
- package/dist/modules/security/commands/deleteEnforcementPolicy.js.map +2 -2
- package/dist/modules/security/commands/resetUserMfa.js +11 -4
- package/dist/modules/security/commands/resetUserMfa.js.map +2 -2
- package/dist/modules/security/commands/updateEnforcementPolicy.js +6 -4
- package/dist/modules/security/commands/updateEnforcementPolicy.js.map +2 -2
- package/dist/modules/security/i18n/de.json +3 -0
- package/dist/modules/security/i18n/en.json +3 -0
- package/dist/modules/security/i18n/es.json +3 -0
- package/dist/modules/security/i18n/pl.json +3 -0
- package/dist/modules/security/services/MfaAdminService.js +42 -8
- package/dist/modules/security/services/MfaAdminService.js.map +2 -2
- package/dist/modules/security/services/MfaEnforcementService.js +57 -7
- package/dist/modules/security/services/MfaEnforcementService.js.map +2 -2
- package/dist/modules/security/services/MfaVerificationService.js +15 -6
- package/dist/modules/security/services/MfaVerificationService.js.map +2 -2
- package/dist/modules/security/services/SudoChallengeService.js +26 -4
- package/dist/modules/security/services/SudoChallengeService.js.map +2 -2
- package/package.json +5 -5
- package/src/modules/security/api/i18n.ts +3 -0
- package/src/modules/security/api/mfa/prepare/route.ts +6 -1
- package/src/modules/security/api/mfa/verify/route.ts +7 -1
- package/src/modules/security/api/sudo/prepare/route.ts +6 -1
- package/src/modules/security/api/users/mfa/compliance/route.ts +6 -3
- package/src/modules/security/commands/createEnforcementPolicy.ts +7 -5
- package/src/modules/security/commands/deleteEnforcementPolicy.ts +10 -5
- package/src/modules/security/commands/resetUserMfa.ts +12 -5
- package/src/modules/security/commands/updateEnforcementPolicy.ts +10 -5
- package/src/modules/security/i18n/de.json +3 -0
- package/src/modules/security/i18n/en.json +3 -0
- package/src/modules/security/i18n/es.json +3 -0
- package/src/modules/security/i18n/pl.json +3 -0
- package/src/modules/security/services/MfaAdminService.ts +101 -8
- package/src/modules/security/services/MfaEnforcementService.ts +174 -7
- package/src/modules/security/services/MfaVerificationService.ts +58 -4
- package/src/modules/security/services/SudoChallengeService.ts +31 -6
|
@@ -13,6 +13,8 @@ const exactMessageMap = /* @__PURE__ */ new Map([
|
|
|
13
13
|
["Sudo config not found", { key: "security.api.errors.sudoConfigurationNotFound", fallback: "Sudo configuration not found." }],
|
|
14
14
|
["Sudo configuration not found", { key: "security.api.errors.sudoConfigurationNotFound", fallback: "Sudo configuration not found." }],
|
|
15
15
|
["Tenant context is required.", { key: "security.api.errors.tenantContextRequired", fallback: "Tenant context is required." }],
|
|
16
|
+
["Cross-tenant access denied.", { key: "security.api.errors.crossTenantAccessDenied", fallback: "Cross-tenant access denied." }],
|
|
17
|
+
["Tenant not found", { key: "security.api.errors.tenantNotFound", fallback: "Tenant not found." }],
|
|
16
18
|
["MFA pending token is required.", { key: "security.api.errors.mfaPendingTokenRequired", fallback: "MFA pending token is required." }],
|
|
17
19
|
["challengeId and methodType are required.", { key: "security.api.errors.challengeIdAndMethodTypeRequired", fallback: "challengeId and methodType are required." }],
|
|
18
20
|
["setupId is required.", { key: "security.api.errors.setupIdRequired", fallback: "setupId is required." }],
|
|
@@ -37,6 +39,7 @@ const exactMessageMap = /* @__PURE__ */ new Map([
|
|
|
37
39
|
["MFA challenge already verified", { key: "security.api.errors.mfaChallengeAlreadyVerified", fallback: "MFA challenge was already verified." }],
|
|
38
40
|
["MFA challenge expired", { key: "security.api.errors.mfaChallengeExpired", fallback: "MFA challenge expired." }],
|
|
39
41
|
["Enforcement policy not found", { key: "security.api.errors.enforcementPolicyNotFound", fallback: "Enforcement policy not found." }],
|
|
42
|
+
["Insufficient scope for enforcement policy", { key: "security.api.errors.enforcementInsufficientScope", fallback: "Insufficient scope for enforcement policy." }],
|
|
40
43
|
["Enforcement policy already exists for this scope", { key: "security.api.errors.enforcementPolicyAlreadyExistsForScope", fallback: "An enforcement policy already exists for this scope." }],
|
|
41
44
|
["scopeId is required for tenant and organisation scopes", { key: "security.api.errors.enforcementScopeIdRequired", fallback: "scopeId is required for tenant and organisation scopes." }],
|
|
42
45
|
["organisation scopeId must use '<tenantId>:<organizationId>' format", { key: "security.api.errors.enforcementOrganizationScopeFormat", fallback: "Organisation scopeId must use '<tenantId>:<organizationId>' format." }],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/security/api/i18n.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\ntype TranslateParams = Record<string, string | number>\n\ntype MessageDescriptor = {\n key: string\n fallback: string\n params?: TranslateParams\n}\n\nconst exactMessageMap = new Map<string, MessageDescriptor>([\n ['Not implemented', { key: 'security.api.errors.notImplemented', fallback: 'Not implemented.' }],\n ['Unauthorized', { key: 'api.errors.unauthorized', fallback: 'Unauthorized' }],\n ['Invalid payload', { key: 'api.errors.invalidPayload', fallback: 'Invalid payload.' }],\n ['Invalid query parameters', { key: 'security.api.errors.invalidQueryParameters', fallback: 'Invalid query parameters.' }],\n ['Invalid route parameters', { key: 'security.api.errors.invalidRouteParameters', fallback: 'Invalid route parameters.' }],\n ['Invalid policy id.', { key: 'security.api.errors.invalidPolicyId', fallback: 'Invalid policy id.' }],\n ['Invalid user id.', { key: 'security.api.errors.invalidUserId', fallback: 'Invalid user id.' }],\n ['Invalid provider type.', { key: 'security.api.errors.invalidProviderType', fallback: 'Invalid provider type.' }],\n ['Invalid method id.', { key: 'security.api.errors.invalidMethodId', fallback: 'Invalid method id.' }],\n ['Sudo config not found', { key: 'security.api.errors.sudoConfigurationNotFound', fallback: 'Sudo configuration not found.' }],\n ['Sudo configuration not found', { key: 'security.api.errors.sudoConfigurationNotFound', fallback: 'Sudo configuration not found.' }],\n ['Tenant context is required.', { key: 'security.api.errors.tenantContextRequired', fallback: 'Tenant context is required.' }],\n ['MFA pending token is required.', { key: 'security.api.errors.mfaPendingTokenRequired', fallback: 'MFA pending token is required.' }],\n ['challengeId and methodType are required.', { key: 'security.api.errors.challengeIdAndMethodTypeRequired', fallback: 'challengeId and methodType are required.' }],\n ['setupId is required.', { key: 'security.api.errors.setupIdRequired', fallback: 'setupId is required.' }],\n ['code is required.', { key: 'security.api.errors.codeRequired', fallback: 'code is required.' }],\n ['Invalid MFA verification code.', { key: 'security.api.errors.invalidMfaVerificationCode', fallback: 'Invalid MFA verification code.' }],\n ['Invalid recovery code.', { key: 'security.api.errors.invalidRecoveryCode', fallback: 'Invalid recovery code.' }],\n ['Failed to process MFA request.', { key: 'security.api.errors.mfaRequestFailed', fallback: 'Failed to process MFA request.' }],\n ['Failed to process enforcement request.', { key: 'security.api.errors.enforcementRequestFailed', fallback: 'Failed to process enforcement request.' }],\n ['Failed to process user security request.', { key: 'security.api.errors.userSecurityRequestFailed', fallback: 'Failed to process user security request.' }],\n ['Failed to process sudo request.', { key: 'security.api.errors.sudoRequestFailed', fallback: 'Failed to process sudo request.' }],\n ['User not found', { key: 'auth.users.form.errors.notFound', fallback: 'User not found' }],\n ['Admin ID is required', { key: 'security.api.errors.adminIdRequired', fallback: 'Admin ID is required.' }],\n ['User ID is required', { key: 'security.api.errors.userIdRequired', fallback: 'User ID is required.' }],\n ['Reset reason is required', { key: 'security.api.errors.resetReasonRequired', fallback: 'Reset reason is required.' }],\n ['Tenant ID is required', { key: 'security.api.errors.tenantIdRequired', fallback: 'Tenant ID is required.' }],\n ['MFA setup session not found', { key: 'security.api.errors.mfaSetupSessionNotFound', fallback: 'MFA setup session not found.' }],\n ['MFA setup session does not match the requested provider', { key: 'security.api.errors.mfaSetupSessionProviderMismatch', fallback: 'MFA setup session does not match the requested provider.' }],\n ['MFA method not found', { key: 'security.api.errors.mfaMethodNotFound', fallback: 'MFA method not found.' }],\n ['No MFA methods configured', { key: 'security.api.errors.noMfaMethodsConfigured', fallback: 'No MFA methods configured.' }],\n ['No registered MFA providers are available for the configured methods', { key: 'security.api.errors.noRegisteredMfaProviders', fallback: 'No registered MFA providers are available for the configured methods.' }],\n ['MFA challenge not found', { key: 'security.api.errors.mfaChallengeNotFound', fallback: 'MFA challenge not found.' }],\n ['MFA challenge already verified', { key: 'security.api.errors.mfaChallengeAlreadyVerified', fallback: 'MFA challenge was already verified.' }],\n ['MFA challenge expired', { key: 'security.api.errors.mfaChallengeExpired', fallback: 'MFA challenge expired.' }],\n ['Enforcement policy not found', { key: 'security.api.errors.enforcementPolicyNotFound', fallback: 'Enforcement policy not found.' }],\n ['Enforcement policy already exists for this scope', { key: 'security.api.errors.enforcementPolicyAlreadyExistsForScope', fallback: 'An enforcement policy already exists for this scope.' }],\n ['scopeId is required for tenant and organisation scopes', { key: 'security.api.errors.enforcementScopeIdRequired', fallback: 'scopeId is required for tenant and organisation scopes.' }],\n [\"organisation scopeId must use '<tenantId>:<organizationId>' format\", { key: 'security.api.errors.enforcementOrganizationScopeFormat', fallback: \"Organisation scopeId must use '<tenantId>:<organizationId>' format.\" }],\n ['tenantId is required for tenant scope', { key: 'security.api.errors.enforcementTenantIdRequired', fallback: 'tenantId is required for tenant scope.' }],\n ['tenantId and organizationId are required for organisation scope', { key: 'security.api.errors.enforcementOrganizationScopeIdsRequired', fallback: 'tenantId and organizationId are required for organisation scope.' }],\n ['This sudo session does not require MFA', { key: 'security.api.errors.sudoSessionDoesNotRequireMfa', fallback: 'This sudo session does not require MFA.' }],\n ['Sudo protection is not configured for this target', { key: 'security.api.errors.sudoProtectionNotConfigured', fallback: 'Sudo protection is not configured for this target.' }],\n ['Unable to verify sudo challenge', { key: 'security.api.errors.sudoVerifyFailed', fallback: 'Unable to verify the sudo challenge.' }],\n ['A sudo configuration for this target and scope already exists', { key: 'security.api.errors.sudoConfigurationAlreadyExists', fallback: 'A sudo configuration for this target and scope already exists.' }],\n ['Organization-scoped sudo config requires a tenant', { key: 'security.api.errors.sudoOrganizationScopeRequiresTenant', fallback: 'An organization-scoped sudo configuration requires a tenant.' }],\n ['This sudo target requires MFA, but no MFA methods are configured', { key: 'security.api.errors.sudoMfaRequiredButUnavailable', fallback: 'This sudo target requires MFA, but no MFA methods are configured.' }],\n ['Sudo challenge session not found', { key: 'security.api.errors.sudoSessionNotFound', fallback: 'Sudo challenge session not found.' }],\n ['Sudo challenge session expired', { key: 'security.api.errors.sudoSessionExpired', fallback: 'Sudo challenge session expired.' }],\n ['Password is required', { key: 'security.api.errors.passwordRequired', fallback: 'Password is required.' }],\n ['TOTP setup session not found', { key: 'security.api.errors.totpSetupSessionNotFound', fallback: 'TOTP setup session not found.' }],\n ['TOTP setup session expired', { key: 'security.api.errors.totpSetupSessionExpired', fallback: 'TOTP setup session expired.' }],\n ['Invalid TOTP code', { key: 'security.api.errors.invalidTotpCode', fallback: 'Invalid TOTP code.' }],\n ['Invalid empty TOTP secret', { key: 'security.api.errors.invalidTotpSecret', fallback: 'Invalid TOTP secret.' }],\n ['Unable to configure Email OTP without a destination email', { key: 'security.api.errors.emailOtpDestinationRequired', fallback: 'Unable to configure email OTP without a destination email address.' }],\n ['Email OTP setup session not found', { key: 'security.api.errors.emailOtpSetupSessionNotFound', fallback: 'Email OTP setup session not found.' }],\n ['Email OTP setup session expired', { key: 'security.api.errors.emailOtpSetupSessionExpired', fallback: 'Email OTP setup session expired.' }],\n ['MFA method does not belong to user', { key: 'security.api.errors.mfaMethodOwnership', fallback: 'The MFA method does not belong to this user.' }],\n ['Email OTP method is missing a destination email address', { key: 'security.api.errors.emailOtpDestinationMissing', fallback: 'The email OTP method is missing a destination email address.' }],\n ['Passkey setup session not found', { key: 'security.api.errors.passkeySetupSessionNotFound', fallback: 'Passkey setup session not found.' }],\n ['Passkey setup session expired', { key: 'security.api.errors.passkeySetupSessionExpired', fallback: 'Passkey setup session expired.' }],\n ['Passkey registration verification failed', { key: 'security.api.errors.passkeyRegistrationVerificationFailed', fallback: 'Passkey registration verification failed.' }],\n ['Passkey registration did not return credential data', { key: 'security.api.errors.passkeyRegistrationCredentialMissing', fallback: 'Passkey registration did not return credential data.' }],\n ['Invalid passkey setup challenge', { key: 'security.api.errors.invalidPasskeySetupChallenge', fallback: 'Invalid passkey setup challenge.' }],\n ['Passkey credential is not configured', { key: 'security.api.errors.passkeyCredentialNotConfigured', fallback: 'The passkey credential is not configured.' }],\n])\n\nconst patternMessageMap: Array<{\n pattern: RegExp\n resolve: (match: RegExpMatchArray) => MessageDescriptor\n}> = [\n {\n pattern: /^Sudo authentication required for: (.+)$/,\n resolve: (match) => ({\n key: 'security.api.errors.sudoRequiredForTarget',\n fallback: 'Sudo authentication is required for: {target}',\n params: { target: match[1] ?? '' },\n }),\n },\n {\n pattern: /^MFA provider '(.+)' is not registered$/,\n resolve: (match) => ({\n key: 'security.api.errors.mfaProviderNotRegistered',\n fallback: 'MFA provider \"{provider}\" is not registered.',\n params: { provider: match[1] ?? '' },\n }),\n },\n {\n pattern: /^MFA provider '(.+)' is already configured$/,\n resolve: (match) => ({\n key: 'security.api.errors.mfaProviderAlreadyConfigured',\n fallback: 'MFA provider \"{provider}\" is already configured.',\n params: { provider: match[1] ?? '' },\n }),\n },\n {\n pattern: /^MFA method '(.+)' not found$/,\n resolve: (match) => ({\n key: 'security.api.errors.mfaMethodByTypeNotFound',\n fallback: 'MFA method \"{method}\" was not found.',\n params: { method: match[1] ?? '' },\n }),\n },\n]\n\nfunction resolveMessageDescriptor(message: string): MessageDescriptor | null {\n const exact = exactMessageMap.get(message)\n if (exact) return exact\n\n for (const entry of patternMessageMap) {\n const match = message.match(entry.pattern)\n if (match) return entry.resolve(match)\n }\n\n return null\n}\n\nexport async function translateSecurityApiMessage(message: string): Promise<string> {\n const descriptor = resolveMessageDescriptor(message)\n if (!descriptor) return message\n\n const { translate } = await resolveTranslations()\n return translate(descriptor.key, descriptor.fallback, descriptor.params)\n}\n\nexport async function localizeSecurityApiBody<T extends Record<string, unknown>>(body: T): Promise<T> {\n const nextBody: Record<string, unknown> = { ...body }\n\n if (typeof nextBody.error === 'string') {\n nextBody.error = await translateSecurityApiMessage(nextBody.error)\n }\n\n if (typeof nextBody.message === 'string') {\n nextBody.message = await translateSecurityApiMessage(nextBody.message)\n }\n\n return nextBody as T\n}\n\nexport async function securityApiError(\n status: number,\n message: string,\n extra?: Record<string, unknown>,\n): Promise<NextResponse> {\n const body = await localizeSecurityApiBody({\n error: message,\n ...(extra ?? {}),\n })\n return NextResponse.json(body, { status })\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\ntype TranslateParams = Record<string, string | number>\n\ntype MessageDescriptor = {\n key: string\n fallback: string\n params?: TranslateParams\n}\n\nconst exactMessageMap = new Map<string, MessageDescriptor>([\n ['Not implemented', { key: 'security.api.errors.notImplemented', fallback: 'Not implemented.' }],\n ['Unauthorized', { key: 'api.errors.unauthorized', fallback: 'Unauthorized' }],\n ['Invalid payload', { key: 'api.errors.invalidPayload', fallback: 'Invalid payload.' }],\n ['Invalid query parameters', { key: 'security.api.errors.invalidQueryParameters', fallback: 'Invalid query parameters.' }],\n ['Invalid route parameters', { key: 'security.api.errors.invalidRouteParameters', fallback: 'Invalid route parameters.' }],\n ['Invalid policy id.', { key: 'security.api.errors.invalidPolicyId', fallback: 'Invalid policy id.' }],\n ['Invalid user id.', { key: 'security.api.errors.invalidUserId', fallback: 'Invalid user id.' }],\n ['Invalid provider type.', { key: 'security.api.errors.invalidProviderType', fallback: 'Invalid provider type.' }],\n ['Invalid method id.', { key: 'security.api.errors.invalidMethodId', fallback: 'Invalid method id.' }],\n ['Sudo config not found', { key: 'security.api.errors.sudoConfigurationNotFound', fallback: 'Sudo configuration not found.' }],\n ['Sudo configuration not found', { key: 'security.api.errors.sudoConfigurationNotFound', fallback: 'Sudo configuration not found.' }],\n ['Tenant context is required.', { key: 'security.api.errors.tenantContextRequired', fallback: 'Tenant context is required.' }],\n ['Cross-tenant access denied.', { key: 'security.api.errors.crossTenantAccessDenied', fallback: 'Cross-tenant access denied.' }],\n ['Tenant not found', { key: 'security.api.errors.tenantNotFound', fallback: 'Tenant not found.' }],\n ['MFA pending token is required.', { key: 'security.api.errors.mfaPendingTokenRequired', fallback: 'MFA pending token is required.' }],\n ['challengeId and methodType are required.', { key: 'security.api.errors.challengeIdAndMethodTypeRequired', fallback: 'challengeId and methodType are required.' }],\n ['setupId is required.', { key: 'security.api.errors.setupIdRequired', fallback: 'setupId is required.' }],\n ['code is required.', { key: 'security.api.errors.codeRequired', fallback: 'code is required.' }],\n ['Invalid MFA verification code.', { key: 'security.api.errors.invalidMfaVerificationCode', fallback: 'Invalid MFA verification code.' }],\n ['Invalid recovery code.', { key: 'security.api.errors.invalidRecoveryCode', fallback: 'Invalid recovery code.' }],\n ['Failed to process MFA request.', { key: 'security.api.errors.mfaRequestFailed', fallback: 'Failed to process MFA request.' }],\n ['Failed to process enforcement request.', { key: 'security.api.errors.enforcementRequestFailed', fallback: 'Failed to process enforcement request.' }],\n ['Failed to process user security request.', { key: 'security.api.errors.userSecurityRequestFailed', fallback: 'Failed to process user security request.' }],\n ['Failed to process sudo request.', { key: 'security.api.errors.sudoRequestFailed', fallback: 'Failed to process sudo request.' }],\n ['User not found', { key: 'auth.users.form.errors.notFound', fallback: 'User not found' }],\n ['Admin ID is required', { key: 'security.api.errors.adminIdRequired', fallback: 'Admin ID is required.' }],\n ['User ID is required', { key: 'security.api.errors.userIdRequired', fallback: 'User ID is required.' }],\n ['Reset reason is required', { key: 'security.api.errors.resetReasonRequired', fallback: 'Reset reason is required.' }],\n ['Tenant ID is required', { key: 'security.api.errors.tenantIdRequired', fallback: 'Tenant ID is required.' }],\n ['MFA setup session not found', { key: 'security.api.errors.mfaSetupSessionNotFound', fallback: 'MFA setup session not found.' }],\n ['MFA setup session does not match the requested provider', { key: 'security.api.errors.mfaSetupSessionProviderMismatch', fallback: 'MFA setup session does not match the requested provider.' }],\n ['MFA method not found', { key: 'security.api.errors.mfaMethodNotFound', fallback: 'MFA method not found.' }],\n ['No MFA methods configured', { key: 'security.api.errors.noMfaMethodsConfigured', fallback: 'No MFA methods configured.' }],\n ['No registered MFA providers are available for the configured methods', { key: 'security.api.errors.noRegisteredMfaProviders', fallback: 'No registered MFA providers are available for the configured methods.' }],\n ['MFA challenge not found', { key: 'security.api.errors.mfaChallengeNotFound', fallback: 'MFA challenge not found.' }],\n ['MFA challenge already verified', { key: 'security.api.errors.mfaChallengeAlreadyVerified', fallback: 'MFA challenge was already verified.' }],\n ['MFA challenge expired', { key: 'security.api.errors.mfaChallengeExpired', fallback: 'MFA challenge expired.' }],\n ['Enforcement policy not found', { key: 'security.api.errors.enforcementPolicyNotFound', fallback: 'Enforcement policy not found.' }],\n ['Insufficient scope for enforcement policy', { key: 'security.api.errors.enforcementInsufficientScope', fallback: 'Insufficient scope for enforcement policy.' }],\n ['Enforcement policy already exists for this scope', { key: 'security.api.errors.enforcementPolicyAlreadyExistsForScope', fallback: 'An enforcement policy already exists for this scope.' }],\n ['scopeId is required for tenant and organisation scopes', { key: 'security.api.errors.enforcementScopeIdRequired', fallback: 'scopeId is required for tenant and organisation scopes.' }],\n [\"organisation scopeId must use '<tenantId>:<organizationId>' format\", { key: 'security.api.errors.enforcementOrganizationScopeFormat', fallback: \"Organisation scopeId must use '<tenantId>:<organizationId>' format.\" }],\n ['tenantId is required for tenant scope', { key: 'security.api.errors.enforcementTenantIdRequired', fallback: 'tenantId is required for tenant scope.' }],\n ['tenantId and organizationId are required for organisation scope', { key: 'security.api.errors.enforcementOrganizationScopeIdsRequired', fallback: 'tenantId and organizationId are required for organisation scope.' }],\n ['This sudo session does not require MFA', { key: 'security.api.errors.sudoSessionDoesNotRequireMfa', fallback: 'This sudo session does not require MFA.' }],\n ['Sudo protection is not configured for this target', { key: 'security.api.errors.sudoProtectionNotConfigured', fallback: 'Sudo protection is not configured for this target.' }],\n ['Unable to verify sudo challenge', { key: 'security.api.errors.sudoVerifyFailed', fallback: 'Unable to verify the sudo challenge.' }],\n ['A sudo configuration for this target and scope already exists', { key: 'security.api.errors.sudoConfigurationAlreadyExists', fallback: 'A sudo configuration for this target and scope already exists.' }],\n ['Organization-scoped sudo config requires a tenant', { key: 'security.api.errors.sudoOrganizationScopeRequiresTenant', fallback: 'An organization-scoped sudo configuration requires a tenant.' }],\n ['This sudo target requires MFA, but no MFA methods are configured', { key: 'security.api.errors.sudoMfaRequiredButUnavailable', fallback: 'This sudo target requires MFA, but no MFA methods are configured.' }],\n ['Sudo challenge session not found', { key: 'security.api.errors.sudoSessionNotFound', fallback: 'Sudo challenge session not found.' }],\n ['Sudo challenge session expired', { key: 'security.api.errors.sudoSessionExpired', fallback: 'Sudo challenge session expired.' }],\n ['Password is required', { key: 'security.api.errors.passwordRequired', fallback: 'Password is required.' }],\n ['TOTP setup session not found', { key: 'security.api.errors.totpSetupSessionNotFound', fallback: 'TOTP setup session not found.' }],\n ['TOTP setup session expired', { key: 'security.api.errors.totpSetupSessionExpired', fallback: 'TOTP setup session expired.' }],\n ['Invalid TOTP code', { key: 'security.api.errors.invalidTotpCode', fallback: 'Invalid TOTP code.' }],\n ['Invalid empty TOTP secret', { key: 'security.api.errors.invalidTotpSecret', fallback: 'Invalid TOTP secret.' }],\n ['Unable to configure Email OTP without a destination email', { key: 'security.api.errors.emailOtpDestinationRequired', fallback: 'Unable to configure email OTP without a destination email address.' }],\n ['Email OTP setup session not found', { key: 'security.api.errors.emailOtpSetupSessionNotFound', fallback: 'Email OTP setup session not found.' }],\n ['Email OTP setup session expired', { key: 'security.api.errors.emailOtpSetupSessionExpired', fallback: 'Email OTP setup session expired.' }],\n ['MFA method does not belong to user', { key: 'security.api.errors.mfaMethodOwnership', fallback: 'The MFA method does not belong to this user.' }],\n ['Email OTP method is missing a destination email address', { key: 'security.api.errors.emailOtpDestinationMissing', fallback: 'The email OTP method is missing a destination email address.' }],\n ['Passkey setup session not found', { key: 'security.api.errors.passkeySetupSessionNotFound', fallback: 'Passkey setup session not found.' }],\n ['Passkey setup session expired', { key: 'security.api.errors.passkeySetupSessionExpired', fallback: 'Passkey setup session expired.' }],\n ['Passkey registration verification failed', { key: 'security.api.errors.passkeyRegistrationVerificationFailed', fallback: 'Passkey registration verification failed.' }],\n ['Passkey registration did not return credential data', { key: 'security.api.errors.passkeyRegistrationCredentialMissing', fallback: 'Passkey registration did not return credential data.' }],\n ['Invalid passkey setup challenge', { key: 'security.api.errors.invalidPasskeySetupChallenge', fallback: 'Invalid passkey setup challenge.' }],\n ['Passkey credential is not configured', { key: 'security.api.errors.passkeyCredentialNotConfigured', fallback: 'The passkey credential is not configured.' }],\n])\n\nconst patternMessageMap: Array<{\n pattern: RegExp\n resolve: (match: RegExpMatchArray) => MessageDescriptor\n}> = [\n {\n pattern: /^Sudo authentication required for: (.+)$/,\n resolve: (match) => ({\n key: 'security.api.errors.sudoRequiredForTarget',\n fallback: 'Sudo authentication is required for: {target}',\n params: { target: match[1] ?? '' },\n }),\n },\n {\n pattern: /^MFA provider '(.+)' is not registered$/,\n resolve: (match) => ({\n key: 'security.api.errors.mfaProviderNotRegistered',\n fallback: 'MFA provider \"{provider}\" is not registered.',\n params: { provider: match[1] ?? '' },\n }),\n },\n {\n pattern: /^MFA provider '(.+)' is already configured$/,\n resolve: (match) => ({\n key: 'security.api.errors.mfaProviderAlreadyConfigured',\n fallback: 'MFA provider \"{provider}\" is already configured.',\n params: { provider: match[1] ?? '' },\n }),\n },\n {\n pattern: /^MFA method '(.+)' not found$/,\n resolve: (match) => ({\n key: 'security.api.errors.mfaMethodByTypeNotFound',\n fallback: 'MFA method \"{method}\" was not found.',\n params: { method: match[1] ?? '' },\n }),\n },\n]\n\nfunction resolveMessageDescriptor(message: string): MessageDescriptor | null {\n const exact = exactMessageMap.get(message)\n if (exact) return exact\n\n for (const entry of patternMessageMap) {\n const match = message.match(entry.pattern)\n if (match) return entry.resolve(match)\n }\n\n return null\n}\n\nexport async function translateSecurityApiMessage(message: string): Promise<string> {\n const descriptor = resolveMessageDescriptor(message)\n if (!descriptor) return message\n\n const { translate } = await resolveTranslations()\n return translate(descriptor.key, descriptor.fallback, descriptor.params)\n}\n\nexport async function localizeSecurityApiBody<T extends Record<string, unknown>>(body: T): Promise<T> {\n const nextBody: Record<string, unknown> = { ...body }\n\n if (typeof nextBody.error === 'string') {\n nextBody.error = await translateSecurityApiMessage(nextBody.error)\n }\n\n if (typeof nextBody.message === 'string') {\n nextBody.message = await translateSecurityApiMessage(nextBody.message)\n }\n\n return nextBody as T\n}\n\nexport async function securityApiError(\n status: number,\n message: string,\n extra?: Record<string, unknown>,\n): Promise<NextResponse> {\n const body = await localizeSecurityApiBody({\n error: message,\n ...(extra ?? {}),\n })\n return NextResponse.json(body, { status })\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -27,7 +27,12 @@ async function POST(req) {
|
|
|
27
27
|
return securityApiError(400, "challengeId and methodType are required.");
|
|
28
28
|
}
|
|
29
29
|
try {
|
|
30
|
-
const prepared = await context.mfaVerificationService.prepareChallenge(
|
|
30
|
+
const prepared = await context.mfaVerificationService.prepareChallenge(
|
|
31
|
+
challengeId,
|
|
32
|
+
methodType,
|
|
33
|
+
{ request: req },
|
|
34
|
+
{ userId: context.auth.sub }
|
|
35
|
+
);
|
|
31
36
|
return NextResponse.json({ ok: true, ...prepared.clientData ? { clientData: prepared.clientData } : {} });
|
|
32
37
|
} catch (error) {
|
|
33
38
|
return await mapMfaError(error);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/security/api/mfa/prepare/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { buildSecurityOpenApi, securityErrorSchema } from '../../openapi'\nimport { securityApiError } from '../../i18n'\nimport { mapMfaError, readJsonRecord, readString, resolveMfaRequestContext } from '../_shared'\n\nconst requestSchema = z.object({\n challengeId: z.string().min(1),\n methodType: z.string().min(1),\n})\n\nconst responseSchema = z.object({\n ok: z.literal(true),\n clientData: z.record(z.string(), z.unknown()).optional(),\n})\n\nexport const metadata = {\n POST: { requireAuth: true, rateLimit: { points: 20, duration: 60, keyPrefix: 'security_mfa_prepare' } },\n}\n\nexport async function POST(req: Request) {\n const context = await resolveMfaRequestContext(req)\n if (context instanceof NextResponse) return context\n\n if (context.auth.mfa_pending !== true) {\n return securityApiError(403, 'MFA pending token is required.')\n }\n\n const body = await readJsonRecord(req)\n const challengeId = readString(body.challengeId)\n const methodType = readString(body.methodType)\n if (!challengeId || !methodType) {\n return securityApiError(400, 'challengeId and methodType are required.')\n }\n\n try {\n const prepared = await context.mfaVerificationService.prepareChallenge(challengeId
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,sBAAsB,2BAA2B;AAC1D,SAAS,wBAAwB;AACjC,SAAS,aAAa,gBAAgB,YAAY,gCAAgC;AAElF,MAAM,gBAAgB,EAAE,OAAO;AAAA,EAC7B,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC;AAC9B,CAAC;AAED,MAAM,iBAAiB,EAAE,OAAO;AAAA,EAC9B,IAAI,EAAE,QAAQ,IAAI;AAAA,EAClB,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AACzD,CAAC;AAEM,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,MAAM,WAAW,EAAE,QAAQ,IAAI,UAAU,IAAI,WAAW,uBAAuB,EAAE;AACxG;AAEA,eAAsB,KAAK,KAAc;AACvC,QAAM,UAAU,MAAM,yBAAyB,GAAG;AAClD,MAAI,mBAAmB,aAAc,QAAO;AAE5C,MAAI,QAAQ,KAAK,gBAAgB,MAAM;AACrC,WAAO,iBAAiB,KAAK,gCAAgC;AAAA,EAC/D;AAEA,QAAM,OAAO,MAAM,eAAe,GAAG;AACrC,QAAM,cAAc,WAAW,KAAK,WAAW;AAC/C,QAAM,aAAa,WAAW,KAAK,UAAU;AAC7C,MAAI,CAAC,eAAe,CAAC,YAAY;AAC/B,WAAO,iBAAiB,KAAK,0CAA0C;AAAA,EACzE;AAEA,MAAI;AACF,UAAM,WAAW,MAAM,QAAQ,uBAAuB,
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { buildSecurityOpenApi, securityErrorSchema } from '../../openapi'\nimport { securityApiError } from '../../i18n'\nimport { mapMfaError, readJsonRecord, readString, resolveMfaRequestContext } from '../_shared'\n\nconst requestSchema = z.object({\n challengeId: z.string().min(1),\n methodType: z.string().min(1),\n})\n\nconst responseSchema = z.object({\n ok: z.literal(true),\n clientData: z.record(z.string(), z.unknown()).optional(),\n})\n\nexport const metadata = {\n POST: { requireAuth: true, rateLimit: { points: 20, duration: 60, keyPrefix: 'security_mfa_prepare' } },\n}\n\nexport async function POST(req: Request) {\n const context = await resolveMfaRequestContext(req)\n if (context instanceof NextResponse) return context\n\n if (context.auth.mfa_pending !== true) {\n return securityApiError(403, 'MFA pending token is required.')\n }\n\n const body = await readJsonRecord(req)\n const challengeId = readString(body.challengeId)\n const methodType = readString(body.methodType)\n if (!challengeId || !methodType) {\n return securityApiError(400, 'challengeId and methodType are required.')\n }\n\n try {\n const prepared = await context.mfaVerificationService.prepareChallenge(\n challengeId,\n methodType,\n { request: req },\n { userId: context.auth.sub },\n )\n return NextResponse.json({ ok: true, ...(prepared.clientData ? { clientData: prepared.clientData } : {}) })\n } catch (error) {\n return await mapMfaError(error)\n }\n}\n\nexport const openApi = buildSecurityOpenApi({\n summary: 'MFA challenge prepare routes',\n methods: {\n POST: {\n summary: 'Prepare MFA challenge payload for selected method',\n requestBody: {\n contentType: 'application/json',\n schema: requestSchema,\n },\n responses: [{ status: 200, description: 'MFA challenge prepared', schema: responseSchema }],\n errors: [\n { status: 400, description: 'Invalid payload', schema: securityErrorSchema },\n { status: 403, description: 'Pending MFA context required', schema: securityErrorSchema },\n ],\n },\n },\n})\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,sBAAsB,2BAA2B;AAC1D,SAAS,wBAAwB;AACjC,SAAS,aAAa,gBAAgB,YAAY,gCAAgC;AAElF,MAAM,gBAAgB,EAAE,OAAO;AAAA,EAC7B,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC;AAC9B,CAAC;AAED,MAAM,iBAAiB,EAAE,OAAO;AAAA,EAC9B,IAAI,EAAE,QAAQ,IAAI;AAAA,EAClB,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AACzD,CAAC;AAEM,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,MAAM,WAAW,EAAE,QAAQ,IAAI,UAAU,IAAI,WAAW,uBAAuB,EAAE;AACxG;AAEA,eAAsB,KAAK,KAAc;AACvC,QAAM,UAAU,MAAM,yBAAyB,GAAG;AAClD,MAAI,mBAAmB,aAAc,QAAO;AAE5C,MAAI,QAAQ,KAAK,gBAAgB,MAAM;AACrC,WAAO,iBAAiB,KAAK,gCAAgC;AAAA,EAC/D;AAEA,QAAM,OAAO,MAAM,eAAe,GAAG;AACrC,QAAM,cAAc,WAAW,KAAK,WAAW;AAC/C,QAAM,aAAa,WAAW,KAAK,UAAU;AAC7C,MAAI,CAAC,eAAe,CAAC,YAAY;AAC/B,WAAO,iBAAiB,KAAK,0CAA0C;AAAA,EACzE;AAEA,MAAI;AACF,UAAM,WAAW,MAAM,QAAQ,uBAAuB;AAAA,MACpD;AAAA,MACA;AAAA,MACA,EAAE,SAAS,IAAI;AAAA,MACf,EAAE,QAAQ,QAAQ,KAAK,IAAI;AAAA,IAC7B;AACA,WAAO,aAAa,KAAK,EAAE,IAAI,MAAM,GAAI,SAAS,aAAa,EAAE,YAAY,SAAS,WAAW,IAAI,CAAC,EAAG,CAAC;AAAA,EAC5G,SAAS,OAAO;AACd,WAAO,MAAM,YAAY,KAAK;AAAA,EAChC;AACF;AAEO,MAAM,UAAU,qBAAqB;AAAA,EAC1C,SAAS;AAAA,EACT,SAAS;AAAA,IACP,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,aAAa;AAAA,QACX,aAAa;AAAA,QACb,QAAQ;AAAA,MACV;AAAA,MACA,WAAW,CAAC,EAAE,QAAQ,KAAK,aAAa,0BAA0B,QAAQ,eAAe,CAAC;AAAA,MAC1F,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,mBAAmB,QAAQ,oBAAoB;AAAA,QAC3E,EAAE,QAAQ,KAAK,aAAa,gCAAgC,QAAQ,oBAAoB;AAAA,MAC1F;AAAA,IACF;AAAA,EACF;AACF,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -30,7 +30,13 @@ async function POST(req) {
|
|
|
30
30
|
return securityApiError(400, "challengeId and methodType are required.");
|
|
31
31
|
}
|
|
32
32
|
try {
|
|
33
|
-
const verified = await context.mfaVerificationService.verifyChallenge(
|
|
33
|
+
const verified = await context.mfaVerificationService.verifyChallenge(
|
|
34
|
+
challengeId,
|
|
35
|
+
methodType,
|
|
36
|
+
payload,
|
|
37
|
+
{ request: req },
|
|
38
|
+
{ userId: context.auth.sub }
|
|
39
|
+
);
|
|
34
40
|
if (!verified) {
|
|
35
41
|
return securityApiError(401, "Invalid MFA verification code.");
|
|
36
42
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/security/api/mfa/verify/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { buildSecurityOpenApi, securityErrorSchema } from '../../openapi'\nimport { securityApiError } from '../../i18n'\nimport { issueVerifiedMfaToken, mapMfaError, readJsonRecord, readString, resolveMfaRequestContext, setAuthCookie } from '../_shared'\n\nconst requestSchema = z.object({\n challengeId: z.string().min(1),\n methodType: z.string().min(1),\n payload: z.record(z.string(), z.unknown()).default({}),\n})\n\nconst responseSchema = z.object({\n ok: z.literal(true),\n token: z.string(),\n redirect: z.string(),\n})\n\nexport const metadata = {\n POST: { requireAuth: true, rateLimit: { points: 10, duration: 60, keyPrefix: 'security_mfa_verify' } },\n}\n\nexport async function POST(req: Request) {\n const context = await resolveMfaRequestContext(req)\n if (context instanceof NextResponse) return context\n\n if (context.auth.mfa_pending !== true) {\n return securityApiError(403, 'MFA pending token is required.')\n }\n\n const body = await readJsonRecord(req)\n const challengeId = readString(body.challengeId)\n const methodType = readString(body.methodType)\n const payload = body.payload && typeof body.payload === 'object' ? body.payload : {}\n if (!challengeId || !methodType) {\n return securityApiError(400, 'challengeId and methodType are required.')\n }\n\n try {\n const verified = await context.mfaVerificationService.verifyChallenge(challengeId
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,sBAAsB,2BAA2B;AAC1D,SAAS,wBAAwB;AACjC,SAAS,uBAAuB,aAAa,gBAAgB,YAAY,0BAA0B,qBAAqB;AAExH,MAAM,gBAAgB,EAAE,OAAO;AAAA,EAC7B,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC5B,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,iBAAiB,EAAE,OAAO;AAAA,EAC9B,IAAI,EAAE,QAAQ,IAAI;AAAA,EAClB,OAAO,EAAE,OAAO;AAAA,EAChB,UAAU,EAAE,OAAO;AACrB,CAAC;AAEM,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,MAAM,WAAW,EAAE,QAAQ,IAAI,UAAU,IAAI,WAAW,sBAAsB,EAAE;AACvG;AAEA,eAAsB,KAAK,KAAc;AACvC,QAAM,UAAU,MAAM,yBAAyB,GAAG;AAClD,MAAI,mBAAmB,aAAc,QAAO;AAE5C,MAAI,QAAQ,KAAK,gBAAgB,MAAM;AACrC,WAAO,iBAAiB,KAAK,gCAAgC;AAAA,EAC/D;AAEA,QAAM,OAAO,MAAM,eAAe,GAAG;AACrC,QAAM,cAAc,WAAW,KAAK,WAAW;AAC/C,QAAM,aAAa,WAAW,KAAK,UAAU;AAC7C,QAAM,UAAU,KAAK,WAAW,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU,CAAC;AACnF,MAAI,CAAC,eAAe,CAAC,YAAY;AAC/B,WAAO,iBAAiB,KAAK,0CAA0C;AAAA,EACzE;AAEA,MAAI;AACF,UAAM,WAAW,MAAM,QAAQ,uBAAuB,
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { buildSecurityOpenApi, securityErrorSchema } from '../../openapi'\nimport { securityApiError } from '../../i18n'\nimport { issueVerifiedMfaToken, mapMfaError, readJsonRecord, readString, resolveMfaRequestContext, setAuthCookie } from '../_shared'\n\nconst requestSchema = z.object({\n challengeId: z.string().min(1),\n methodType: z.string().min(1),\n payload: z.record(z.string(), z.unknown()).default({}),\n})\n\nconst responseSchema = z.object({\n ok: z.literal(true),\n token: z.string(),\n redirect: z.string(),\n})\n\nexport const metadata = {\n POST: { requireAuth: true, rateLimit: { points: 10, duration: 60, keyPrefix: 'security_mfa_verify' } },\n}\n\nexport async function POST(req: Request) {\n const context = await resolveMfaRequestContext(req)\n if (context instanceof NextResponse) return context\n\n if (context.auth.mfa_pending !== true) {\n return securityApiError(403, 'MFA pending token is required.')\n }\n\n const body = await readJsonRecord(req)\n const challengeId = readString(body.challengeId)\n const methodType = readString(body.methodType)\n const payload = body.payload && typeof body.payload === 'object' ? body.payload : {}\n if (!challengeId || !methodType) {\n return securityApiError(400, 'challengeId and methodType are required.')\n }\n\n try {\n const verified = await context.mfaVerificationService.verifyChallenge(\n challengeId,\n methodType,\n payload,\n { request: req },\n { userId: context.auth.sub },\n )\n if (!verified) {\n return securityApiError(401, 'Invalid MFA verification code.')\n }\n\n const methods = await context.mfaService.getUserMethods(context.auth.sub)\n const token = issueVerifiedMfaToken(context.auth, methods.map((method) => method.type))\n const response = NextResponse.json({ ok: true, token, redirect: '/backend' })\n setAuthCookie(response, token)\n return response\n } catch (error) {\n return await mapMfaError(error)\n }\n}\n\nexport const openApi = buildSecurityOpenApi({\n summary: 'MFA challenge verify routes',\n methods: {\n POST: {\n summary: 'Verify MFA challenge during login flow',\n requestBody: {\n contentType: 'application/json',\n schema: requestSchema,\n },\n responses: [{ status: 200, description: 'MFA challenge verified', schema: responseSchema }],\n errors: [\n { status: 400, description: 'Invalid payload', schema: securityErrorSchema },\n { status: 401, description: 'Invalid challenge response', schema: securityErrorSchema },\n { status: 403, description: 'Pending MFA context required', schema: securityErrorSchema },\n ],\n },\n },\n})\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,sBAAsB,2BAA2B;AAC1D,SAAS,wBAAwB;AACjC,SAAS,uBAAuB,aAAa,gBAAgB,YAAY,0BAA0B,qBAAqB;AAExH,MAAM,gBAAgB,EAAE,OAAO;AAAA,EAC7B,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC5B,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,iBAAiB,EAAE,OAAO;AAAA,EAC9B,IAAI,EAAE,QAAQ,IAAI;AAAA,EAClB,OAAO,EAAE,OAAO;AAAA,EAChB,UAAU,EAAE,OAAO;AACrB,CAAC;AAEM,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,MAAM,WAAW,EAAE,QAAQ,IAAI,UAAU,IAAI,WAAW,sBAAsB,EAAE;AACvG;AAEA,eAAsB,KAAK,KAAc;AACvC,QAAM,UAAU,MAAM,yBAAyB,GAAG;AAClD,MAAI,mBAAmB,aAAc,QAAO;AAE5C,MAAI,QAAQ,KAAK,gBAAgB,MAAM;AACrC,WAAO,iBAAiB,KAAK,gCAAgC;AAAA,EAC/D;AAEA,QAAM,OAAO,MAAM,eAAe,GAAG;AACrC,QAAM,cAAc,WAAW,KAAK,WAAW;AAC/C,QAAM,aAAa,WAAW,KAAK,UAAU;AAC7C,QAAM,UAAU,KAAK,WAAW,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU,CAAC;AACnF,MAAI,CAAC,eAAe,CAAC,YAAY;AAC/B,WAAO,iBAAiB,KAAK,0CAA0C;AAAA,EACzE;AAEA,MAAI;AACF,UAAM,WAAW,MAAM,QAAQ,uBAAuB;AAAA,MACpD;AAAA,MACA;AAAA,MACA;AAAA,MACA,EAAE,SAAS,IAAI;AAAA,MACf,EAAE,QAAQ,QAAQ,KAAK,IAAI;AAAA,IAC7B;AACA,QAAI,CAAC,UAAU;AACb,aAAO,iBAAiB,KAAK,gCAAgC;AAAA,IAC/D;AAEA,UAAM,UAAU,MAAM,QAAQ,WAAW,eAAe,QAAQ,KAAK,GAAG;AACxE,UAAM,QAAQ,sBAAsB,QAAQ,MAAM,QAAQ,IAAI,CAAC,WAAW,OAAO,IAAI,CAAC;AACtF,UAAM,WAAW,aAAa,KAAK,EAAE,IAAI,MAAM,OAAO,UAAU,WAAW,CAAC;AAC5E,kBAAc,UAAU,KAAK;AAC7B,WAAO;AAAA,EACT,SAAS,OAAO;AACd,WAAO,MAAM,YAAY,KAAK;AAAA,EAChC;AACF;AAEO,MAAM,UAAU,qBAAqB;AAAA,EAC1C,SAAS;AAAA,EACT,SAAS;AAAA,IACP,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,aAAa;AAAA,QACX,aAAa;AAAA,QACb,QAAQ;AAAA,MACV;AAAA,MACA,WAAW,CAAC,EAAE,QAAQ,KAAK,aAAa,0BAA0B,QAAQ,eAAe,CAAC;AAAA,MAC1F,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,mBAAmB,QAAQ,oBAAoB;AAAA,QAC3E,EAAE,QAAQ,KAAK,aAAa,8BAA8B,QAAQ,oBAAoB;AAAA,QACtF,EAAE,QAAQ,KAAK,aAAa,gCAAgC,QAAQ,oBAAoB;AAAA,MAC1F;AAAA,IACF;AAAA,EACF;AACF,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -24,7 +24,12 @@ async function POST(req) {
|
|
|
24
24
|
return securityApiError(400, "Invalid payload", { issues: parsed.error.issues });
|
|
25
25
|
}
|
|
26
26
|
try {
|
|
27
|
-
const result = await context.sudoChallengeService.prepare(
|
|
27
|
+
const result = await context.sudoChallengeService.prepare(
|
|
28
|
+
parsed.data.sessionId,
|
|
29
|
+
parsed.data.methodType,
|
|
30
|
+
{ expectedUserId: context.auth.sub },
|
|
31
|
+
req
|
|
32
|
+
);
|
|
28
33
|
return NextResponse.json(result);
|
|
29
34
|
} catch (error) {
|
|
30
35
|
return await mapSudoError(error);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/security/api/sudo/prepare/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { sudoChallengePrepareSchema } from '../../../data/validators'\nimport { buildSecurityOpenApi, securityErrorSchema } from '../../openapi'\nimport { securityApiError } from '../../i18n'\nimport { mapSudoError, resolveSudoContext } from '../_shared'\n\nconst prepareResponseSchema = z.object({\n clientData: z.record(z.string(), z.unknown()).optional(),\n})\n\nexport const metadata = {\n POST: { requireAuth: true },\n}\n\nexport async function POST(req: Request) {\n const context = await resolveSudoContext(req)\n if (context instanceof NextResponse) return context\n\n let body: unknown\n try {\n body = await req.json()\n } catch {\n body = {}\n }\n\n const parsed = sudoChallengePrepareSchema.safeParse(body)\n if (!parsed.success) {\n return securityApiError(400, 'Invalid payload', { issues: parsed.error.issues })\n }\n\n try {\n const result = await context.sudoChallengeService.prepare(parsed.data.sessionId
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,kCAAkC;AAC3C,SAAS,sBAAsB,2BAA2B;AAC1D,SAAS,wBAAwB;AACjC,SAAS,cAAc,0BAA0B;AAEjD,MAAM,wBAAwB,EAAE,OAAO;AAAA,EACrC,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AACzD,CAAC;AAEM,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,KAAK;AAC5B;AAEA,eAAsB,KAAK,KAAc;AACvC,QAAM,UAAU,MAAM,mBAAmB,GAAG;AAC5C,MAAI,mBAAmB,aAAc,QAAO;AAE5C,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,IAAI,KAAK;AAAA,EACxB,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,SAAS,2BAA2B,UAAU,IAAI;AACxD,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,iBAAiB,KAAK,mBAAmB,EAAE,QAAQ,OAAO,MAAM,OAAO,CAAC;AAAA,EACjF;AAEA,MAAI;AACF,UAAM,SAAS,MAAM,QAAQ,qBAAqB,
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { sudoChallengePrepareSchema } from '../../../data/validators'\nimport { buildSecurityOpenApi, securityErrorSchema } from '../../openapi'\nimport { securityApiError } from '../../i18n'\nimport { mapSudoError, resolveSudoContext } from '../_shared'\n\nconst prepareResponseSchema = z.object({\n clientData: z.record(z.string(), z.unknown()).optional(),\n})\n\nexport const metadata = {\n POST: { requireAuth: true },\n}\n\nexport async function POST(req: Request) {\n const context = await resolveSudoContext(req)\n if (context instanceof NextResponse) return context\n\n let body: unknown\n try {\n body = await req.json()\n } catch {\n body = {}\n }\n\n const parsed = sudoChallengePrepareSchema.safeParse(body)\n if (!parsed.success) {\n return securityApiError(400, 'Invalid payload', { issues: parsed.error.issues })\n }\n\n try {\n const result = await context.sudoChallengeService.prepare(\n parsed.data.sessionId,\n parsed.data.methodType,\n { expectedUserId: context.auth.sub },\n req,\n )\n return NextResponse.json(result)\n } catch (error) {\n return await mapSudoError(error)\n }\n}\n\nexport const openApi = buildSecurityOpenApi({\n summary: 'Sudo prepare challenge routes',\n methods: {\n POST: {\n summary: 'Prepare a sudo MFA challenge',\n requestBody: {\n contentType: 'application/json',\n schema: sudoChallengePrepareSchema,\n },\n responses: [\n { status: 200, description: 'Sudo challenge prepared', schema: prepareResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Invalid payload', schema: securityErrorSchema },\n { status: 401, description: 'Unauthorized', schema: securityErrorSchema },\n ],\n },\n },\n})\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,kCAAkC;AAC3C,SAAS,sBAAsB,2BAA2B;AAC1D,SAAS,wBAAwB;AACjC,SAAS,cAAc,0BAA0B;AAEjD,MAAM,wBAAwB,EAAE,OAAO;AAAA,EACrC,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AACzD,CAAC;AAEM,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,KAAK;AAC5B;AAEA,eAAsB,KAAK,KAAc;AACvC,QAAM,UAAU,MAAM,mBAAmB,GAAG;AAC5C,MAAI,mBAAmB,aAAc,QAAO;AAE5C,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,IAAI,KAAK;AAAA,EACxB,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,SAAS,2BAA2B,UAAU,IAAI;AACxD,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,iBAAiB,KAAK,mBAAmB,EAAE,QAAQ,OAAO,MAAM,OAAO,CAAC;AAAA,EACjF;AAEA,MAAI;AACF,UAAM,SAAS,MAAM,QAAQ,qBAAqB;AAAA,MAChD,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,MACZ,EAAE,gBAAgB,QAAQ,KAAK,IAAI;AAAA,MACnC;AAAA,IACF;AACA,WAAO,aAAa,KAAK,MAAM;AAAA,EACjC,SAAS,OAAO;AACd,WAAO,MAAM,aAAa,KAAK;AAAA,EACjC;AACF;AAEO,MAAM,UAAU,qBAAqB;AAAA,EAC1C,SAAS;AAAA,EACT,SAAS;AAAA,IACP,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,aAAa;AAAA,QACX,aAAa;AAAA,QACb,QAAQ;AAAA,MACV;AAAA,MACA,WAAW;AAAA,QACT,EAAE,QAAQ,KAAK,aAAa,2BAA2B,QAAQ,sBAAsB;AAAA,MACvF;AAAA,MACA,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,mBAAmB,QAAQ,oBAAoB;AAAA,QAC3E,EAAE,QAAQ,KAAK,aAAa,gBAAgB,QAAQ,oBAAoB;AAAA,MAC1E;AAAA,IACF;AAAA,EACF;AACF,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -41,10 +41,12 @@ async function GET(req) {
|
|
|
41
41
|
return securityApiError(400, "Tenant context is required.");
|
|
42
42
|
}
|
|
43
43
|
const isSuperAdmin = await resolveIsSuperAdmin({ auth: context.auth, container: context.container });
|
|
44
|
-
const
|
|
44
|
+
const scope = {
|
|
45
45
|
tenantId: context.auth.tenantId ?? null,
|
|
46
|
+
organizationId: context.auth.orgId ?? null,
|
|
46
47
|
isSuperAdmin
|
|
47
|
-
}
|
|
48
|
+
};
|
|
49
|
+
const items = await context.mfaAdminService.bulkComplianceCheck(tenantId, scope);
|
|
48
50
|
return NextResponse.json({ items });
|
|
49
51
|
} catch (error) {
|
|
50
52
|
return await mapSecurityUsersError(error);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/security/api/users/mfa/compliance/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { buildSecurityOpenApi, securityErrorSchema } from '../../../openapi'\nimport { securityApiError } from '../../../i18n'\nimport { resolveIsSuperAdmin } from '@open-mercato/core/modules/auth/lib/tenantAccess'\nimport {\n assertActorOwnsTenantScope,\n mapSecurityUsersError,\n resolveSecurityUsersContext,\n} from '../../_shared'\n\nconst querySchema = z.object({\n tenantId: z.string().uuid().optional(),\n})\n\nconst complianceItemSchema = z.object({\n userId: z.string().uuid(),\n email: z.string().email(),\n enrolled: z.boolean(),\n methodCount: z.number().int().nonnegative(),\n compliant: z.boolean(),\n lastLoginAt: z.string().datetime().optional(),\n})\n\nconst complianceListResponseSchema = z.object({\n items: z.array(complianceItemSchema),\n})\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['security.admin.manage'] },\n}\n\nexport async function GET(req: Request) {\n const context = await resolveSecurityUsersContext(req)\n if (context instanceof NextResponse) return context\n\n const url = new URL(req.url)\n const parsedQuery = querySchema.safeParse({\n tenantId: url.searchParams.get('tenantId') ?? undefined,\n })\n if (!parsedQuery.success) {\n return securityApiError(400, 'Invalid query parameters', { issues: parsedQuery.error.issues })\n }\n\n try {\n const tenantId = await assertActorOwnsTenantScope(context, parsedQuery.data.tenantId)\n if (!tenantId) {\n return securityApiError(400, 'Tenant context is required.')\n }\n const isSuperAdmin = await resolveIsSuperAdmin({ auth: context.auth, container: context.container })\n const
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,sBAAsB,2BAA2B;AAC1D,SAAS,wBAAwB;AACjC,SAAS,2BAA2B;AACpC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { buildSecurityOpenApi, securityErrorSchema } from '../../../openapi'\nimport { securityApiError } from '../../../i18n'\nimport { resolveIsSuperAdmin } from '@open-mercato/core/modules/auth/lib/tenantAccess'\nimport {\n assertActorOwnsTenantScope,\n mapSecurityUsersError,\n resolveSecurityUsersContext,\n} from '../../_shared'\nimport type { MfaAdminAuthScope } from '../../../../services/MfaAdminService'\n\nconst querySchema = z.object({\n tenantId: z.string().uuid().optional(),\n})\n\nconst complianceItemSchema = z.object({\n userId: z.string().uuid(),\n email: z.string().email(),\n enrolled: z.boolean(),\n methodCount: z.number().int().nonnegative(),\n compliant: z.boolean(),\n lastLoginAt: z.string().datetime().optional(),\n})\n\nconst complianceListResponseSchema = z.object({\n items: z.array(complianceItemSchema),\n})\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['security.admin.manage'] },\n}\n\nexport async function GET(req: Request) {\n const context = await resolveSecurityUsersContext(req)\n if (context instanceof NextResponse) return context\n\n const url = new URL(req.url)\n const parsedQuery = querySchema.safeParse({\n tenantId: url.searchParams.get('tenantId') ?? undefined,\n })\n if (!parsedQuery.success) {\n return securityApiError(400, 'Invalid query parameters', { issues: parsedQuery.error.issues })\n }\n\n try {\n const tenantId = await assertActorOwnsTenantScope(context, parsedQuery.data.tenantId)\n if (!tenantId) {\n return securityApiError(400, 'Tenant context is required.')\n }\n const isSuperAdmin = await resolveIsSuperAdmin({ auth: context.auth, container: context.container })\n const scope: MfaAdminAuthScope = {\n tenantId: (context.auth.tenantId as string | null | undefined) ?? null,\n organizationId: (context.auth.orgId as string | null | undefined) ?? null,\n isSuperAdmin,\n }\n const items = await context.mfaAdminService.bulkComplianceCheck(tenantId, scope)\n return NextResponse.json({ items })\n } catch (error) {\n return await mapSecurityUsersError(error)\n }\n}\n\nexport const openApi = buildSecurityOpenApi({\n summary: 'Admin users MFA compliance routes',\n methods: {\n GET: {\n summary: 'List MFA compliance for tenant users',\n query: querySchema,\n responses: [\n { status: 200, description: 'MFA compliance list', schema: complianceListResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Invalid query or missing tenant context', schema: securityErrorSchema },\n { status: 401, description: 'Unauthorized', schema: securityErrorSchema },\n { status: 403, description: 'Not authorized for the requested tenant scope', schema: securityErrorSchema },\n ],\n },\n },\n})\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,sBAAsB,2BAA2B;AAC1D,SAAS,wBAAwB;AACjC,SAAS,2BAA2B;AACpC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,MAAM,cAAc,EAAE,OAAO;AAAA,EAC3B,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AACvC,CAAC;AAED,MAAM,uBAAuB,EAAE,OAAO;AAAA,EACpC,QAAQ,EAAE,OAAO,EAAE,KAAK;AAAA,EACxB,OAAO,EAAE,OAAO,EAAE,MAAM;AAAA,EACxB,UAAU,EAAE,QAAQ;AAAA,EACpB,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC1C,WAAW,EAAE,QAAQ;AAAA,EACrB,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAC9C,CAAC;AAED,MAAM,+BAA+B,EAAE,OAAO;AAAA,EAC5C,OAAO,EAAE,MAAM,oBAAoB;AACrC,CAAC;AAEM,MAAM,WAAW;AAAA,EACtB,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,uBAAuB,EAAE;AACvE;AAEA,eAAsB,IAAI,KAAc;AACtC,QAAM,UAAU,MAAM,4BAA4B,GAAG;AACrD,MAAI,mBAAmB,aAAc,QAAO;AAE5C,QAAM,MAAM,IAAI,IAAI,IAAI,GAAG;AAC3B,QAAM,cAAc,YAAY,UAAU;AAAA,IACxC,UAAU,IAAI,aAAa,IAAI,UAAU,KAAK;AAAA,EAChD,CAAC;AACD,MAAI,CAAC,YAAY,SAAS;AACxB,WAAO,iBAAiB,KAAK,4BAA4B,EAAE,QAAQ,YAAY,MAAM,OAAO,CAAC;AAAA,EAC/F;AAEA,MAAI;AACF,UAAM,WAAW,MAAM,2BAA2B,SAAS,YAAY,KAAK,QAAQ;AACpF,QAAI,CAAC,UAAU;AACb,aAAO,iBAAiB,KAAK,6BAA6B;AAAA,IAC5D;AACA,UAAM,eAAe,MAAM,oBAAoB,EAAE,MAAM,QAAQ,MAAM,WAAW,QAAQ,UAAU,CAAC;AACnG,UAAM,QAA2B;AAAA,MAC/B,UAAW,QAAQ,KAAK,YAA0C;AAAA,MAClE,gBAAiB,QAAQ,KAAK,SAAuC;AAAA,MACrE;AAAA,IACF;AACA,UAAM,QAAQ,MAAM,QAAQ,gBAAgB,oBAAoB,UAAU,KAAK;AAC/E,WAAO,aAAa,KAAK,EAAE,MAAM,CAAC;AAAA,EACpC,SAAS,OAAO;AACd,WAAO,MAAM,sBAAsB,KAAK;AAAA,EAC1C;AACF;AAEO,MAAM,UAAU,qBAAqB;AAAA,EAC1C,SAAS;AAAA,EACT,SAAS;AAAA,IACP,KAAK;AAAA,MACH,SAAS;AAAA,MACT,OAAO;AAAA,MACP,WAAW;AAAA,QACT,EAAE,QAAQ,KAAK,aAAa,uBAAuB,QAAQ,6BAA6B;AAAA,MAC1F;AAAA,MACA,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,2CAA2C,QAAQ,oBAAoB;AAAA,QACnG,EAAE,QAAQ,KAAK,aAAa,gBAAgB,QAAQ,oBAAoB;AAAA,QACxE,EAAE,QAAQ,KAAK,aAAa,iDAAiD,QAAQ,oBAAoB;AAAA,MAC3G;AAAA,IACF;AAAA,EACF;AACF,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -22,11 +22,13 @@ registerCommand({
|
|
|
22
22
|
}
|
|
23
23
|
const enforcementService = ctx.container.resolve("mfaEnforcementService");
|
|
24
24
|
const isSuperAdmin = await resolveIsSuperAdmin({ auth: ctx.auth, container: ctx.container });
|
|
25
|
+
const scope = {
|
|
26
|
+
tenantId: ctx.auth.tenantId ?? null,
|
|
27
|
+
organizationId: ctx.auth.orgId ?? null,
|
|
28
|
+
isSuperAdmin
|
|
29
|
+
};
|
|
25
30
|
try {
|
|
26
|
-
const policy = await enforcementService.createPolicy(parsed.data, ctx.auth.sub,
|
|
27
|
-
tenantId: ctx.auth.tenantId ?? null,
|
|
28
|
-
isSuperAdmin
|
|
29
|
-
});
|
|
31
|
+
const policy = await enforcementService.createPolicy(parsed.data, ctx.auth.sub, scope);
|
|
30
32
|
return { id: policy.id };
|
|
31
33
|
} catch (error) {
|
|
32
34
|
if (isEnforcementServiceError(error)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/security/commands/createEnforcementPolicy.ts"],
|
|
4
|
-
"sourcesContent": ["import { z } from 'zod'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { resolveIsSuperAdmin } from '@open-mercato/core/modules/auth/lib/tenantAccess'\nimport { enforcementPolicySchema } from '../data/validators'\nimport type { MfaEnforcementService } from '../services/MfaEnforcementService'\n\nexport const commandId = 'security.enforcement.create'\n\nconst commandSchema = enforcementPolicySchema\n\ntype CommandInput = z.infer<typeof commandSchema>\n\ntype EnforcementServiceErrorLike = Error & {\n statusCode: number\n}\n\nfunction isEnforcementServiceError(error: unknown): error is EnforcementServiceErrorLike {\n if (!(error instanceof Error)) return false\n const maybe = error as Partial<EnforcementServiceErrorLike>\n return error.name === 'MfaEnforcementServiceError' && typeof maybe.statusCode === 'number'\n}\n\nregisterCommand({\n id: commandId,\n async execute(rawInput, ctx) {\n if (!ctx.auth?.sub) {\n throw new CrudHttpError(401, { error: 'Unauthorized' })\n }\n\n const parsed = commandSchema.safeParse(rawInput)\n if (!parsed.success) {\n throw new CrudHttpError(400, { error: 'Invalid payload', issues: parsed.error.issues })\n }\n\n const enforcementService = ctx.container.resolve<MfaEnforcementService>('mfaEnforcementService')\n const isSuperAdmin = await resolveIsSuperAdmin({ auth: ctx.auth, container: ctx.container })\n try {\n const policy = await enforcementService.createPolicy(parsed.data, ctx.auth.sub,
|
|
5
|
-
"mappings": "AACA,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,SAAS,2BAA2B;AACpC,SAAS,+BAA+B;AAGjC,MAAM,YAAY;AAEzB,MAAM,gBAAgB;AAQtB,SAAS,0BAA0B,OAAsD;AACvF,MAAI,EAAE,iBAAiB,OAAQ,QAAO;AACtC,QAAM,QAAQ;AACd,SAAO,MAAM,SAAS,gCAAgC,OAAO,MAAM,eAAe;AACpF;AAEA,gBAAgB;AAAA,EACd,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,QAAI,CAAC,IAAI,MAAM,KAAK;AAClB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,eAAe,CAAC;AAAA,IACxD;AAEA,UAAM,SAAS,cAAc,UAAU,QAAQ;AAC/C,QAAI,CAAC,OAAO,SAAS;AACnB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,mBAAmB,QAAQ,OAAO,MAAM,OAAO,CAAC;AAAA,IACxF;AAEA,UAAM,qBAAqB,IAAI,UAAU,QAA+B,uBAAuB;AAC/F,UAAM,eAAe,MAAM,oBAAoB,EAAE,MAAM,IAAI,MAAM,WAAW,IAAI,UAAU,CAAC;AAC3F,QAAI;AACF,YAAM,SAAS,MAAM,mBAAmB,aAAa,OAAO,MAAM,IAAI,KAAK,KAAK
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { resolveIsSuperAdmin } from '@open-mercato/core/modules/auth/lib/tenantAccess'\nimport { enforcementPolicySchema } from '../data/validators'\nimport type { MfaEnforcementAuthScope, MfaEnforcementService } from '../services/MfaEnforcementService'\n\nexport const commandId = 'security.enforcement.create'\n\nconst commandSchema = enforcementPolicySchema\n\ntype CommandInput = z.infer<typeof commandSchema>\n\ntype EnforcementServiceErrorLike = Error & {\n statusCode: number\n}\n\nfunction isEnforcementServiceError(error: unknown): error is EnforcementServiceErrorLike {\n if (!(error instanceof Error)) return false\n const maybe = error as Partial<EnforcementServiceErrorLike>\n return error.name === 'MfaEnforcementServiceError' && typeof maybe.statusCode === 'number'\n}\n\nregisterCommand({\n id: commandId,\n async execute(rawInput, ctx) {\n if (!ctx.auth?.sub) {\n throw new CrudHttpError(401, { error: 'Unauthorized' })\n }\n\n const parsed = commandSchema.safeParse(rawInput)\n if (!parsed.success) {\n throw new CrudHttpError(400, { error: 'Invalid payload', issues: parsed.error.issues })\n }\n\n const enforcementService = ctx.container.resolve<MfaEnforcementService>('mfaEnforcementService')\n const isSuperAdmin = await resolveIsSuperAdmin({ auth: ctx.auth, container: ctx.container })\n const scope: MfaEnforcementAuthScope = {\n tenantId: (ctx.auth.tenantId as string | null | undefined) ?? null,\n organizationId: (ctx.auth.orgId as string | null | undefined) ?? null,\n isSuperAdmin,\n }\n try {\n const policy = await enforcementService.createPolicy(parsed.data, ctx.auth.sub, scope)\n return { id: policy.id }\n } catch (error) {\n if (isEnforcementServiceError(error)) {\n throw new CrudHttpError(error.statusCode, { error: error.message })\n }\n throw error\n }\n },\n async buildLog({ input, result, ctx }) {\n const { translate } = await resolveTranslations()\n const payload = input as CommandInput\n const commandResult = result as { id: string }\n return {\n actionLabel: translate('security.audit.enforcement.create', 'Create enforcement policy'),\n resourceKind: 'security.enforcement_policy',\n resourceId: commandResult.id,\n tenantId: payload.tenantId ?? null,\n organizationId: payload.organizationId ?? null,\n actorUserId: ctx.auth?.sub ?? null,\n payload,\n context: {\n source: 'security.enforcement',\n },\n }\n },\n})\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,SAAS,2BAA2B;AACpC,SAAS,+BAA+B;AAGjC,MAAM,YAAY;AAEzB,MAAM,gBAAgB;AAQtB,SAAS,0BAA0B,OAAsD;AACvF,MAAI,EAAE,iBAAiB,OAAQ,QAAO;AACtC,QAAM,QAAQ;AACd,SAAO,MAAM,SAAS,gCAAgC,OAAO,MAAM,eAAe;AACpF;AAEA,gBAAgB;AAAA,EACd,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,QAAI,CAAC,IAAI,MAAM,KAAK;AAClB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,eAAe,CAAC;AAAA,IACxD;AAEA,UAAM,SAAS,cAAc,UAAU,QAAQ;AAC/C,QAAI,CAAC,OAAO,SAAS;AACnB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,mBAAmB,QAAQ,OAAO,MAAM,OAAO,CAAC;AAAA,IACxF;AAEA,UAAM,qBAAqB,IAAI,UAAU,QAA+B,uBAAuB;AAC/F,UAAM,eAAe,MAAM,oBAAoB,EAAE,MAAM,IAAI,MAAM,WAAW,IAAI,UAAU,CAAC;AAC3F,UAAM,QAAiC;AAAA,MACrC,UAAW,IAAI,KAAK,YAA0C;AAAA,MAC9D,gBAAiB,IAAI,KAAK,SAAuC;AAAA,MACjE;AAAA,IACF;AACA,QAAI;AACF,YAAM,SAAS,MAAM,mBAAmB,aAAa,OAAO,MAAM,IAAI,KAAK,KAAK,KAAK;AACrF,aAAO,EAAE,IAAI,OAAO,GAAG;AAAA,IACzB,SAAS,OAAO;AACd,UAAI,0BAA0B,KAAK,GAAG;AACpC,cAAM,IAAI,cAAc,MAAM,YAAY,EAAE,OAAO,MAAM,QAAQ,CAAC;AAAA,MACpE;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EACA,MAAM,SAAS,EAAE,OAAO,QAAQ,IAAI,GAAG;AACrC,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAM,UAAU;AAChB,UAAM,gBAAgB;AACtB,WAAO;AAAA,MACL,aAAa,UAAU,qCAAqC,2BAA2B;AAAA,MACvF,cAAc;AAAA,MACd,YAAY,cAAc;AAAA,MAC1B,UAAU,QAAQ,YAAY;AAAA,MAC9B,gBAAgB,QAAQ,kBAAkB;AAAA,MAC1C,aAAa,IAAI,MAAM,OAAO;AAAA,MAC9B;AAAA,MACA,SAAS;AAAA,QACP,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AACF,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -24,11 +24,13 @@ registerCommand({
|
|
|
24
24
|
}
|
|
25
25
|
const enforcementService = ctx.container.resolve("mfaEnforcementService");
|
|
26
26
|
const isSuperAdmin = await resolveIsSuperAdmin({ auth: ctx.auth, container: ctx.container });
|
|
27
|
+
const scope = {
|
|
28
|
+
tenantId: ctx.auth.tenantId ?? null,
|
|
29
|
+
organizationId: ctx.auth.orgId ?? null,
|
|
30
|
+
isSuperAdmin
|
|
31
|
+
};
|
|
27
32
|
try {
|
|
28
|
-
await enforcementService.deletePolicy(parsed.data.id,
|
|
29
|
-
tenantId: ctx.auth.tenantId ?? null,
|
|
30
|
-
isSuperAdmin
|
|
31
|
-
});
|
|
33
|
+
await enforcementService.deletePolicy(parsed.data.id, scope);
|
|
32
34
|
return { ok: true };
|
|
33
35
|
} catch (error) {
|
|
34
36
|
if (isEnforcementServiceError(error)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/security/commands/deleteEnforcementPolicy.ts"],
|
|
4
|
-
"sourcesContent": ["import { z } from 'zod'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { resolveIsSuperAdmin } from '@open-mercato/core/modules/auth/lib/tenantAccess'\nimport type {
|
|
5
|
-
"mappings": "AAAA,SAAS,SAAS;AAClB,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,SAAS,2BAA2B;
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { resolveIsSuperAdmin } from '@open-mercato/core/modules/auth/lib/tenantAccess'\nimport type {\n MfaEnforcementAuthScope,\n MfaEnforcementService,\n} from '../services/MfaEnforcementService'\n\nexport const commandId = 'security.enforcement.delete'\n\nconst commandSchema = z.object({\n id: z.string().uuid(),\n})\n\ntype CommandInput = z.infer<typeof commandSchema>\n\ntype EnforcementServiceErrorLike = Error & {\n statusCode: number\n}\n\nfunction isEnforcementServiceError(error: unknown): error is EnforcementServiceErrorLike {\n if (!(error instanceof Error)) return false\n const maybe = error as Partial<EnforcementServiceErrorLike>\n return error.name === 'MfaEnforcementServiceError' && typeof maybe.statusCode === 'number'\n}\n\nregisterCommand({\n id: commandId,\n async execute(rawInput, ctx) {\n if (!ctx.auth?.sub) {\n throw new CrudHttpError(401, { error: 'Unauthorized' })\n }\n\n const parsed = commandSchema.safeParse(rawInput)\n if (!parsed.success) {\n throw new CrudHttpError(400, { error: 'Invalid payload', issues: parsed.error.issues })\n }\n\n const enforcementService = ctx.container.resolve<MfaEnforcementService>('mfaEnforcementService')\n const isSuperAdmin = await resolveIsSuperAdmin({ auth: ctx.auth, container: ctx.container })\n const scope: MfaEnforcementAuthScope = {\n tenantId: (ctx.auth.tenantId as string | null | undefined) ?? null,\n organizationId: (ctx.auth.orgId as string | null | undefined) ?? null,\n isSuperAdmin,\n }\n try {\n await enforcementService.deletePolicy(parsed.data.id, scope)\n return { ok: true as const }\n } catch (error) {\n if (isEnforcementServiceError(error)) {\n throw new CrudHttpError(error.statusCode, { error: error.message })\n }\n throw error\n }\n },\n async buildLog({ input, ctx }) {\n const { translate } = await resolveTranslations()\n const payload = input as CommandInput\n return {\n actionLabel: translate('security.audit.enforcement.delete', 'Delete enforcement policy'),\n resourceKind: 'security.enforcement_policy',\n resourceId: payload.id,\n actorUserId: ctx.auth?.sub ?? null,\n payload,\n context: {\n source: 'security.enforcement',\n },\n }\n },\n})\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,SAAS;AAClB,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,SAAS,2BAA2B;AAM7B,MAAM,YAAY;AAEzB,MAAM,gBAAgB,EAAE,OAAO;AAAA,EAC7B,IAAI,EAAE,OAAO,EAAE,KAAK;AACtB,CAAC;AAQD,SAAS,0BAA0B,OAAsD;AACvF,MAAI,EAAE,iBAAiB,OAAQ,QAAO;AACtC,QAAM,QAAQ;AACd,SAAO,MAAM,SAAS,gCAAgC,OAAO,MAAM,eAAe;AACpF;AAEA,gBAAgB;AAAA,EACd,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,QAAI,CAAC,IAAI,MAAM,KAAK;AAClB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,eAAe,CAAC;AAAA,IACxD;AAEA,UAAM,SAAS,cAAc,UAAU,QAAQ;AAC/C,QAAI,CAAC,OAAO,SAAS;AACnB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,mBAAmB,QAAQ,OAAO,MAAM,OAAO,CAAC;AAAA,IACxF;AAEA,UAAM,qBAAqB,IAAI,UAAU,QAA+B,uBAAuB;AAC/F,UAAM,eAAe,MAAM,oBAAoB,EAAE,MAAM,IAAI,MAAM,WAAW,IAAI,UAAU,CAAC;AAC3F,UAAM,QAAiC;AAAA,MACrC,UAAW,IAAI,KAAK,YAA0C;AAAA,MAC9D,gBAAiB,IAAI,KAAK,SAAuC;AAAA,MACjE;AAAA,IACF;AACA,QAAI;AACF,YAAM,mBAAmB,aAAa,OAAO,KAAK,IAAI,KAAK;AAC3D,aAAO,EAAE,IAAI,KAAc;AAAA,IAC7B,SAAS,OAAO;AACd,UAAI,0BAA0B,KAAK,GAAG;AACpC,cAAM,IAAI,cAAc,MAAM,YAAY,EAAE,OAAO,MAAM,QAAQ,CAAC;AAAA,MACpE;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EACA,MAAM,SAAS,EAAE,OAAO,IAAI,GAAG;AAC7B,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAM,UAAU;AAChB,WAAO;AAAA,MACL,aAAa,UAAU,qCAAqC,2BAA2B;AAAA,MACvF,cAAc;AAAA,MACd,YAAY,QAAQ;AAAA,MACpB,aAAa,IAAI,MAAM,OAAO;AAAA,MAC9B;AAAA,MACA,SAAS;AAAA,QACP,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AACF,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -25,11 +25,18 @@ registerCommand({
|
|
|
25
25
|
}
|
|
26
26
|
const mfaAdminService = ctx.container.resolve("mfaAdminService");
|
|
27
27
|
const isSuperAdmin = await resolveIsSuperAdmin({ auth: ctx.auth, container: ctx.container });
|
|
28
|
+
const scope = {
|
|
29
|
+
tenantId: ctx.auth.tenantId ?? null,
|
|
30
|
+
organizationId: ctx.auth.orgId ?? null,
|
|
31
|
+
isSuperAdmin
|
|
32
|
+
};
|
|
28
33
|
try {
|
|
29
|
-
await mfaAdminService.resetUserMfa(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
await mfaAdminService.resetUserMfa(
|
|
35
|
+
ctx.auth.sub,
|
|
36
|
+
parsed.data.userId,
|
|
37
|
+
parsed.data.reason,
|
|
38
|
+
scope
|
|
39
|
+
);
|
|
33
40
|
return { ok: true };
|
|
34
41
|
} catch (error) {
|
|
35
42
|
if (isMfaAdminServiceError(error)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/security/commands/resetUserMfa.ts"],
|
|
4
|
-
"sourcesContent": ["import { z } from 'zod'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { resolveIsSuperAdmin } from '@open-mercato/core/modules/auth/lib/tenantAccess'\nimport type { MfaAdminService } from '../services/MfaAdminService'\n\nexport const commandId = 'security.admin.mfa.reset'\n\nconst commandSchema = z.object({\n userId: z.string().uuid(),\n reason: z.string().min(1),\n})\n\ntype CommandInput = z.infer<typeof commandSchema>\n\ntype MfaAdminServiceErrorLike = Error & {\n statusCode: number\n}\n\nfunction isMfaAdminServiceError(error: unknown): error is MfaAdminServiceErrorLike {\n if (!(error instanceof Error)) return false\n const maybe = error as Partial<MfaAdminServiceErrorLike>\n return error.name === 'MfaAdminServiceError' && typeof maybe.statusCode === 'number'\n}\n\nregisterCommand({\n id: commandId,\n async execute(rawInput, ctx) {\n if (!ctx.auth?.sub) {\n throw new CrudHttpError(401, { error: 'Unauthorized' })\n }\n\n const parsed = commandSchema.safeParse(rawInput)\n if (!parsed.success) {\n throw new CrudHttpError(400, { error: 'Invalid payload', issues: parsed.error.issues })\n }\n\n const mfaAdminService = ctx.container.resolve<MfaAdminService>('mfaAdminService')\n const isSuperAdmin = await resolveIsSuperAdmin({ auth: ctx.auth, container: ctx.container })\n try {\n await mfaAdminService.resetUserMfa(ctx.auth.sub
|
|
5
|
-
"mappings": "AAAA,SAAS,SAAS;AAClB,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,SAAS,2BAA2B;AAG7B,MAAM,YAAY;AAEzB,MAAM,gBAAgB,EAAE,OAAO;AAAA,EAC7B,QAAQ,EAAE,OAAO,EAAE,KAAK;AAAA,EACxB,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC;AAC1B,CAAC;AAQD,SAAS,uBAAuB,OAAmD;AACjF,MAAI,EAAE,iBAAiB,OAAQ,QAAO;AACtC,QAAM,QAAQ;AACd,SAAO,MAAM,SAAS,0BAA0B,OAAO,MAAM,eAAe;AAC9E;AAEA,gBAAgB;AAAA,EACd,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,QAAI,CAAC,IAAI,MAAM,KAAK;AAClB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,eAAe,CAAC;AAAA,IACxD;AAEA,UAAM,SAAS,cAAc,UAAU,QAAQ;AAC/C,QAAI,CAAC,OAAO,SAAS;AACnB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,mBAAmB,QAAQ,OAAO,MAAM,OAAO,CAAC;AAAA,IACxF;AAEA,UAAM,kBAAkB,IAAI,UAAU,QAAyB,iBAAiB;AAChF,UAAM,eAAe,MAAM,oBAAoB,EAAE,MAAM,IAAI,MAAM,WAAW,IAAI,UAAU,CAAC;AAC3F,
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { resolveIsSuperAdmin } from '@open-mercato/core/modules/auth/lib/tenantAccess'\nimport type { MfaAdminAuthScope, MfaAdminService } from '../services/MfaAdminService'\n\nexport const commandId = 'security.admin.mfa.reset'\n\nconst commandSchema = z.object({\n userId: z.string().uuid(),\n reason: z.string().min(1),\n})\n\ntype CommandInput = z.infer<typeof commandSchema>\n\ntype MfaAdminServiceErrorLike = Error & {\n statusCode: number\n}\n\nfunction isMfaAdminServiceError(error: unknown): error is MfaAdminServiceErrorLike {\n if (!(error instanceof Error)) return false\n const maybe = error as Partial<MfaAdminServiceErrorLike>\n return error.name === 'MfaAdminServiceError' && typeof maybe.statusCode === 'number'\n}\n\nregisterCommand({\n id: commandId,\n async execute(rawInput, ctx) {\n if (!ctx.auth?.sub) {\n throw new CrudHttpError(401, { error: 'Unauthorized' })\n }\n\n const parsed = commandSchema.safeParse(rawInput)\n if (!parsed.success) {\n throw new CrudHttpError(400, { error: 'Invalid payload', issues: parsed.error.issues })\n }\n\n const mfaAdminService = ctx.container.resolve<MfaAdminService>('mfaAdminService')\n const isSuperAdmin = await resolveIsSuperAdmin({ auth: ctx.auth, container: ctx.container })\n const scope: MfaAdminAuthScope = {\n tenantId: (ctx.auth.tenantId as string | null | undefined) ?? null,\n organizationId: (ctx.auth.orgId as string | null | undefined) ?? null,\n isSuperAdmin,\n }\n try {\n await mfaAdminService.resetUserMfa(\n ctx.auth.sub,\n parsed.data.userId,\n parsed.data.reason,\n scope,\n )\n return { ok: true as const }\n } catch (error) {\n if (isMfaAdminServiceError(error)) {\n throw new CrudHttpError(error.statusCode, { error: error.message })\n }\n throw error\n }\n },\n async buildLog({ input, ctx }) {\n const { translate } = await resolveTranslations()\n const payload = input as CommandInput\n return {\n actionLabel: translate('security.audit.mfa.reset', 'Reset user MFA'),\n resourceKind: 'security.user_mfa',\n resourceId: payload.userId,\n actorUserId: ctx.auth?.sub ?? null,\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.auth?.orgId ?? null,\n payload,\n context: {\n source: 'security.admin.users',\n },\n }\n },\n})\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,SAAS;AAClB,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,SAAS,2BAA2B;AAG7B,MAAM,YAAY;AAEzB,MAAM,gBAAgB,EAAE,OAAO;AAAA,EAC7B,QAAQ,EAAE,OAAO,EAAE,KAAK;AAAA,EACxB,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC;AAC1B,CAAC;AAQD,SAAS,uBAAuB,OAAmD;AACjF,MAAI,EAAE,iBAAiB,OAAQ,QAAO;AACtC,QAAM,QAAQ;AACd,SAAO,MAAM,SAAS,0BAA0B,OAAO,MAAM,eAAe;AAC9E;AAEA,gBAAgB;AAAA,EACd,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,QAAI,CAAC,IAAI,MAAM,KAAK;AAClB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,eAAe,CAAC;AAAA,IACxD;AAEA,UAAM,SAAS,cAAc,UAAU,QAAQ;AAC/C,QAAI,CAAC,OAAO,SAAS;AACnB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,mBAAmB,QAAQ,OAAO,MAAM,OAAO,CAAC;AAAA,IACxF;AAEA,UAAM,kBAAkB,IAAI,UAAU,QAAyB,iBAAiB;AAChF,UAAM,eAAe,MAAM,oBAAoB,EAAE,MAAM,IAAI,MAAM,WAAW,IAAI,UAAU,CAAC;AAC3F,UAAM,QAA2B;AAAA,MAC/B,UAAW,IAAI,KAAK,YAA0C;AAAA,MAC9D,gBAAiB,IAAI,KAAK,SAAuC;AAAA,MACjE;AAAA,IACF;AACA,QAAI;AACF,YAAM,gBAAgB;AAAA,QACpB,IAAI,KAAK;AAAA,QACT,OAAO,KAAK;AAAA,QACZ,OAAO,KAAK;AAAA,QACZ;AAAA,MACF;AACA,aAAO,EAAE,IAAI,KAAc;AAAA,IAC7B,SAAS,OAAO;AACd,UAAI,uBAAuB,KAAK,GAAG;AACjC,cAAM,IAAI,cAAc,MAAM,YAAY,EAAE,OAAO,MAAM,QAAQ,CAAC;AAAA,MACpE;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EACA,MAAM,SAAS,EAAE,OAAO,IAAI,GAAG;AAC7B,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAM,UAAU;AAChB,WAAO;AAAA,MACL,aAAa,UAAU,4BAA4B,gBAAgB;AAAA,MACnE,cAAc;AAAA,MACd,YAAY,QAAQ;AAAA,MACpB,aAAa,IAAI,MAAM,OAAO;AAAA,MAC9B,UAAU,IAAI,MAAM,YAAY;AAAA,MAChC,gBAAgB,IAAI,MAAM,SAAS;AAAA,MACnC;AAAA,MACA,SAAS;AAAA,QACP,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AACF,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -26,11 +26,13 @@ registerCommand({
|
|
|
26
26
|
}
|
|
27
27
|
const enforcementService = ctx.container.resolve("mfaEnforcementService");
|
|
28
28
|
const isSuperAdmin = await resolveIsSuperAdmin({ auth: ctx.auth, container: ctx.container });
|
|
29
|
+
const scope = {
|
|
30
|
+
tenantId: ctx.auth.tenantId ?? null,
|
|
31
|
+
organizationId: ctx.auth.orgId ?? null,
|
|
32
|
+
isSuperAdmin
|
|
33
|
+
};
|
|
29
34
|
try {
|
|
30
|
-
await enforcementService.updatePolicy(parsed.data.id, parsed.data.data, ctx.auth.sub,
|
|
31
|
-
tenantId: ctx.auth.tenantId ?? null,
|
|
32
|
-
isSuperAdmin
|
|
33
|
-
});
|
|
35
|
+
await enforcementService.updatePolicy(parsed.data.id, parsed.data.data, ctx.auth.sub, scope);
|
|
34
36
|
return { ok: true };
|
|
35
37
|
} catch (error) {
|
|
36
38
|
if (isEnforcementServiceError(error)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/security/commands/updateEnforcementPolicy.ts"],
|
|
4
|
-
"sourcesContent": ["import { z } from 'zod'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { resolveIsSuperAdmin } from '@open-mercato/core/modules/auth/lib/tenantAccess'\nimport { updateEnforcementPolicySchema } from '../data/validators'\nimport type {
|
|
5
|
-
"mappings": "AAAA,SAAS,SAAS;AAClB,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,SAAS,2BAA2B;AACpC,SAAS,qCAAqC;
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { resolveIsSuperAdmin } from '@open-mercato/core/modules/auth/lib/tenantAccess'\nimport { updateEnforcementPolicySchema } from '../data/validators'\nimport type {\n MfaEnforcementAuthScope,\n MfaEnforcementService,\n} from '../services/MfaEnforcementService'\n\nexport const commandId = 'security.enforcement.update'\n\nconst commandSchema = z.object({\n id: z.string().uuid(),\n data: updateEnforcementPolicySchema,\n})\n\ntype CommandInput = z.infer<typeof commandSchema>\n\ntype EnforcementServiceErrorLike = Error & {\n statusCode: number\n}\n\nfunction isEnforcementServiceError(error: unknown): error is EnforcementServiceErrorLike {\n if (!(error instanceof Error)) return false\n const maybe = error as Partial<EnforcementServiceErrorLike>\n return error.name === 'MfaEnforcementServiceError' && typeof maybe.statusCode === 'number'\n}\n\nregisterCommand({\n id: commandId,\n async execute(rawInput, ctx) {\n if (!ctx.auth?.sub) {\n throw new CrudHttpError(401, { error: 'Unauthorized' })\n }\n\n const parsed = commandSchema.safeParse(rawInput)\n if (!parsed.success) {\n throw new CrudHttpError(400, { error: 'Invalid payload', issues: parsed.error.issues })\n }\n\n const enforcementService = ctx.container.resolve<MfaEnforcementService>('mfaEnforcementService')\n const isSuperAdmin = await resolveIsSuperAdmin({ auth: ctx.auth, container: ctx.container })\n const scope: MfaEnforcementAuthScope = {\n tenantId: (ctx.auth.tenantId as string | null | undefined) ?? null,\n organizationId: (ctx.auth.orgId as string | null | undefined) ?? null,\n isSuperAdmin,\n }\n try {\n await enforcementService.updatePolicy(parsed.data.id, parsed.data.data, ctx.auth.sub, scope)\n return { ok: true as const }\n } catch (error) {\n if (isEnforcementServiceError(error)) {\n throw new CrudHttpError(error.statusCode, { error: error.message })\n }\n throw error\n }\n },\n async buildLog({ input, ctx }) {\n const { translate } = await resolveTranslations()\n const payload = input as CommandInput\n return {\n actionLabel: translate('security.audit.enforcement.update', 'Update enforcement policy'),\n resourceKind: 'security.enforcement_policy',\n resourceId: payload.id,\n tenantId: payload.data.tenantId ?? null,\n organizationId: payload.data.organizationId ?? null,\n actorUserId: ctx.auth?.sub ?? null,\n payload,\n context: {\n source: 'security.enforcement',\n },\n }\n },\n})\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,SAAS;AAClB,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,SAAS,2BAA2B;AACpC,SAAS,qCAAqC;AAMvC,MAAM,YAAY;AAEzB,MAAM,gBAAgB,EAAE,OAAO;AAAA,EAC7B,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,EACpB,MAAM;AACR,CAAC;AAQD,SAAS,0BAA0B,OAAsD;AACvF,MAAI,EAAE,iBAAiB,OAAQ,QAAO;AACtC,QAAM,QAAQ;AACd,SAAO,MAAM,SAAS,gCAAgC,OAAO,MAAM,eAAe;AACpF;AAEA,gBAAgB;AAAA,EACd,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,QAAI,CAAC,IAAI,MAAM,KAAK;AAClB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,eAAe,CAAC;AAAA,IACxD;AAEA,UAAM,SAAS,cAAc,UAAU,QAAQ;AAC/C,QAAI,CAAC,OAAO,SAAS;AACnB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,mBAAmB,QAAQ,OAAO,MAAM,OAAO,CAAC;AAAA,IACxF;AAEA,UAAM,qBAAqB,IAAI,UAAU,QAA+B,uBAAuB;AAC/F,UAAM,eAAe,MAAM,oBAAoB,EAAE,MAAM,IAAI,MAAM,WAAW,IAAI,UAAU,CAAC;AAC3F,UAAM,QAAiC;AAAA,MACrC,UAAW,IAAI,KAAK,YAA0C;AAAA,MAC9D,gBAAiB,IAAI,KAAK,SAAuC;AAAA,MACjE;AAAA,IACF;AACA,QAAI;AACF,YAAM,mBAAmB,aAAa,OAAO,KAAK,IAAI,OAAO,KAAK,MAAM,IAAI,KAAK,KAAK,KAAK;AAC3F,aAAO,EAAE,IAAI,KAAc;AAAA,IAC7B,SAAS,OAAO;AACd,UAAI,0BAA0B,KAAK,GAAG;AACpC,cAAM,IAAI,cAAc,MAAM,YAAY,EAAE,OAAO,MAAM,QAAQ,CAAC;AAAA,MACpE;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EACA,MAAM,SAAS,EAAE,OAAO,IAAI,GAAG;AAC7B,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAM,UAAU;AAChB,WAAO;AAAA,MACL,aAAa,UAAU,qCAAqC,2BAA2B;AAAA,MACvF,cAAc;AAAA,MACd,YAAY,QAAQ;AAAA,MACpB,UAAU,QAAQ,KAAK,YAAY;AAAA,MACnC,gBAAgB,QAAQ,KAAK,kBAAkB;AAAA,MAC/C,aAAa,IAAI,MAAM,OAAO;AAAA,MAC9B;AAAA,MACA,SAAS;AAAA,QACP,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AACF,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -224,10 +224,12 @@
|
|
|
224
224
|
"security.api.errors.adminIdRequired": "Eine Administrator-ID ist erforderlich.",
|
|
225
225
|
"security.api.errors.challengeIdAndMethodTypeRequired": "challengeId und methodType sind erforderlich.",
|
|
226
226
|
"security.api.errors.codeRequired": "code ist erforderlich.",
|
|
227
|
+
"security.api.errors.crossTenantAccessDenied": "Tenantübergreifender Zugriff verweigert.",
|
|
227
228
|
"security.api.errors.emailOtpDestinationMissing": "Bei der E-Mail-OTP-Methode fehlt die Ziel-E-Mail-Adresse.",
|
|
228
229
|
"security.api.errors.emailOtpDestinationRequired": "E-Mail-OTP kann ohne Ziel-E-Mail-Adresse nicht konfiguriert werden.",
|
|
229
230
|
"security.api.errors.emailOtpSetupSessionExpired": "Die E-Mail-OTP-Einrichtungssitzung ist abgelaufen.",
|
|
230
231
|
"security.api.errors.emailOtpSetupSessionNotFound": "Die E-Mail-OTP-Einrichtungssitzung wurde nicht gefunden.",
|
|
232
|
+
"security.api.errors.enforcementInsufficientScope": "Unzureichende Berechtigung für diese Enforcement-Richtlinie.",
|
|
231
233
|
"security.api.errors.enforcementOrganizationScopeFormat": "Die Organisations-scopeId muss das Format '<tenantId>:<organizationId>' verwenden.",
|
|
232
234
|
"security.api.errors.enforcementOrganizationScopeIdsRequired": "tenantId und organizationId sind für den Organisationsbereich erforderlich.",
|
|
233
235
|
"security.api.errors.enforcementPolicyAlreadyExistsForScope": "Für diesen Geltungsbereich existiert bereits eine Enforcement-Richtlinie.",
|
|
@@ -282,6 +284,7 @@
|
|
|
282
284
|
"security.api.errors.sudoVerifyFailed": "Die Sudo-Challenge konnte nicht verifiziert werden.",
|
|
283
285
|
"security.api.errors.tenantContextRequired": "Ein Tenant-Kontext ist erforderlich.",
|
|
284
286
|
"security.api.errors.tenantIdRequired": "Eine Tenant-ID ist erforderlich.",
|
|
287
|
+
"security.api.errors.tenantNotFound": "Tenant nicht gefunden.",
|
|
285
288
|
"security.api.errors.totpSetupSessionExpired": "Die TOTP-Einrichtungssitzung ist abgelaufen.",
|
|
286
289
|
"security.api.errors.totpSetupSessionNotFound": "Die TOTP-Einrichtungssitzung wurde nicht gefunden.",
|
|
287
290
|
"security.api.errors.userIdRequired": "Eine Benutzer-ID ist erforderlich.",
|
|
@@ -224,10 +224,12 @@
|
|
|
224
224
|
"security.api.errors.adminIdRequired": "Admin ID is required.",
|
|
225
225
|
"security.api.errors.challengeIdAndMethodTypeRequired": "challengeId and methodType are required.",
|
|
226
226
|
"security.api.errors.codeRequired": "code is required.",
|
|
227
|
+
"security.api.errors.crossTenantAccessDenied": "Cross-tenant access denied.",
|
|
227
228
|
"security.api.errors.emailOtpDestinationMissing": "The email OTP method is missing a destination email address.",
|
|
228
229
|
"security.api.errors.emailOtpDestinationRequired": "Unable to configure email OTP without a destination email address.",
|
|
229
230
|
"security.api.errors.emailOtpSetupSessionExpired": "Email OTP setup session expired.",
|
|
230
231
|
"security.api.errors.emailOtpSetupSessionNotFound": "Email OTP setup session not found.",
|
|
232
|
+
"security.api.errors.enforcementInsufficientScope": "Insufficient scope for enforcement policy.",
|
|
231
233
|
"security.api.errors.enforcementOrganizationScopeFormat": "Organisation scopeId must use '<tenantId>:<organizationId>' format.",
|
|
232
234
|
"security.api.errors.enforcementOrganizationScopeIdsRequired": "tenantId and organizationId are required for organisation scope.",
|
|
233
235
|
"security.api.errors.enforcementPolicyAlreadyExistsForScope": "An enforcement policy already exists for this scope.",
|
|
@@ -282,6 +284,7 @@
|
|
|
282
284
|
"security.api.errors.sudoVerifyFailed": "Unable to verify the sudo challenge.",
|
|
283
285
|
"security.api.errors.tenantContextRequired": "Tenant context is required.",
|
|
284
286
|
"security.api.errors.tenantIdRequired": "Tenant ID is required.",
|
|
287
|
+
"security.api.errors.tenantNotFound": "Tenant not found.",
|
|
285
288
|
"security.api.errors.totpSetupSessionExpired": "TOTP setup session expired.",
|
|
286
289
|
"security.api.errors.totpSetupSessionNotFound": "TOTP setup session not found.",
|
|
287
290
|
"security.api.errors.userIdRequired": "User ID is required.",
|
|
@@ -224,10 +224,12 @@
|
|
|
224
224
|
"security.api.errors.adminIdRequired": "Se requiere el ID del administrador.",
|
|
225
225
|
"security.api.errors.challengeIdAndMethodTypeRequired": "challengeId y methodType son obligatorios.",
|
|
226
226
|
"security.api.errors.codeRequired": "code es obligatorio.",
|
|
227
|
+
"security.api.errors.crossTenantAccessDenied": "Acceso entre inquilinos denegado.",
|
|
227
228
|
"security.api.errors.emailOtpDestinationMissing": "Al método OTP por correo le falta una dirección de correo de destino.",
|
|
228
229
|
"security.api.errors.emailOtpDestinationRequired": "No se puede configurar OTP por correo electrónico sin una dirección de correo de destino.",
|
|
229
230
|
"security.api.errors.emailOtpSetupSessionExpired": "La sesión de configuración de OTP por correo ha expirado.",
|
|
230
231
|
"security.api.errors.emailOtpSetupSessionNotFound": "No se encontró la sesión de configuración de OTP por correo.",
|
|
232
|
+
"security.api.errors.enforcementInsufficientScope": "Permisos insuficientes para esta política de aplicación.",
|
|
231
233
|
"security.api.errors.enforcementOrganizationScopeFormat": "El scopeId de organización debe usar el formato '<tenantId>:<organizationId>'.",
|
|
232
234
|
"security.api.errors.enforcementOrganizationScopeIdsRequired": "tenantId y organizationId son obligatorios para el alcance de organización.",
|
|
233
235
|
"security.api.errors.enforcementPolicyAlreadyExistsForScope": "Ya existe una política de cumplimiento para este alcance.",
|
|
@@ -282,6 +284,7 @@
|
|
|
282
284
|
"security.api.errors.sudoVerifyFailed": "No se pudo verificar el desafío sudo.",
|
|
283
285
|
"security.api.errors.tenantContextRequired": "Se requiere el contexto del tenant.",
|
|
284
286
|
"security.api.errors.tenantIdRequired": "Se requiere el ID del tenant.",
|
|
287
|
+
"security.api.errors.tenantNotFound": "Tenant no encontrado.",
|
|
285
288
|
"security.api.errors.totpSetupSessionExpired": "La sesión de configuración de TOTP ha expirado.",
|
|
286
289
|
"security.api.errors.totpSetupSessionNotFound": "No se encontró la sesión de configuración de TOTP.",
|
|
287
290
|
"security.api.errors.userIdRequired": "Se requiere el ID del usuario.",
|
|
@@ -224,10 +224,12 @@
|
|
|
224
224
|
"security.api.errors.adminIdRequired": "Identyfikator administratora jest wymagany.",
|
|
225
225
|
"security.api.errors.challengeIdAndMethodTypeRequired": "Pola challengeId i methodType są wymagane.",
|
|
226
226
|
"security.api.errors.codeRequired": "Pole code jest wymagane.",
|
|
227
|
+
"security.api.errors.crossTenantAccessDenied": "Dostęp międzytenantowy został zablokowany.",
|
|
227
228
|
"security.api.errors.emailOtpDestinationMissing": "W metodzie OTP e-mail brakuje docelowego adresu e-mail.",
|
|
228
229
|
"security.api.errors.emailOtpDestinationRequired": "Nie można skonfigurować OTP e-mail bez docelowego adresu e-mail.",
|
|
229
230
|
"security.api.errors.emailOtpSetupSessionExpired": "Sesja konfiguracji OTP e-mail wygasła.",
|
|
230
231
|
"security.api.errors.emailOtpSetupSessionNotFound": "Nie znaleziono sesji konfiguracji OTP e-mail.",
|
|
232
|
+
"security.api.errors.enforcementInsufficientScope": "Niewystarczające uprawnienia do tej polityki wymuszania.",
|
|
231
233
|
"security.api.errors.enforcementOrganizationScopeFormat": "Pole scopeId dla organizacji musi mieć format '<tenantId>:<organizationId>'.",
|
|
232
234
|
"security.api.errors.enforcementOrganizationScopeIdsRequired": "Pola tenantId i organizationId są wymagane dla zakresu organizacji.",
|
|
233
235
|
"security.api.errors.enforcementPolicyAlreadyExistsForScope": "Polityka egzekwowania dla tego zakresu już istnieje.",
|
|
@@ -282,6 +284,7 @@
|
|
|
282
284
|
"security.api.errors.sudoVerifyFailed": "Nie udało się zweryfikować wyzwania sudo.",
|
|
283
285
|
"security.api.errors.tenantContextRequired": "Kontekst tenantu jest wymagany.",
|
|
284
286
|
"security.api.errors.tenantIdRequired": "Identyfikator tenantu jest wymagany.",
|
|
287
|
+
"security.api.errors.tenantNotFound": "Tenant nie został znaleziony.",
|
|
285
288
|
"security.api.errors.totpSetupSessionExpired": "Sesja konfiguracji TOTP wygasła.",
|
|
286
289
|
"security.api.errors.totpSetupSessionNotFound": "Nie znaleziono sesji konfiguracji TOTP.",
|
|
287
290
|
"security.api.errors.userIdRequired": "Identyfikator użytkownika jest wymagany.",
|