@techelusive/nest-auth 0.0.0-stage → 0.2.0
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/CHANGELOG.md +64 -0
- package/LICENSE +21 -0
- package/README.md +204 -2
- package/api/openapi.json +4399 -0
- package/api/techelusive-authentication.postman_collection.json +3178 -0
- package/dist/auth-options.d.ts +156 -0
- package/dist/auth-options.js +3 -0
- package/dist/auth-options.js.map +1 -0
- package/dist/auth-options.validation.d.ts +9 -0
- package/dist/auth-options.validation.js +74 -0
- package/dist/auth-options.validation.js.map +1 -0
- package/dist/auth.module.d.ts +38 -0
- package/dist/auth.module.js +173 -0
- package/dist/auth.module.js.map +1 -0
- package/dist/common/auth-error.d.ts +16 -0
- package/dist/common/auth-error.js +23 -0
- package/dist/common/auth-error.js.map +1 -0
- package/dist/common/auth-exception.filter.d.ts +24 -0
- package/dist/common/auth-exception.filter.js +66 -0
- package/dist/common/auth-exception.filter.js.map +1 -0
- package/dist/common/crypto/jwt.d.ts +89 -0
- package/dist/common/crypto/jwt.js +144 -0
- package/dist/common/crypto/jwt.js.map +1 -0
- package/dist/common/crypto/random-secrets.d.ts +78 -0
- package/dist/common/crypto/random-secrets.js +113 -0
- package/dist/common/crypto/random-secrets.js.map +1 -0
- package/dist/common/crypto/remote-public-keys.d.ts +49 -0
- package/dist/common/crypto/remote-public-keys.js +105 -0
- package/dist/common/crypto/remote-public-keys.js.map +1 -0
- package/dist/common/crypto/totp.d.ts +68 -0
- package/dist/common/crypto/totp.js +148 -0
- package/dist/common/crypto/totp.js.map +1 -0
- package/dist/common/encryption.service.d.ts +36 -0
- package/dist/common/encryption.service.js +111 -0
- package/dist/common/encryption.service.js.map +1 -0
- package/dist/common/identifiers.d.ts +48 -0
- package/dist/common/identifiers.js +89 -0
- package/dist/common/identifiers.js.map +1 -0
- package/dist/common/network-safety.d.ts +19 -0
- package/dist/common/network-safety.js +72 -0
- package/dist/common/network-safety.js.map +1 -0
- package/dist/common/rate-limiter.service.d.ts +63 -0
- package/dist/common/rate-limiter.service.js +158 -0
- package/dist/common/rate-limiter.service.js.map +1 -0
- package/dist/common/refresh-token-cookie.d.ts +78 -0
- package/dist/common/refresh-token-cookie.js +185 -0
- package/dist/common/refresh-token-cookie.js.map +1 -0
- package/dist/common/request-context.d.ts +14 -0
- package/dist/common/request-context.js +22 -0
- package/dist/common/request-context.js.map +1 -0
- package/dist/common/strict-validation.pipe.d.ts +8 -0
- package/dist/common/strict-validation.pipe.js +16 -0
- package/dist/common/strict-validation.pipe.js.map +1 -0
- package/dist/common/time.d.ts +15 -0
- package/dist/common/time.js +34 -0
- package/dist/common/time.js.map +1 -0
- package/dist/constants.d.ts +1326 -0
- package/dist/constants.js +1142 -0
- package/dist/constants.js.map +1 -0
- package/dist/database/create-auth-tables.migration.d.ts +26 -0
- package/dist/database/create-auth-tables.migration.js +291 -0
- package/dist/database/create-auth-tables.migration.js.map +1 -0
- package/dist/database/email-change-and-retention.migration.d.ts +25 -0
- package/dist/database/email-change-and-retention.migration.js +54 -0
- package/dist/database/email-change-and-retention.migration.js.map +1 -0
- package/dist/database/entities/api-key.entity.d.ts +17 -0
- package/dist/database/entities/api-key.entity.js +80 -0
- package/dist/database/entities/api-key.entity.js.map +1 -0
- package/dist/database/entities/audit-log.entity.d.ts +13 -0
- package/dist/database/entities/audit-log.entity.js +64 -0
- package/dist/database/entities/audit-log.entity.js.map +1 -0
- package/dist/database/entities/backup-code.entity.d.ts +9 -0
- package/dist/database/entities/backup-code.entity.js +52 -0
- package/dist/database/entities/backup-code.entity.js.map +1 -0
- package/dist/database/entities/index.d.ts +43 -0
- package/dist/database/entities/index.js +82 -0
- package/dist/database/entities/index.js.map +1 -0
- package/dist/database/entities/json-object.d.ts +12 -0
- package/dist/database/entities/json-object.js +3 -0
- package/dist/database/entities/json-object.js.map +1 -0
- package/dist/database/entities/link-token.entity.d.ts +15 -0
- package/dist/database/entities/link-token.entity.js +64 -0
- package/dist/database/entities/link-token.entity.js.map +1 -0
- package/dist/database/entities/one-time-code.entity.d.ts +16 -0
- package/dist/database/entities/one-time-code.entity.js +69 -0
- package/dist/database/entities/one-time-code.entity.js.map +1 -0
- package/dist/database/entities/organization-invitation.entity.d.ts +14 -0
- package/dist/database/entities/organization-invitation.entity.js +73 -0
- package/dist/database/entities/organization-invitation.entity.js.map +1 -0
- package/dist/database/entities/organization-member.entity.d.ts +9 -0
- package/dist/database/entities/organization-member.entity.js +48 -0
- package/dist/database/entities/organization-member.entity.js.map +1 -0
- package/dist/database/entities/organization.entity.d.ts +12 -0
- package/dist/database/entities/organization.entity.js +58 -0
- package/dist/database/entities/organization.entity.js.map +1 -0
- package/dist/database/entities/passkey.entity.d.ts +19 -0
- package/dist/database/entities/passkey.entity.js +78 -0
- package/dist/database/entities/passkey.entity.js.map +1 -0
- package/dist/database/entities/password.entity.d.ts +6 -0
- package/dist/database/entities/password.entity.js +36 -0
- package/dist/database/entities/password.entity.js.map +1 -0
- package/dist/database/entities/refresh-token.entity.d.ts +9 -0
- package/dist/database/entities/refresh-token.entity.js +53 -0
- package/dist/database/entities/refresh-token.entity.js.map +1 -0
- package/dist/database/entities/session.entity.d.ts +20 -0
- package/dist/database/entities/session.entity.js +87 -0
- package/dist/database/entities/session.entity.js.map +1 -0
- package/dist/database/entities/settings.entity.d.ts +7 -0
- package/dist/database/entities/settings.entity.js +41 -0
- package/dist/database/entities/settings.entity.js.map +1 -0
- package/dist/database/entities/sign-in-challenge.entity.d.ts +23 -0
- package/dist/database/entities/sign-in-challenge.entity.js +80 -0
- package/dist/database/entities/sign-in-challenge.entity.js.map +1 -0
- package/dist/database/entities/signing-key.entity.d.ts +11 -0
- package/dist/database/entities/signing-key.entity.js +54 -0
- package/dist/database/entities/signing-key.entity.js.map +1 -0
- package/dist/database/entities/social-account.entity.d.ts +13 -0
- package/dist/database/entities/social-account.entity.js +54 -0
- package/dist/database/entities/social-account.entity.js.map +1 -0
- package/dist/database/entities/two-factor-secret.entity.d.ts +10 -0
- package/dist/database/entities/two-factor-secret.entity.js +48 -0
- package/dist/database/entities/two-factor-secret.entity.js.map +1 -0
- package/dist/database/entities/user.entity.d.ts +34 -0
- package/dist/database/entities/user.entity.js +129 -0
- package/dist/database/entities/user.entity.js.map +1 -0
- package/dist/database/entities/webhook-delivery.entity.d.ts +17 -0
- package/dist/database/entities/webhook-delivery.entity.js +79 -0
- package/dist/database/entities/webhook-delivery.entity.js.map +1 -0
- package/dist/database/entities/webhook.entity.d.ts +12 -0
- package/dist/database/entities/webhook.entity.js +58 -0
- package/dist/database/entities/webhook.entity.js.map +1 -0
- package/dist/database/typeorm-row.d.ts +21 -0
- package/dist/database/typeorm-row.js +29 -0
- package/dist/database/typeorm-row.js.map +1 -0
- package/dist/features/account/account.controller.d.ts +259 -0
- package/dist/features/account/account.controller.js +372 -0
- package/dist/features/account/account.controller.js.map +1 -0
- package/dist/features/account/account.dto.d.ts +16 -0
- package/dist/features/account/account.dto.js +61 -0
- package/dist/features/account/account.dto.js.map +1 -0
- package/dist/features/account/data-export.service.d.ts +85 -0
- package/dist/features/account/data-export.service.js +125 -0
- package/dist/features/account/data-export.service.js.map +1 -0
- package/dist/features/account/health.service.d.ts +30 -0
- package/dist/features/account/health.service.js +59 -0
- package/dist/features/account/health.service.js.map +1 -0
- package/dist/features/admin/admin.controller.d.ts +382 -0
- package/dist/features/admin/admin.controller.js +623 -0
- package/dist/features/admin/admin.controller.js.map +1 -0
- package/dist/features/admin/admin.dto.d.ts +61 -0
- package/dist/features/admin/admin.dto.js +253 -0
- package/dist/features/admin/admin.dto.js.map +1 -0
- package/dist/features/admin/admin.service.d.ts +142 -0
- package/dist/features/admin/admin.service.js +227 -0
- package/dist/features/admin/admin.service.js.map +1 -0
- package/dist/features/api-keys/api-keys.service.d.ts +67 -0
- package/dist/features/api-keys/api-keys.service.js +144 -0
- package/dist/features/api-keys/api-keys.service.js.map +1 -0
- package/dist/features/email-change/email-change.controller.d.ts +38 -0
- package/dist/features/email-change/email-change.controller.js +85 -0
- package/dist/features/email-change/email-change.controller.js.map +1 -0
- package/dist/features/email-change/email-change.dto.d.ts +10 -0
- package/dist/features/email-change/email-change.dto.js +43 -0
- package/dist/features/email-change/email-change.dto.js.map +1 -0
- package/dist/features/email-change/email-change.service.d.ts +74 -0
- package/dist/features/email-change/email-change.service.js +179 -0
- package/dist/features/email-change/email-change.service.js.map +1 -0
- package/dist/features/email-links/email-verification.service.d.ts +46 -0
- package/dist/features/email-links/email-verification.service.js +94 -0
- package/dist/features/email-links/email-verification.service.js.map +1 -0
- package/dist/features/email-links/link-tokens.service.d.ts +44 -0
- package/dist/features/email-links/link-tokens.service.js +122 -0
- package/dist/features/email-links/link-tokens.service.js.map +1 -0
- package/dist/features/events/auth-events.service.d.ts +52 -0
- package/dist/features/events/auth-events.service.js +117 -0
- package/dist/features/events/auth-events.service.js.map +1 -0
- package/dist/features/maintenance/data-retention.service.d.ts +60 -0
- package/dist/features/maintenance/data-retention.service.js +182 -0
- package/dist/features/maintenance/data-retention.service.js.map +1 -0
- package/dist/features/notifications/notifications.service.d.ts +40 -0
- package/dist/features/notifications/notifications.service.js +94 -0
- package/dist/features/notifications/notifications.service.js.map +1 -0
- package/dist/features/one-time-codes/one-time-codes.service.d.ts +40 -0
- package/dist/features/one-time-codes/one-time-codes.service.js +102 -0
- package/dist/features/one-time-codes/one-time-codes.service.js.map +1 -0
- package/dist/features/organizations/organizations.controller.d.ts +220 -0
- package/dist/features/organizations/organizations.controller.js +337 -0
- package/dist/features/organizations/organizations.controller.js.map +1 -0
- package/dist/features/organizations/organizations.dto.d.ts +31 -0
- package/dist/features/organizations/organizations.dto.js +100 -0
- package/dist/features/organizations/organizations.dto.js.map +1 -0
- package/dist/features/organizations/organizations.service.d.ts +274 -0
- package/dist/features/organizations/organizations.service.js +481 -0
- package/dist/features/organizations/organizations.service.js.map +1 -0
- package/dist/features/passkeys/passkeys.controller.d.ts +92 -0
- package/dist/features/passkeys/passkeys.controller.js +183 -0
- package/dist/features/passkeys/passkeys.controller.js.map +1 -0
- package/dist/features/passkeys/passkeys.dto.d.ts +13 -0
- package/dist/features/passkeys/passkeys.dto.js +50 -0
- package/dist/features/passkeys/passkeys.dto.js.map +1 -0
- package/dist/features/passkeys/passkeys.service.d.ts +159 -0
- package/dist/features/passkeys/passkeys.service.js +350 -0
- package/dist/features/passkeys/passkeys.service.js.map +1 -0
- package/dist/features/passwordless/passwordless-auth.service.d.ts +152 -0
- package/dist/features/passwordless/passwordless-auth.service.js +304 -0
- package/dist/features/passwordless/passwordless-auth.service.js.map +1 -0
- package/dist/features/passwordless/passwordless.controller.d.ts +75 -0
- package/dist/features/passwordless/passwordless.controller.js +163 -0
- package/dist/features/passwordless/passwordless.controller.js.map +1 -0
- package/dist/features/passwordless/passwordless.dto.d.ts +29 -0
- package/dist/features/passwordless/passwordless.dto.js +101 -0
- package/dist/features/passwordless/passwordless.dto.js.map +1 -0
- package/dist/features/passwords/password-auth.service.d.ts +154 -0
- package/dist/features/passwords/password-auth.service.js +317 -0
- package/dist/features/passwords/password-auth.service.js.map +1 -0
- package/dist/features/passwords/password-policy.service.d.ts +63 -0
- package/dist/features/passwords/password-policy.service.js +175 -0
- package/dist/features/passwords/password-policy.service.js.map +1 -0
- package/dist/features/passwords/password.controller.d.ts +95 -0
- package/dist/features/passwords/password.controller.js +193 -0
- package/dist/features/passwords/password.controller.js.map +1 -0
- package/dist/features/passwords/password.dto.d.ts +36 -0
- package/dist/features/passwords/password.dto.js +140 -0
- package/dist/features/passwords/password.dto.js.map +1 -0
- package/dist/features/sessions/session.service.d.ts +132 -0
- package/dist/features/sessions/session.service.js +308 -0
- package/dist/features/sessions/session.service.js.map +1 -0
- package/dist/features/sessions/session.types.d.ts +34 -0
- package/dist/features/sessions/session.types.js +3 -0
- package/dist/features/sessions/session.types.js.map +1 -0
- package/dist/features/settings/settings.defaults.d.ts +2 -0
- package/dist/features/settings/settings.defaults.js +7 -0
- package/dist/features/settings/settings.defaults.js.map +1 -0
- package/dist/features/settings/settings.service.d.ts +44 -0
- package/dist/features/settings/settings.service.js +112 -0
- package/dist/features/settings/settings.service.js.map +1 -0
- package/dist/features/settings/settings.types.d.ts +133 -0
- package/dist/features/settings/settings.types.js +3 -0
- package/dist/features/settings/settings.types.js.map +1 -0
- package/dist/features/settings/settings.validation.d.ts +33 -0
- package/dist/features/settings/settings.validation.js +614 -0
- package/dist/features/settings/settings.validation.js.map +1 -0
- package/dist/features/sign-in/sign-in-challenges.service.d.ts +54 -0
- package/dist/features/sign-in/sign-in-challenges.service.js +104 -0
- package/dist/features/sign-in/sign-in-challenges.service.js.map +1 -0
- package/dist/features/sign-in/sign-in.service.d.ts +127 -0
- package/dist/features/sign-in/sign-in.service.js +248 -0
- package/dist/features/sign-in/sign-in.service.js.map +1 -0
- package/dist/features/sign-in/sign-in.types.d.ts +22 -0
- package/dist/features/sign-in/sign-in.types.js +3 -0
- package/dist/features/sign-in/sign-in.types.js.map +1 -0
- package/dist/features/signing-keys/jwks.controller.d.ts +17 -0
- package/dist/features/signing-keys/jwks.controller.js +51 -0
- package/dist/features/signing-keys/jwks.controller.js.map +1 -0
- package/dist/features/signing-keys/signing-keys.service.d.ts +67 -0
- package/dist/features/signing-keys/signing-keys.service.js +142 -0
- package/dist/features/signing-keys/signing-keys.service.js.map +1 -0
- package/dist/features/social/social-auth.service.d.ts +100 -0
- package/dist/features/social/social-auth.service.js +232 -0
- package/dist/features/social/social-auth.service.js.map +1 -0
- package/dist/features/social/social-providers.service.d.ts +97 -0
- package/dist/features/social/social-providers.service.js +214 -0
- package/dist/features/social/social-providers.service.js.map +1 -0
- package/dist/features/social/social.controller.d.ts +54 -0
- package/dist/features/social/social.controller.js +124 -0
- package/dist/features/social/social.controller.js.map +1 -0
- package/dist/features/social/social.dto.d.ts +11 -0
- package/dist/features/social/social.dto.js +38 -0
- package/dist/features/social/social.dto.js.map +1 -0
- package/dist/features/two-factor/two-factor.controller.d.ts +84 -0
- package/dist/features/two-factor/two-factor.controller.js +174 -0
- package/dist/features/two-factor/two-factor.controller.js.map +1 -0
- package/dist/features/two-factor/two-factor.dto.d.ts +10 -0
- package/dist/features/two-factor/two-factor.dto.js +37 -0
- package/dist/features/two-factor/two-factor.dto.js.map +1 -0
- package/dist/features/two-factor/two-factor.service.d.ts +171 -0
- package/dist/features/two-factor/two-factor.service.js +348 -0
- package/dist/features/two-factor/two-factor.service.js.map +1 -0
- package/dist/features/users/sign-in-methods.service.d.ts +40 -0
- package/dist/features/users/sign-in-methods.service.js +81 -0
- package/dist/features/users/sign-in-methods.service.js.map +1 -0
- package/dist/features/users/sign-up-rules.d.ts +12 -0
- package/dist/features/users/sign-up-rules.js +29 -0
- package/dist/features/users/sign-up-rules.js.map +1 -0
- package/dist/features/users/users.service.d.ts +246 -0
- package/dist/features/users/users.service.js +509 -0
- package/dist/features/users/users.service.js.map +1 -0
- package/dist/features/users/users.types.d.ts +24 -0
- package/dist/features/users/users.types.js +3 -0
- package/dist/features/users/users.types.js.map +1 -0
- package/dist/features/webhooks/webhook-delivery.worker.d.ts +55 -0
- package/dist/features/webhooks/webhook-delivery.worker.js +175 -0
- package/dist/features/webhooks/webhook-delivery.worker.js.map +1 -0
- package/dist/features/webhooks/webhook-signature.d.ts +28 -0
- package/dist/features/webhooks/webhook-signature.js +85 -0
- package/dist/features/webhooks/webhook-signature.js.map +1 -0
- package/dist/features/webhooks/webhooks.service.d.ts +144 -0
- package/dist/features/webhooks/webhooks.service.js +238 -0
- package/dist/features/webhooks/webhooks.service.js.map +1 -0
- package/dist/guards/auth.decorators.d.ts +65 -0
- package/dist/guards/auth.decorators.js +68 -0
- package/dist/guards/auth.decorators.js.map +1 -0
- package/dist/guards/auth.guard.d.ts +47 -0
- package/dist/guards/auth.guard.js +132 -0
- package/dist/guards/auth.guard.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +95 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/console-email-sender.d.ts +15 -0
- package/dist/integrations/console-email-sender.js +26 -0
- package/dist/integrations/console-email-sender.js.map +1 -0
- package/dist/integrations/msg91-sms-sender.d.ts +28 -0
- package/dist/integrations/msg91-sms-sender.js +46 -0
- package/dist/integrations/msg91-sms-sender.js.map +1 -0
- package/docs/README.md +39 -0
- package/docs/admin-api-keys-webhooks.md +147 -0
- package/docs/api-reference.md +175 -0
- package/docs/architecture.md +119 -0
- package/docs/client-integration.md +192 -0
- package/docs/code-walkthrough.md +273 -0
- package/docs/configuration.md +229 -0
- package/docs/endpoints/README.md +151 -0
- package/docs/endpoints/account.md +363 -0
- package/docs/endpoints/admin.md +422 -0
- package/docs/endpoints/email-password.md +261 -0
- package/docs/endpoints/organizations.md +192 -0
- package/docs/endpoints/passkeys.md +195 -0
- package/docs/endpoints/passwordless.md +214 -0
- package/docs/endpoints/social.md +116 -0
- package/docs/endpoints/two-factor.md +146 -0
- package/docs/error-codes.md +100 -0
- package/docs/events.md +83 -0
- package/docs/getting-started.md +139 -0
- package/docs/manual-testing.md +215 -0
- package/docs/organizations.md +86 -0
- package/docs/production-checklist.md +60 -0
- package/docs/protecting-routes.md +147 -0
- package/docs/security.md +61 -0
- package/docs/sign-in-flows.md +294 -0
- package/package.json +92 -4
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.VerifyMagicLinkInput = exports.VerifyPhoneCodeInput = exports.PhoneNumberInput = exports.VerifyEmailCodeInput = exports.SignUpDetailsInput = void 0;
|
|
13
|
+
const class_validator_1 = require("class-validator");
|
|
14
|
+
const constants_1 = require("../../constants.js");
|
|
15
|
+
/**
|
|
16
|
+
* Optional details for someone signing up with a code, link or social account. Only used when
|
|
17
|
+
* the sign-in creates a NEW account; ignored for existing users. If your settings require names
|
|
18
|
+
* or consent and they are missing, the response is VALIDATION_ERROR with `missingSignUpDetails`.
|
|
19
|
+
*/
|
|
20
|
+
class SignUpDetailsInput {
|
|
21
|
+
firstName;
|
|
22
|
+
lastName;
|
|
23
|
+
acceptTerms;
|
|
24
|
+
acceptPrivacyPolicy;
|
|
25
|
+
}
|
|
26
|
+
exports.SignUpDetailsInput = SignUpDetailsInput;
|
|
27
|
+
__decorate([
|
|
28
|
+
(0, class_validator_1.IsOptional)(),
|
|
29
|
+
(0, class_validator_1.IsString)(),
|
|
30
|
+
(0, class_validator_1.MaxLength)(constants_1.DISPLAY_NAME_MAX_LENGTH),
|
|
31
|
+
__metadata("design:type", String)
|
|
32
|
+
], SignUpDetailsInput.prototype, "firstName", void 0);
|
|
33
|
+
__decorate([
|
|
34
|
+
(0, class_validator_1.IsOptional)(),
|
|
35
|
+
(0, class_validator_1.IsString)(),
|
|
36
|
+
(0, class_validator_1.MaxLength)(constants_1.DISPLAY_NAME_MAX_LENGTH),
|
|
37
|
+
__metadata("design:type", String)
|
|
38
|
+
], SignUpDetailsInput.prototype, "lastName", void 0);
|
|
39
|
+
__decorate([
|
|
40
|
+
(0, class_validator_1.IsOptional)(),
|
|
41
|
+
(0, class_validator_1.IsBoolean)(),
|
|
42
|
+
__metadata("design:type", Boolean)
|
|
43
|
+
], SignUpDetailsInput.prototype, "acceptTerms", void 0);
|
|
44
|
+
__decorate([
|
|
45
|
+
(0, class_validator_1.IsOptional)(),
|
|
46
|
+
(0, class_validator_1.IsBoolean)(),
|
|
47
|
+
__metadata("design:type", Boolean)
|
|
48
|
+
], SignUpDetailsInput.prototype, "acceptPrivacyPolicy", void 0);
|
|
49
|
+
/** POST /auth/email/verify-otp */
|
|
50
|
+
class VerifyEmailCodeInput extends SignUpDetailsInput {
|
|
51
|
+
email;
|
|
52
|
+
code;
|
|
53
|
+
}
|
|
54
|
+
exports.VerifyEmailCodeInput = VerifyEmailCodeInput;
|
|
55
|
+
__decorate([
|
|
56
|
+
(0, class_validator_1.IsString)(),
|
|
57
|
+
(0, class_validator_1.MaxLength)(constants_1.EMAIL_MAX_LENGTH),
|
|
58
|
+
__metadata("design:type", String)
|
|
59
|
+
], VerifyEmailCodeInput.prototype, "email", void 0);
|
|
60
|
+
__decorate([
|
|
61
|
+
(0, class_validator_1.IsString)(),
|
|
62
|
+
(0, class_validator_1.MaxLength)(constants_1.CODE_INPUT_MAX_LENGTH),
|
|
63
|
+
__metadata("design:type", String)
|
|
64
|
+
], VerifyEmailCodeInput.prototype, "code", void 0);
|
|
65
|
+
/** POST /auth/phone/send-otp */
|
|
66
|
+
class PhoneNumberInput {
|
|
67
|
+
phoneNumber;
|
|
68
|
+
}
|
|
69
|
+
exports.PhoneNumberInput = PhoneNumberInput;
|
|
70
|
+
__decorate([
|
|
71
|
+
(0, class_validator_1.IsString)(),
|
|
72
|
+
(0, class_validator_1.MaxLength)(constants_1.PHONE_NUMBER_INPUT_MAX_LENGTH),
|
|
73
|
+
__metadata("design:type", String)
|
|
74
|
+
], PhoneNumberInput.prototype, "phoneNumber", void 0);
|
|
75
|
+
/** POST /auth/phone/verify-otp */
|
|
76
|
+
class VerifyPhoneCodeInput extends SignUpDetailsInput {
|
|
77
|
+
phoneNumber;
|
|
78
|
+
code;
|
|
79
|
+
}
|
|
80
|
+
exports.VerifyPhoneCodeInput = VerifyPhoneCodeInput;
|
|
81
|
+
__decorate([
|
|
82
|
+
(0, class_validator_1.IsString)(),
|
|
83
|
+
(0, class_validator_1.MaxLength)(constants_1.PHONE_NUMBER_INPUT_MAX_LENGTH),
|
|
84
|
+
__metadata("design:type", String)
|
|
85
|
+
], VerifyPhoneCodeInput.prototype, "phoneNumber", void 0);
|
|
86
|
+
__decorate([
|
|
87
|
+
(0, class_validator_1.IsString)(),
|
|
88
|
+
(0, class_validator_1.MaxLength)(constants_1.CODE_INPUT_MAX_LENGTH),
|
|
89
|
+
__metadata("design:type", String)
|
|
90
|
+
], VerifyPhoneCodeInput.prototype, "code", void 0);
|
|
91
|
+
/** POST /auth/magic-link/verify */
|
|
92
|
+
class VerifyMagicLinkInput extends SignUpDetailsInput {
|
|
93
|
+
token;
|
|
94
|
+
}
|
|
95
|
+
exports.VerifyMagicLinkInput = VerifyMagicLinkInput;
|
|
96
|
+
__decorate([
|
|
97
|
+
(0, class_validator_1.IsString)(),
|
|
98
|
+
(0, class_validator_1.MaxLength)(constants_1.RANDOM_TOKEN_INPUT_MAX_LENGTH),
|
|
99
|
+
__metadata("design:type", String)
|
|
100
|
+
], VerifyMagicLinkInput.prototype, "token", void 0);
|
|
101
|
+
//# sourceMappingURL=passwordless.dto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passwordless.dto.js","sourceRoot":"","sources":["../../../src/features/passwordless/passwordless.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qDAA6E;AAC7E,2CAMqB;AAErB;;;;GAIG;AACH,MAAa,kBAAkB;IAE7B,SAAS,CAAU;IAGnB,QAAQ,CAAU;IAGlB,WAAW,CAAW;IAGtB,mBAAmB,CAAW;CAC/B;AAZD,gDAYC;AAVC;IADC,IAAA,4BAAU,GAAE;IAAE,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,mCAAuB,CAAC;;qDAC1C;AAGnB;IADC,IAAA,4BAAU,GAAE;IAAE,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,mCAAuB,CAAC;;oDAC3C;AAGlB;IADC,IAAA,4BAAU,GAAE;IAAE,IAAA,2BAAS,GAAE;;uDACJ;AAGtB;IADC,IAAA,4BAAU,GAAE;IAAE,IAAA,2BAAS,GAAE;;+DACI;AAGhC,kCAAkC;AAClC,MAAa,oBAAqB,SAAQ,kBAAkB;IAE1D,KAAK,CAAS;IAGd,IAAI,CAAS;CACd;AAND,oDAMC;AAJC;IADC,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,4BAAgB,CAAC;;mDAC1B;AAGd;IADC,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,iCAAqB,CAAC;;kDAChC;AAGf,gCAAgC;AAChC,MAAa,gBAAgB;IAE3B,WAAW,CAAS;CACrB;AAHD,4CAGC;AADC;IADC,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,yCAA6B,CAAC;;qDACjC;AAGtB,kCAAkC;AAClC,MAAa,oBAAqB,SAAQ,kBAAkB;IAE1D,WAAW,CAAS;IAGpB,IAAI,CAAS;CACd;AAND,oDAMC;AAJC;IADC,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,yCAA6B,CAAC;;yDACjC;AAGpB;IADC,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,iCAAqB,CAAC;;kDAChC;AAGf,mCAAmC;AACnC,MAAa,oBAAqB,SAAQ,kBAAkB;IAE1D,KAAK,CAAS;CACf;AAHD,oDAGC;AADC;IADC,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,yCAA6B,CAAC;;mDACvC"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { AuthOptions } from '../../auth-options.js';
|
|
2
|
+
import { RateLimiterService } from '../../common/rate-limiter.service.js';
|
|
3
|
+
import { RequestContext } from '../../common/request-context.js';
|
|
4
|
+
import { SIGN_IN_STATUS } from '../../constants.js';
|
|
5
|
+
import { LinkTokensService } from '../email-links/link-tokens.service.js';
|
|
6
|
+
import { EmailVerificationService } from '../email-links/email-verification.service.js';
|
|
7
|
+
import { AuthEventsService } from '../events/auth-events.service.js';
|
|
8
|
+
import { NotificationsService } from '../notifications/notifications.service.js';
|
|
9
|
+
import { SessionService } from '../sessions/session.service.js';
|
|
10
|
+
import { SettingsService } from '../settings/settings.service.js';
|
|
11
|
+
import { SignInService } from '../sign-in/sign-in.service.js';
|
|
12
|
+
import { SignInResult } from '../sign-in/sign-in.types.js';
|
|
13
|
+
import { UsersService } from '../users/users.service.js';
|
|
14
|
+
import { PendingVerification } from '../users/users.types.js';
|
|
15
|
+
import { RegisterInput } from './password.dto';
|
|
16
|
+
import { PasswordPolicyService } from './password-policy.service';
|
|
17
|
+
/** What POST /auth/register returns when the user still has to verify something. */
|
|
18
|
+
export interface RegisteredResult {
|
|
19
|
+
success: true;
|
|
20
|
+
status: typeof SIGN_IN_STATUS.verificationRequired;
|
|
21
|
+
message: string;
|
|
22
|
+
pendingVerifications: PendingVerification[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Email + password: register, sign in, forgot / reset password, change password.
|
|
26
|
+
*/
|
|
27
|
+
export declare class PasswordAuthService {
|
|
28
|
+
private readonly settingsService;
|
|
29
|
+
private readonly passwordPolicy;
|
|
30
|
+
private readonly users;
|
|
31
|
+
private readonly signIn;
|
|
32
|
+
private readonly sessions;
|
|
33
|
+
private readonly linkTokens;
|
|
34
|
+
private readonly emailVerification;
|
|
35
|
+
private readonly notifications;
|
|
36
|
+
private readonly rateLimiter;
|
|
37
|
+
private readonly events;
|
|
38
|
+
private readonly database;
|
|
39
|
+
constructor(options: AuthOptions, settingsService: SettingsService, passwordPolicy: PasswordPolicyService, users: UsersService, signIn: SignInService, sessions: SessionService, linkTokens: LinkTokensService, emailVerification: EmailVerificationService, notifications: NotificationsService, rateLimiter: RateLimiterService, events: AuthEventsService);
|
|
40
|
+
/**
|
|
41
|
+
* Creates an account.
|
|
42
|
+
*
|
|
43
|
+
* - If the settings require no verification, the user is signed in straight away.
|
|
44
|
+
* - Otherwise a verification email is sent and the response says what to verify next.
|
|
45
|
+
* - If the email is already registered, the response looks exactly like a new sign-up
|
|
46
|
+
* (no account is created), so nobody can use this form to find out who has an account.
|
|
47
|
+
*
|
|
48
|
+
* @param input - The sign-up form: email, password, and optional phone, names and consents.
|
|
49
|
+
* @param request - Who is asking (for rate limits and the audit log).
|
|
50
|
+
* @returns Tokens when the account is active at once, otherwise `status: "verification_required"`.
|
|
51
|
+
* @throws AuthError SIGN_UP_CLOSED, EMAIL_DOMAIN_NOT_ALLOWED, TERMS_NOT_ACCEPTED... when a sign-up rule fails.
|
|
52
|
+
* @throws AuthError INVALID_PASSWORD when the password breaks a rule or appeared in a data breach.
|
|
53
|
+
* @throws AuthError TOO_MANY_REQUESTS after too many sign-ups from one IP.
|
|
54
|
+
*/
|
|
55
|
+
register(input: RegisterInput, request: RequestContext): Promise<SignInResult | RegisteredResult>;
|
|
56
|
+
/**
|
|
57
|
+
* Signs in with email + password. Wrong email and wrong password give the same error.
|
|
58
|
+
*
|
|
59
|
+
* @param typedEmail - The email from the request.
|
|
60
|
+
* @param typedPassword - The password from the request.
|
|
61
|
+
* @param request - Who is asking (for rate limits and the audit log).
|
|
62
|
+
* @returns Tokens, or a 2FA challenge when the user has 2FA on.
|
|
63
|
+
* @throws AuthError INVALID_CREDENTIALS when the email or password is wrong.
|
|
64
|
+
* @throws AuthError TOO_MANY_REQUESTS after too many attempts for this IP or account.
|
|
65
|
+
*/
|
|
66
|
+
signInWithPassword(typedEmail: unknown, typedPassword: unknown, request: RequestContext): Promise<SignInResult>;
|
|
67
|
+
/**
|
|
68
|
+
* Emails a password reset link. Always answers the same, whether or not the email has an account.
|
|
69
|
+
*
|
|
70
|
+
* @param typedEmail - The email from the request.
|
|
71
|
+
* @param request - Who is asking (for rate limits and the audit log).
|
|
72
|
+
* @returns A generic success message.
|
|
73
|
+
* @throws AuthError TOO_MANY_REQUESTS after too many emails for this IP or address.
|
|
74
|
+
*/
|
|
75
|
+
requestPasswordReset(typedEmail: unknown, request: RequestContext): Promise<{
|
|
76
|
+
success: true;
|
|
77
|
+
message: "If an account exists for this email, a password reset link is on its way.";
|
|
78
|
+
}>;
|
|
79
|
+
/**
|
|
80
|
+
* Sets a new password from a reset link. Signs the user out everywhere (whoever knew the old
|
|
81
|
+
* password is kicked out) and marks the email verified (the user just proved they read it).
|
|
82
|
+
*
|
|
83
|
+
* @param resetToken - The token from the link in the email.
|
|
84
|
+
* @param newPassword - The new password.
|
|
85
|
+
* @param request - Who is asking (for the audit log).
|
|
86
|
+
* @returns A success message. The user signs in again with the new password.
|
|
87
|
+
* @throws AuthError INVALID_TOKEN when the link is unknown, used, expired, or the
|
|
88
|
+
* account's email has changed since it was sent.
|
|
89
|
+
* @throws AuthError INVALID_PASSWORD when the new password breaks a rule or appeared in a data breach.
|
|
90
|
+
*/
|
|
91
|
+
resetPassword(resetToken: unknown, newPassword: unknown, request: RequestContext): Promise<{
|
|
92
|
+
success: true;
|
|
93
|
+
message: "Your password has been reset. Please sign in with your new password.";
|
|
94
|
+
}>;
|
|
95
|
+
/**
|
|
96
|
+
* Changes the password of a signed-in user (they must type the current one).
|
|
97
|
+
* Users who signed up with Google etc. have no password yet and may set one without it.
|
|
98
|
+
* Other devices are signed out; this one stays signed in.
|
|
99
|
+
*
|
|
100
|
+
* @param userId - The signed-in user.
|
|
101
|
+
* @param sessionId - This device's session, which stays signed in.
|
|
102
|
+
* @param currentPassword - The current password (ignored when the user has none yet).
|
|
103
|
+
* @param newPassword - The new password.
|
|
104
|
+
* @param request - Who is asking (for the audit log).
|
|
105
|
+
* @returns A success message.
|
|
106
|
+
* @throws AuthError INVALID_CREDENTIALS when the current password is wrong.
|
|
107
|
+
* @throws AuthError INVALID_PASSWORD when the new password breaks a rule or equals the current one.
|
|
108
|
+
*/
|
|
109
|
+
changePassword(userId: string, sessionId: string, currentPassword: unknown, newPassword: unknown, request: RequestContext): Promise<{
|
|
110
|
+
success: true;
|
|
111
|
+
message: "Your password has been changed. Other devices have been signed out.";
|
|
112
|
+
}>;
|
|
113
|
+
/**
|
|
114
|
+
* @returns The current settings.
|
|
115
|
+
* @throws AuthError SIGN_IN_METHOD_DISABLED when email + password is turned off.
|
|
116
|
+
*/
|
|
117
|
+
private getPasswordSettings;
|
|
118
|
+
/**
|
|
119
|
+
* Checks the sign-up form against the registration rules in settings.
|
|
120
|
+
*
|
|
121
|
+
* @param input - The sign-up form.
|
|
122
|
+
* @param email - The normalized email.
|
|
123
|
+
* @param phoneNumber - The normalized phone number, or null.
|
|
124
|
+
* @param settings - The current settings.
|
|
125
|
+
* @throws AuthError for the first rule that fails (SIGN_UP_CLOSED, EMAIL_DOMAIN_NOT_ALLOWED,
|
|
126
|
+
* INVALID_PHONE, VALIDATION_ERROR, TERMS_NOT_ACCEPTED, PRIVACY_POLICY_NOT_ACCEPTED).
|
|
127
|
+
*/
|
|
128
|
+
private assertRegistrationRules;
|
|
129
|
+
/**
|
|
130
|
+
* The verifications a brand-new email + password account will need (same answer for everyone,
|
|
131
|
+
* so the response can't reveal whether the email was already registered).
|
|
132
|
+
*
|
|
133
|
+
* @param phoneNumber - The phone number from the form, or null.
|
|
134
|
+
* @param settings - The current settings.
|
|
135
|
+
* @returns e.g. ["email"] or ["email", "phone"].
|
|
136
|
+
*/
|
|
137
|
+
private newAccountVerifications;
|
|
138
|
+
/**
|
|
139
|
+
* Hashes the password and stores it, replacing any old one.
|
|
140
|
+
*
|
|
141
|
+
* @param userId - The user.
|
|
142
|
+
* @param password - The plain password (already checked against the rules).
|
|
143
|
+
*/
|
|
144
|
+
private savePassword;
|
|
145
|
+
/**
|
|
146
|
+
* Records the change in the audit log and, if enabled, emails the user that it happened.
|
|
147
|
+
*
|
|
148
|
+
* @param user - The user whose password changed.
|
|
149
|
+
* @param settings - The current settings.
|
|
150
|
+
* @param request - Who made the change.
|
|
151
|
+
* @param how - "reset", "changed" or "first_set".
|
|
152
|
+
*/
|
|
153
|
+
private afterPasswordChanged;
|
|
154
|
+
}
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.PasswordAuthService = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const auth_error_1 = require("../../common/auth-error.js");
|
|
18
|
+
const identifiers_1 = require("../../common/identifiers.js");
|
|
19
|
+
const rate_limiter_service_1 = require("../../common/rate-limiter.service.js");
|
|
20
|
+
const constants_1 = require("../../constants.js");
|
|
21
|
+
const entities_1 = require("../../database/entities/index.js");
|
|
22
|
+
const link_tokens_service_1 = require("../email-links/link-tokens.service.js");
|
|
23
|
+
const email_verification_service_1 = require("../email-links/email-verification.service.js");
|
|
24
|
+
const auth_events_service_1 = require("../events/auth-events.service.js");
|
|
25
|
+
const notifications_service_1 = require("../notifications/notifications.service.js");
|
|
26
|
+
const session_service_1 = require("../sessions/session.service.js");
|
|
27
|
+
const settings_service_1 = require("../settings/settings.service.js");
|
|
28
|
+
const sign_in_service_1 = require("../sign-in/sign-in.service.js");
|
|
29
|
+
const users_service_1 = require("../users/users.service.js");
|
|
30
|
+
const password_policy_service_1 = require("./password-policy.service");
|
|
31
|
+
/**
|
|
32
|
+
* Email + password: register, sign in, forgot / reset password, change password.
|
|
33
|
+
*/
|
|
34
|
+
let PasswordAuthService = class PasswordAuthService {
|
|
35
|
+
settingsService;
|
|
36
|
+
passwordPolicy;
|
|
37
|
+
users;
|
|
38
|
+
signIn;
|
|
39
|
+
sessions;
|
|
40
|
+
linkTokens;
|
|
41
|
+
emailVerification;
|
|
42
|
+
notifications;
|
|
43
|
+
rateLimiter;
|
|
44
|
+
events;
|
|
45
|
+
database;
|
|
46
|
+
constructor(options, settingsService, passwordPolicy, users, signIn, sessions, linkTokens, emailVerification, notifications, rateLimiter, events) {
|
|
47
|
+
this.settingsService = settingsService;
|
|
48
|
+
this.passwordPolicy = passwordPolicy;
|
|
49
|
+
this.users = users;
|
|
50
|
+
this.signIn = signIn;
|
|
51
|
+
this.sessions = sessions;
|
|
52
|
+
this.linkTokens = linkTokens;
|
|
53
|
+
this.emailVerification = emailVerification;
|
|
54
|
+
this.notifications = notifications;
|
|
55
|
+
this.rateLimiter = rateLimiter;
|
|
56
|
+
this.events = events;
|
|
57
|
+
this.database = options.dataSource;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Creates an account.
|
|
61
|
+
*
|
|
62
|
+
* - If the settings require no verification, the user is signed in straight away.
|
|
63
|
+
* - Otherwise a verification email is sent and the response says what to verify next.
|
|
64
|
+
* - If the email is already registered, the response looks exactly like a new sign-up
|
|
65
|
+
* (no account is created), so nobody can use this form to find out who has an account.
|
|
66
|
+
*
|
|
67
|
+
* @param input - The sign-up form: email, password, and optional phone, names and consents.
|
|
68
|
+
* @param request - Who is asking (for rate limits and the audit log).
|
|
69
|
+
* @returns Tokens when the account is active at once, otherwise `status: "verification_required"`.
|
|
70
|
+
* @throws AuthError SIGN_UP_CLOSED, EMAIL_DOMAIN_NOT_ALLOWED, TERMS_NOT_ACCEPTED... when a sign-up rule fails.
|
|
71
|
+
* @throws AuthError INVALID_PASSWORD when the password breaks a rule or appeared in a data breach.
|
|
72
|
+
* @throws AuthError TOO_MANY_REQUESTS after too many sign-ups from one IP.
|
|
73
|
+
*/
|
|
74
|
+
async register(input, request) {
|
|
75
|
+
const settings = await this.getPasswordSettings();
|
|
76
|
+
await this.rateLimiter.consume(constants_1.RATE_LIMIT_KEY.signUpPerIp(request.ipAddress), constants_1.RATE_LIMITS.signUpPerIp);
|
|
77
|
+
const email = (0, identifiers_1.normalizeEmail)(input.email);
|
|
78
|
+
const phoneNumber = input.phoneNumber ? (0, identifiers_1.normalizePhoneNumber)(input.phoneNumber) : null;
|
|
79
|
+
this.assertRegistrationRules(input, email, phoneNumber, settings);
|
|
80
|
+
const password = await this.passwordPolicy.assertPasswordIsAcceptable(input.password, settings);
|
|
81
|
+
const genericResult = {
|
|
82
|
+
success: true,
|
|
83
|
+
status: constants_1.SIGN_IN_STATUS.verificationRequired,
|
|
84
|
+
message: constants_1.SUCCESS_MESSAGES.registered,
|
|
85
|
+
pendingVerifications: this.newAccountVerifications(phoneNumber, settings),
|
|
86
|
+
};
|
|
87
|
+
const existingUser = await this.users.findUserByEmail(email);
|
|
88
|
+
if (existingUser) {
|
|
89
|
+
// Help a real owner who never finished verifying; tell a stranger nothing.
|
|
90
|
+
if (!existingUser.isEmailVerified)
|
|
91
|
+
await this.emailVerification.sendVerificationEmail(email, request);
|
|
92
|
+
return genericResult;
|
|
93
|
+
}
|
|
94
|
+
const passwordHash = await this.passwordPolicy.hashPassword(password);
|
|
95
|
+
const newUser = await this.database.transaction(async (transaction) => {
|
|
96
|
+
const createdUser = await this.users.createUser({
|
|
97
|
+
email,
|
|
98
|
+
phoneNumber,
|
|
99
|
+
firstName: input.firstName?.trim() || null,
|
|
100
|
+
lastName: input.lastName?.trim() || null,
|
|
101
|
+
acceptedTerms: input.acceptTerms === true,
|
|
102
|
+
acceptedPrivacyPolicy: input.acceptPrivacyPolicy === true,
|
|
103
|
+
}, settings, request, transaction);
|
|
104
|
+
await transaction.insert(entities_1.PasswordEntity, { userId: createdUser.id, passwordHash });
|
|
105
|
+
return createdUser;
|
|
106
|
+
});
|
|
107
|
+
if (newUser.status === constants_1.ACCOUNT_STATUS.active)
|
|
108
|
+
return this.signIn.completeSignIn(newUser, constants_1.SIGN_IN_METHOD.password, request, settings);
|
|
109
|
+
if (this.users.getPendingVerifications(newUser, settings).includes(constants_1.PENDING_VERIFICATION.email)) {
|
|
110
|
+
await this.emailVerification.sendVerificationEmail(email, request);
|
|
111
|
+
}
|
|
112
|
+
return genericResult;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Signs in with email + password. Wrong email and wrong password give the same error.
|
|
116
|
+
*
|
|
117
|
+
* @param typedEmail - The email from the request.
|
|
118
|
+
* @param typedPassword - The password from the request.
|
|
119
|
+
* @param request - Who is asking (for rate limits and the audit log).
|
|
120
|
+
* @returns Tokens, or a 2FA challenge when the user has 2FA on.
|
|
121
|
+
* @throws AuthError INVALID_CREDENTIALS when the email or password is wrong.
|
|
122
|
+
* @throws AuthError TOO_MANY_REQUESTS after too many attempts for this IP or account.
|
|
123
|
+
*/
|
|
124
|
+
async signInWithPassword(typedEmail, typedPassword, request) {
|
|
125
|
+
const settings = await this.getPasswordSettings();
|
|
126
|
+
const email = (0, identifiers_1.normalizeEmail)(typedEmail);
|
|
127
|
+
await this.rateLimiter.consume(constants_1.RATE_LIMIT_KEY.signInPerIp(request.ipAddress), constants_1.RATE_LIMITS.signInPerIp);
|
|
128
|
+
await this.rateLimiter.consume(constants_1.RATE_LIMIT_KEY.signInPerAccount(email), constants_1.RATE_LIMITS.signInPerAccount);
|
|
129
|
+
const user = await this.users.findUserByEmail(email);
|
|
130
|
+
const storedPassword = user
|
|
131
|
+
? await this.database.getRepository(entities_1.PasswordEntity).findOne({ where: { userId: user.id } })
|
|
132
|
+
: null;
|
|
133
|
+
// Always run the slow hash check, even with no account, so response time reveals nothing.
|
|
134
|
+
const isPasswordRight = await this.passwordPolicy.verifyPassword(storedPassword?.passwordHash ?? null, typedPassword);
|
|
135
|
+
if (!user || !storedPassword || !isPasswordRight) {
|
|
136
|
+
await this.signIn.recordFailedSignIn(user?.id ?? null, constants_1.SIGN_IN_METHOD.password, constants_1.SIGN_IN_FAILURE_REASON.wrongEmailOrPassword, request);
|
|
137
|
+
throw new auth_error_1.AuthError(constants_1.AUTH_ERRORS.invalidCredentials);
|
|
138
|
+
}
|
|
139
|
+
await this.rateLimiter.reset(constants_1.RATE_LIMIT_KEY.signInPerAccount(email));
|
|
140
|
+
if (this.passwordPolicy.needsRehash(storedPassword.passwordHash)) {
|
|
141
|
+
await this.savePassword(user.id, typedPassword);
|
|
142
|
+
}
|
|
143
|
+
return this.signIn.completeSignIn(user, constants_1.SIGN_IN_METHOD.password, request, settings);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Emails a password reset link. Always answers the same, whether or not the email has an account.
|
|
147
|
+
*
|
|
148
|
+
* @param typedEmail - The email from the request.
|
|
149
|
+
* @param request - Who is asking (for rate limits and the audit log).
|
|
150
|
+
* @returns A generic success message.
|
|
151
|
+
* @throws AuthError TOO_MANY_REQUESTS after too many emails for this IP or address.
|
|
152
|
+
*/
|
|
153
|
+
async requestPasswordReset(typedEmail, request) {
|
|
154
|
+
await this.getPasswordSettings();
|
|
155
|
+
const email = (0, identifiers_1.normalizeEmail)(typedEmail);
|
|
156
|
+
await this.rateLimiter.consume(constants_1.RATE_LIMIT_KEY.sendEmailLinkPerIp(request.ipAddress), constants_1.RATE_LIMITS.sendEmailLinkPerIp);
|
|
157
|
+
await this.rateLimiter.consume(constants_1.RATE_LIMIT_KEY.sendEmailLinkPerEmail(email), constants_1.RATE_LIMITS.sendEmailLinkPerEmail);
|
|
158
|
+
const user = await this.users.findUserByEmail(email);
|
|
159
|
+
if (user && user.status !== constants_1.ACCOUNT_STATUS.deleted && user.status !== constants_1.ACCOUNT_STATUS.suspended) {
|
|
160
|
+
const token = await this.linkTokens.createLinkToken(constants_1.LINK_PURPOSE.resetPassword, email, user.id);
|
|
161
|
+
await this.notifications.sendRequiredEmail({ type: constants_1.EMAIL_TYPE.resetPassword, to: email, token });
|
|
162
|
+
await this.events.record({ name: constants_1.AUTH_EVENTS.passwordResetRequested, userId: user.id, request });
|
|
163
|
+
}
|
|
164
|
+
return { success: true, message: constants_1.SUCCESS_MESSAGES.passwordResetEmailSent };
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Sets a new password from a reset link. Signs the user out everywhere (whoever knew the old
|
|
168
|
+
* password is kicked out) and marks the email verified (the user just proved they read it).
|
|
169
|
+
*
|
|
170
|
+
* @param resetToken - The token from the link in the email.
|
|
171
|
+
* @param newPassword - The new password.
|
|
172
|
+
* @param request - Who is asking (for the audit log).
|
|
173
|
+
* @returns A success message. The user signs in again with the new password.
|
|
174
|
+
* @throws AuthError INVALID_TOKEN when the link is unknown, used, expired, or the
|
|
175
|
+
* account's email has changed since it was sent.
|
|
176
|
+
* @throws AuthError INVALID_PASSWORD when the new password breaks a rule or appeared in a data breach.
|
|
177
|
+
*/
|
|
178
|
+
async resetPassword(resetToken, newPassword, request) {
|
|
179
|
+
const settings = await this.getPasswordSettings();
|
|
180
|
+
const password = await this.passwordPolicy.assertPasswordIsAcceptable(newPassword, settings);
|
|
181
|
+
const usedToken = await this.linkTokens.useLinkToken(resetToken, constants_1.LINK_PURPOSE.resetPassword);
|
|
182
|
+
const user = usedToken.userId ? await this.users.findUserById(usedToken.userId) : null;
|
|
183
|
+
// The email may have changed, or the account been deleted, since the link was sent.
|
|
184
|
+
if (!user || user.email !== usedToken.email || user.status === constants_1.ACCOUNT_STATUS.deleted)
|
|
185
|
+
throw new auth_error_1.AuthError(constants_1.AUTH_ERRORS.invalidOrExpiredLink);
|
|
186
|
+
await this.savePassword(user.id, password);
|
|
187
|
+
await this.linkTokens.cancelLinkTokens(constants_1.LINK_PURPOSE.resetPassword, user.id);
|
|
188
|
+
await this.sessions.revokeAllSessions(user.id, constants_1.SESSION_END_REASON.passwordReset);
|
|
189
|
+
await this.users.markEmailVerified(user, settings, request);
|
|
190
|
+
await this.afterPasswordChanged(user, settings, request, constants_1.PASSWORD_CHANGE_KIND.reset);
|
|
191
|
+
return { success: true, message: constants_1.SUCCESS_MESSAGES.passwordReset };
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Changes the password of a signed-in user (they must type the current one).
|
|
195
|
+
* Users who signed up with Google etc. have no password yet and may set one without it.
|
|
196
|
+
* Other devices are signed out; this one stays signed in.
|
|
197
|
+
*
|
|
198
|
+
* @param userId - The signed-in user.
|
|
199
|
+
* @param sessionId - This device's session, which stays signed in.
|
|
200
|
+
* @param currentPassword - The current password (ignored when the user has none yet).
|
|
201
|
+
* @param newPassword - The new password.
|
|
202
|
+
* @param request - Who is asking (for the audit log).
|
|
203
|
+
* @returns A success message.
|
|
204
|
+
* @throws AuthError INVALID_CREDENTIALS when the current password is wrong.
|
|
205
|
+
* @throws AuthError INVALID_PASSWORD when the new password breaks a rule or equals the current one.
|
|
206
|
+
*/
|
|
207
|
+
async changePassword(userId, sessionId, currentPassword, newPassword, request) {
|
|
208
|
+
const settings = await this.getPasswordSettings();
|
|
209
|
+
await this.rateLimiter.consume(constants_1.RATE_LIMIT_KEY.changePasswordPerUser(userId), constants_1.RATE_LIMITS.changePasswordPerUser);
|
|
210
|
+
const user = await this.users.getUserOrThrow(userId);
|
|
211
|
+
const storedPassword = await this.database.getRepository(entities_1.PasswordEntity).findOne({ where: { userId } });
|
|
212
|
+
if (storedPassword && !(await this.passwordPolicy.verifyPassword(storedPassword.passwordHash, currentPassword))) {
|
|
213
|
+
throw new auth_error_1.AuthError(constants_1.AUTH_ERRORS.invalidCredentials);
|
|
214
|
+
}
|
|
215
|
+
const password = await this.passwordPolicy.assertPasswordIsAcceptable(newPassword, settings);
|
|
216
|
+
if (storedPassword && (await this.passwordPolicy.verifyPassword(storedPassword.passwordHash, password))) {
|
|
217
|
+
throw new auth_error_1.AuthError(constants_1.AUTH_ERRORS.invalidPassword, { requirements: [constants_1.PASSWORD_REQUIREMENT.differentFromCurrent] });
|
|
218
|
+
}
|
|
219
|
+
await this.savePassword(userId, password);
|
|
220
|
+
await this.sessions.revokeAllSessions(userId, constants_1.SESSION_END_REASON.passwordChanged, sessionId);
|
|
221
|
+
await this.afterPasswordChanged(user, settings, request, storedPassword ? constants_1.PASSWORD_CHANGE_KIND.changed : constants_1.PASSWORD_CHANGE_KIND.firstSet);
|
|
222
|
+
return { success: true, message: constants_1.SUCCESS_MESSAGES.passwordChanged };
|
|
223
|
+
}
|
|
224
|
+
// -------------------------------------------------------------------------------------------
|
|
225
|
+
/**
|
|
226
|
+
* @returns The current settings.
|
|
227
|
+
* @throws AuthError SIGN_IN_METHOD_DISABLED when email + password is turned off.
|
|
228
|
+
*/
|
|
229
|
+
async getPasswordSettings() {
|
|
230
|
+
const settings = await this.settingsService.getSettings();
|
|
231
|
+
if (!settings.password.enabled)
|
|
232
|
+
throw new auth_error_1.AuthError(constants_1.AUTH_ERRORS.signInMethodDisabled);
|
|
233
|
+
return settings;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Checks the sign-up form against the registration rules in settings.
|
|
237
|
+
*
|
|
238
|
+
* @param input - The sign-up form.
|
|
239
|
+
* @param email - The normalized email.
|
|
240
|
+
* @param phoneNumber - The normalized phone number, or null.
|
|
241
|
+
* @param settings - The current settings.
|
|
242
|
+
* @throws AuthError for the first rule that fails (SIGN_UP_CLOSED, EMAIL_DOMAIN_NOT_ALLOWED,
|
|
243
|
+
* INVALID_PHONE, VALIDATION_ERROR, TERMS_NOT_ACCEPTED, PRIVACY_POLICY_NOT_ACCEPTED).
|
|
244
|
+
*/
|
|
245
|
+
assertRegistrationRules(input, email, phoneNumber, settings) {
|
|
246
|
+
const rules = settings.registration;
|
|
247
|
+
if (!rules.enabled)
|
|
248
|
+
throw new auth_error_1.AuthError(constants_1.AUTH_ERRORS.signUpClosed);
|
|
249
|
+
if (!(0, identifiers_1.isEmailDomainAllowed)(email, rules.allowedEmailDomains))
|
|
250
|
+
throw new auth_error_1.AuthError(constants_1.AUTH_ERRORS.emailDomainNotAllowed);
|
|
251
|
+
if (rules.requirePhoneNumber && !phoneNumber)
|
|
252
|
+
throw new auth_error_1.AuthError(constants_1.AUTH_ERRORS.invalidPhone);
|
|
253
|
+
if (rules.requireFirstAndLastName && (!input.firstName?.trim() || !input.lastName?.trim())) {
|
|
254
|
+
throw new auth_error_1.AuthError(constants_1.AUTH_ERRORS.validationFailed, { problems: [constants_1.VALIDATION_PROBLEM.namesRequired] });
|
|
255
|
+
}
|
|
256
|
+
if (rules.requireTermsAcceptance && input.acceptTerms !== true)
|
|
257
|
+
throw new auth_error_1.AuthError(constants_1.AUTH_ERRORS.termsNotAccepted);
|
|
258
|
+
if (rules.requirePrivacyPolicyAcceptance && input.acceptPrivacyPolicy !== true)
|
|
259
|
+
throw new auth_error_1.AuthError(constants_1.AUTH_ERRORS.privacyPolicyNotAccepted);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* The verifications a brand-new email + password account will need (same answer for everyone,
|
|
263
|
+
* so the response can't reveal whether the email was already registered).
|
|
264
|
+
*
|
|
265
|
+
* @param phoneNumber - The phone number from the form, or null.
|
|
266
|
+
* @param settings - The current settings.
|
|
267
|
+
* @returns e.g. ["email"] or ["email", "phone"].
|
|
268
|
+
*/
|
|
269
|
+
newAccountVerifications(phoneNumber, settings) {
|
|
270
|
+
const pending = [];
|
|
271
|
+
if (settings.activation.requireVerifiedEmail)
|
|
272
|
+
pending.push(constants_1.PENDING_VERIFICATION.email);
|
|
273
|
+
if (settings.activation.requireVerifiedPhone && phoneNumber)
|
|
274
|
+
pending.push(constants_1.PENDING_VERIFICATION.phone);
|
|
275
|
+
return pending;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Hashes the password and stores it, replacing any old one.
|
|
279
|
+
*
|
|
280
|
+
* @param userId - The user.
|
|
281
|
+
* @param password - The plain password (already checked against the rules).
|
|
282
|
+
*/
|
|
283
|
+
async savePassword(userId, password) {
|
|
284
|
+
const passwordHash = await this.passwordPolicy.hashPassword(password);
|
|
285
|
+
await this.database.getRepository(entities_1.PasswordEntity).upsert({ userId, passwordHash }, ['userId']);
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Records the change in the audit log and, if enabled, emails the user that it happened.
|
|
289
|
+
*
|
|
290
|
+
* @param user - The user whose password changed.
|
|
291
|
+
* @param settings - The current settings.
|
|
292
|
+
* @param request - Who made the change.
|
|
293
|
+
* @param how - "reset", "changed" or "first_set".
|
|
294
|
+
*/
|
|
295
|
+
async afterPasswordChanged(user, settings, request, how) {
|
|
296
|
+
await this.events.record({ name: constants_1.AUTH_EVENTS.passwordChanged, userId: user.id, request, details: { how } });
|
|
297
|
+
if (settings.password.notifyOnChange && user.email) {
|
|
298
|
+
await this.notifications.sendNoticeEmail({ type: constants_1.EMAIL_TYPE.passwordChanged, to: user.email });
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
exports.PasswordAuthService = PasswordAuthService;
|
|
303
|
+
exports.PasswordAuthService = PasswordAuthService = __decorate([
|
|
304
|
+
(0, common_1.Injectable)(),
|
|
305
|
+
__param(0, (0, common_1.Inject)(constants_1.AUTH_OPTIONS_TOKEN)),
|
|
306
|
+
__metadata("design:paramtypes", [Object, settings_service_1.SettingsService,
|
|
307
|
+
password_policy_service_1.PasswordPolicyService,
|
|
308
|
+
users_service_1.UsersService,
|
|
309
|
+
sign_in_service_1.SignInService,
|
|
310
|
+
session_service_1.SessionService,
|
|
311
|
+
link_tokens_service_1.LinkTokensService,
|
|
312
|
+
email_verification_service_1.EmailVerificationService,
|
|
313
|
+
notifications_service_1.NotificationsService,
|
|
314
|
+
rate_limiter_service_1.RateLimiterService,
|
|
315
|
+
auth_events_service_1.AuthEventsService])
|
|
316
|
+
], PasswordAuthService);
|
|
317
|
+
//# sourceMappingURL=password-auth.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-auth.service.js","sourceRoot":"","sources":["../../../src/features/passwords/password-auth.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAoD;AAGpD,oDAAgD;AAChD,sDAAkG;AAClG,wEAAmE;AAEnE,2CAmBqB;AACrB,kDAAiE;AACjE,oFAA+E;AAC/E,kGAA6F;AAC7F,+EAA0E;AAC1E,0FAAsF;AACtF,yEAAqE;AACrE,2EAAuE;AAEvE,wEAAmE;AAEnE,kEAA8D;AAG9D,uEAAkE;AAUlE;;GAEG;AAEI,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAKX;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IAbF,QAAQ,CAAa;IAEtC,YAC8B,OAAoB,EAC/B,eAAgC,EAChC,cAAqC,EACrC,KAAmB,EACnB,MAAqB,EACrB,QAAwB,EACxB,UAA6B,EAC7B,iBAA2C,EAC3C,aAAmC,EACnC,WAA+B,EAC/B,MAAyB;QATzB,oBAAe,GAAf,eAAe,CAAiB;QAChC,mBAAc,GAAd,cAAc,CAAuB;QACrC,UAAK,GAAL,KAAK,CAAc;QACnB,WAAM,GAAN,MAAM,CAAe;QACrB,aAAQ,GAAR,QAAQ,CAAgB;QACxB,eAAU,GAAV,UAAU,CAAmB;QAC7B,sBAAiB,GAAjB,iBAAiB,CAA0B;QAC3C,kBAAa,GAAb,aAAa,CAAsB;QACnC,gBAAW,GAAX,WAAW,CAAoB;QAC/B,WAAM,GAAN,MAAM,CAAmB;QAE1C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IACrC,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,QAAQ,CAAC,KAAoB,EAAE,OAAuB;QAC1D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAClD,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,0BAAc,CAAC,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,uBAAW,CAAC,WAAW,CAAC,CAAC;QAEvG,MAAM,KAAK,GAAG,IAAA,4BAAc,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,IAAA,kCAAoB,EAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACvF,IAAI,CAAC,uBAAuB,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;QAClE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,0BAA0B,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAEhG,MAAM,aAAa,GAAqB;YACtC,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,0BAAc,CAAC,oBAAoB;YAC3C,OAAO,EAAE,4BAAgB,CAAC,UAAU;YACpC,oBAAoB,EAAE,IAAI,CAAC,uBAAuB,CAAC,WAAW,EAAE,QAAQ,CAAC;SAC1E,CAAC;QAEF,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAC7D,IAAI,YAAY,EAAE,CAAC;YACjB,2EAA2E;YAC3E,IAAI,CAAC,YAAY,CAAC,eAAe;gBAAE,MAAM,IAAI,CAAC,iBAAiB,CAAC,qBAAqB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YACtG,OAAO,aAAa,CAAC;QACvB,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QACtE,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE;YACpE,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAC7C;gBACE,KAAK;gBACL,WAAW;gBACX,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,IAAI;gBAC1C,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,IAAI;gBACxC,aAAa,EAAE,KAAK,CAAC,WAAW,KAAK,IAAI;gBACzC,qBAAqB,EAAE,KAAK,CAAC,mBAAmB,KAAK,IAAI;aAC1D,EACD,QAAQ,EACR,OAAO,EACP,WAAW,CACZ,CAAC;YACF,MAAM,WAAW,CAAC,MAAM,CAAC,yBAAc,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC;YACnF,OAAO,WAAW,CAAC;QACrB,CAAC,CAAC,CAAC;QAEH,IAAI,OAAO,CAAC,MAAM,KAAK,0BAAc,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,0BAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAErI,IAAI,IAAI,CAAC,KAAK,CAAC,uBAAuB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,gCAAoB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/F,MAAM,IAAI,CAAC,iBAAiB,CAAC,qBAAqB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACrE,CAAC;QACD,OAAO,aAAa,CAAC;IACvB,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,kBAAkB,CAAC,UAAmB,EAAE,aAAsB,EAAE,OAAuB;QAC3F,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAClD,MAAM,KAAK,GAAG,IAAA,4BAAc,EAAC,UAAU,CAAC,CAAC;QACzC,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,0BAAc,CAAC,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,uBAAW,CAAC,WAAW,CAAC,CAAC;QACvG,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,0BAAc,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,uBAAW,CAAC,gBAAgB,CAAC,CAAC;QAErG,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QACrD,MAAM,cAAc,GAAG,IAAI;YACzB,CAAC,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,yBAAc,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC;YAC3F,CAAC,CAAC,IAAI,CAAC;QAET,0FAA0F;QAC1F,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,cAAc,EAAE,YAAY,IAAI,IAAI,EAAE,aAAa,CAAC,CAAC;QACtH,IAAI,CAAC,IAAI,IAAI,CAAC,cAAc,IAAI,CAAC,eAAe,EAAE,CAAC;YACjD,MAAM,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,0BAAc,CAAC,QAAQ,EAAE,kCAAsB,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC;YACtI,MAAM,IAAI,sBAAS,CAAC,uBAAW,CAAC,kBAAkB,CAAC,CAAC;QACtD,CAAC;QAED,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,0BAAc,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;QACrE,IAAI,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,cAAc,CAAC,YAAY,CAAC,EAAE,CAAC;YACjE,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,aAAuB,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,0BAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IACtF,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,oBAAoB,CAAC,UAAmB,EAAE,OAAuB;QACrE,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,IAAA,4BAAc,EAAC,UAAU,CAAC,CAAC;QACzC,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,0BAAc,CAAC,kBAAkB,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,uBAAW,CAAC,kBAAkB,CAAC,CAAC;QACrH,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,0BAAc,CAAC,qBAAqB,CAAC,KAAK,CAAC,EAAE,uBAAW,CAAC,qBAAqB,CAAC,CAAC;QAE/G,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QACrD,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,0BAAc,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,KAAK,0BAAc,CAAC,SAAS,EAAE,CAAC;YAC/F,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,wBAAY,CAAC,aAAa,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;YAChG,MAAM,IAAI,CAAC,aAAa,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,sBAAU,CAAC,aAAa,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YACjG,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,uBAAW,CAAC,sBAAsB,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QACnG,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,IAAa,EAAE,OAAO,EAAE,4BAAgB,CAAC,sBAAsB,EAAE,CAAC;IACtF,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,aAAa,CAAC,UAAmB,EAAE,WAAoB,EAAE,OAAuB;QACpF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAClD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,0BAA0B,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAC7F,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,UAAU,EAAE,wBAAY,CAAC,aAAa,CAAC,CAAC;QAE7F,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACvF,oFAAoF;QACpF,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,KAAK,0BAAc,CAAC,OAAO;YAAE,MAAM,IAAI,sBAAS,CAAC,uBAAW,CAAC,oBAAoB,CAAC,CAAC;QAE7I,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QAC3C,MAAM,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,wBAAY,CAAC,aAAa,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5E,MAAM,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,EAAE,8BAAkB,CAAC,aAAa,CAAC,CAAC;QACjF,MAAM,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC5D,MAAM,IAAI,CAAC,oBAAoB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,gCAAoB,CAAC,KAAK,CAAC,CAAC;QACrF,OAAO,EAAE,OAAO,EAAE,IAAa,EAAE,OAAO,EAAE,4BAAgB,CAAC,aAAa,EAAE,CAAC;IAC7E,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,cAAc,CAAC,MAAc,EAAE,SAAiB,EAAE,eAAwB,EAAE,WAAoB,EAAE,OAAuB;QAC7H,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAClD,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,0BAAc,CAAC,qBAAqB,CAAC,MAAM,CAAC,EAAE,uBAAW,CAAC,qBAAqB,CAAC,CAAC;QAChH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QAErD,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,yBAAc,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QACxG,IAAI,cAAc,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,cAAc,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC;YAChH,MAAM,IAAI,sBAAS,CAAC,uBAAW,CAAC,kBAAkB,CAAC,CAAC;QACtD,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,0BAA0B,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAC7F,IAAI,cAAc,IAAI,CAAC,MAAM,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,cAAc,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;YACxG,MAAM,IAAI,sBAAS,CAAC,uBAAW,CAAC,eAAe,EAAE,EAAE,YAAY,EAAE,CAAC,gCAAoB,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC;QAClH,CAAC;QAED,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC1C,MAAM,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,MAAM,EAAE,8BAAkB,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC;QAC7F,MAAM,IAAI,CAAC,oBAAoB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,gCAAoB,CAAC,OAAO,CAAC,CAAC,CAAC,gCAAoB,CAAC,QAAQ,CAAC,CAAC;QACxI,OAAO,EAAE,OAAO,EAAE,IAAa,EAAE,OAAO,EAAE,4BAAgB,CAAC,eAAe,EAAE,CAAC;IAC/E,CAAC;IAED,8FAA8F;IAE9F;;;OAGG;IACK,KAAK,CAAC,mBAAmB;QAC/B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,CAAC;QAC1D,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO;YAAE,MAAM,IAAI,sBAAS,CAAC,uBAAW,CAAC,oBAAoB,CAAC,CAAC;QACtF,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;;;;;OASG;IACK,uBAAuB,CAAC,KAAoB,EAAE,KAAa,EAAE,WAA0B,EAAE,QAAsB;QACrH,MAAM,KAAK,GAAG,QAAQ,CAAC,YAAY,CAAC;QACpC,IAAI,CAAC,KAAK,CAAC,OAAO;YAAE,MAAM,IAAI,sBAAS,CAAC,uBAAW,CAAC,YAAY,CAAC,CAAC;QAClE,IAAI,CAAC,IAAA,kCAAoB,EAAC,KAAK,EAAE,KAAK,CAAC,mBAAmB,CAAC;YAAE,MAAM,IAAI,sBAAS,CAAC,uBAAW,CAAC,qBAAqB,CAAC,CAAC;QACpH,IAAI,KAAK,CAAC,kBAAkB,IAAI,CAAC,WAAW;YAAE,MAAM,IAAI,sBAAS,CAAC,uBAAW,CAAC,YAAY,CAAC,CAAC;QAC5F,IAAI,KAAK,CAAC,uBAAuB,IAAI,CAAC,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YAC3F,MAAM,IAAI,sBAAS,CAAC,uBAAW,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,CAAC,8BAAkB,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACtG,CAAC;QACD,IAAI,KAAK,CAAC,sBAAsB,IAAI,KAAK,CAAC,WAAW,KAAK,IAAI;YAAE,MAAM,IAAI,sBAAS,CAAC,uBAAW,CAAC,gBAAgB,CAAC,CAAC;QAClH,IAAI,KAAK,CAAC,8BAA8B,IAAI,KAAK,CAAC,mBAAmB,KAAK,IAAI;YAAE,MAAM,IAAI,sBAAS,CAAC,uBAAW,CAAC,wBAAwB,CAAC,CAAC;IAC5I,CAAC;IAED;;;;;;;OAOG;IACK,uBAAuB,CAAC,WAA0B,EAAE,QAAsB;QAChF,MAAM,OAAO,GAA0B,EAAE,CAAC;QAC1C,IAAI,QAAQ,CAAC,UAAU,CAAC,oBAAoB;YAAE,OAAO,CAAC,IAAI,CAAC,gCAAoB,CAAC,KAAK,CAAC,CAAC;QACvF,IAAI,QAAQ,CAAC,UAAU,CAAC,oBAAoB,IAAI,WAAW;YAAE,OAAO,CAAC,IAAI,CAAC,gCAAoB,CAAC,KAAK,CAAC,CAAC;QACtG,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;OAKG;IACK,KAAK,CAAC,YAAY,CAAC,MAAc,EAAE,QAAgB;QACzD,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QACtE,MAAM,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,yBAAc,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IACjG,CAAC;IAED;;;;;;;OAOG;IACK,KAAK,CAAC,oBAAoB,CAAC,IAAgB,EAAE,QAAsB,EAAE,OAAuB,EAAE,GAAuB;QAC3H,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,uBAAW,CAAC,eAAe,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QAC5G,IAAI,QAAQ,CAAC,QAAQ,CAAC,cAAc,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACnD,MAAM,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,EAAE,IAAI,EAAE,sBAAU,CAAC,eAAe,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QACjG,CAAC;IACH,CAAC;CACF,CAAA;AAvRY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,mBAAU,GAAE;IAKR,WAAA,IAAA,eAAM,EAAC,8BAAkB,CAAC,CAAA;6CACO,kCAAe;QAChB,+CAAqB;QAC9B,4BAAY;QACX,+BAAa;QACX,gCAAc;QACZ,uCAAiB;QACV,qDAAwB;QAC5B,4CAAoB;QACtB,yCAAkB;QACvB,uCAAiB;GAdjC,mBAAmB,CAuR/B"}
|