@ambushsoftworks/nestjs-auth-graphql 0.11.0 → 0.14.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.
Files changed (105) hide show
  1. package/CHANGELOG.md +300 -0
  2. package/README.md +411 -3
  3. package/dist/auth.module.d.ts +15 -1
  4. package/dist/auth.module.d.ts.map +1 -1
  5. package/dist/auth.module.js +114 -16
  6. package/dist/auth.module.js.map +1 -1
  7. package/dist/constants.d.ts +2 -0
  8. package/dist/constants.d.ts.map +1 -1
  9. package/dist/constants.js +3 -1
  10. package/dist/constants.js.map +1 -1
  11. package/dist/decorators/require-scopes.decorator.d.ts +2 -0
  12. package/dist/decorators/require-scopes.decorator.d.ts.map +1 -0
  13. package/dist/decorators/require-scopes.decorator.js +8 -0
  14. package/dist/decorators/require-scopes.decorator.js.map +1 -0
  15. package/dist/guards/csrf.guard.d.ts +2 -0
  16. package/dist/guards/csrf.guard.d.ts.map +1 -1
  17. package/dist/guards/csrf.guard.js +9 -2
  18. package/dist/guards/csrf.guard.js.map +1 -1
  19. package/dist/guards/scope.guard.d.ts +8 -0
  20. package/dist/guards/scope.guard.d.ts.map +1 -0
  21. package/dist/guards/scope.guard.js +53 -0
  22. package/dist/guards/scope.guard.js.map +1 -0
  23. package/dist/index.d.ts +6 -6
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +6 -6
  26. package/dist/index.js.map +1 -1
  27. package/dist/interfaces/api-key-repository.interface.d.ts +3 -0
  28. package/dist/interfaces/api-key-repository.interface.d.ts.map +1 -1
  29. package/dist/interfaces/biometric-repository.interface.d.ts +29 -17
  30. package/dist/interfaces/biometric-repository.interface.d.ts.map +1 -1
  31. package/dist/interfaces/biometric-verifier.interface.d.ts +10 -0
  32. package/dist/interfaces/biometric-verifier.interface.d.ts.map +1 -0
  33. package/dist/interfaces/{magic-link-repository.interface.js → biometric-verifier.interface.js} +1 -1
  34. package/dist/interfaces/biometric-verifier.interface.js.map +1 -0
  35. package/dist/resolvers/base-auth.resolver.d.ts.map +1 -1
  36. package/dist/resolvers/base-auth.resolver.js +0 -15
  37. package/dist/resolvers/base-auth.resolver.js.map +1 -1
  38. package/dist/services/auth.service.d.ts.map +1 -1
  39. package/dist/services/auth.service.js +10 -3
  40. package/dist/services/auth.service.js.map +1 -1
  41. package/dist/services/biometric-auth.service.d.ts +47 -17
  42. package/dist/services/biometric-auth.service.d.ts.map +1 -1
  43. package/dist/services/biometric-auth.service.js +109 -68
  44. package/dist/services/biometric-auth.service.js.map +1 -1
  45. package/dist/services/biometric-challenge.service.d.ts +27 -0
  46. package/dist/services/biometric-challenge.service.d.ts.map +1 -0
  47. package/dist/services/biometric-challenge.service.js +116 -0
  48. package/dist/services/biometric-challenge.service.js.map +1 -0
  49. package/dist/services/biometric-verification.service.d.ts.map +1 -1
  50. package/dist/services/biometric-verification.service.js +4 -0
  51. package/dist/services/biometric-verification.service.js.map +1 -1
  52. package/dist/services/verification.service.d.ts +2 -1
  53. package/dist/services/verification.service.d.ts.map +1 -1
  54. package/dist/services/verification.service.js +38 -8
  55. package/dist/services/verification.service.js.map +1 -1
  56. package/dist/strategies/api-key.strategy.d.ts +6 -1
  57. package/dist/strategies/api-key.strategy.d.ts.map +1 -1
  58. package/dist/strategies/api-key.strategy.js +40 -6
  59. package/dist/strategies/api-key.strategy.js.map +1 -1
  60. package/dist/strategies/external-jwt.strategy.d.ts +19 -0
  61. package/dist/strategies/external-jwt.strategy.d.ts.map +1 -0
  62. package/dist/strategies/external-jwt.strategy.js +124 -0
  63. package/dist/strategies/external-jwt.strategy.js.map +1 -0
  64. package/dist/strategies/jwt.strategy.d.ts.map +1 -1
  65. package/dist/strategies/jwt.strategy.js +1 -0
  66. package/dist/strategies/jwt.strategy.js.map +1 -1
  67. package/dist/test-utils/mock-repositories.d.ts.map +1 -1
  68. package/dist/test-utils/mock-repositories.js +8 -7
  69. package/dist/test-utils/mock-repositories.js.map +1 -1
  70. package/dist/utils/provider-helpers.d.ts +6 -0
  71. package/dist/utils/provider-helpers.d.ts.map +1 -1
  72. package/dist/utils/provider-helpers.js +4 -0
  73. package/dist/utils/provider-helpers.js.map +1 -1
  74. package/dist/utils/verification-base-url.d.ts +2 -0
  75. package/dist/utils/verification-base-url.d.ts.map +1 -0
  76. package/dist/utils/verification-base-url.js +19 -0
  77. package/dist/utils/verification-base-url.js.map +1 -0
  78. package/dist/verifiers/es256-device-key.verifier.d.ts +14 -0
  79. package/dist/verifiers/es256-device-key.verifier.d.ts.map +1 -0
  80. package/dist/verifiers/es256-device-key.verifier.js +42 -0
  81. package/dist/verifiers/es256-device-key.verifier.js.map +1 -0
  82. package/package.json +8 -2
  83. package/dist/interfaces/magic-link-repository.interface.d.ts +0 -6
  84. package/dist/interfaces/magic-link-repository.interface.d.ts.map +0 -1
  85. package/dist/interfaces/magic-link-repository.interface.js.map +0 -1
  86. package/dist/interfaces/password-reset-strategy.interface.d.ts +0 -7
  87. package/dist/interfaces/password-reset-strategy.interface.d.ts.map +0 -1
  88. package/dist/interfaces/password-reset-strategy.interface.js +0 -3
  89. package/dist/interfaces/password-reset-strategy.interface.js.map +0 -1
  90. package/dist/repositories/noop-biometric.repository.d.ts +0 -26
  91. package/dist/repositories/noop-biometric.repository.d.ts.map +0 -1
  92. package/dist/repositories/noop-biometric.repository.js +0 -56
  93. package/dist/repositories/noop-biometric.repository.js.map +0 -1
  94. package/dist/repositories/noop-magic-link.repository.d.ts +0 -9
  95. package/dist/repositories/noop-magic-link.repository.d.ts.map +0 -1
  96. package/dist/repositories/noop-magic-link.repository.js +0 -37
  97. package/dist/repositories/noop-magic-link.repository.js.map +0 -1
  98. package/dist/strategies/magic-link.strategy.d.ts +0 -16
  99. package/dist/strategies/magic-link.strategy.d.ts.map +0 -1
  100. package/dist/strategies/magic-link.strategy.js +0 -80
  101. package/dist/strategies/magic-link.strategy.js.map +0 -1
  102. package/dist/strategies/verification-code.strategy.d.ts +0 -11
  103. package/dist/strategies/verification-code.strategy.d.ts.map +0 -1
  104. package/dist/strategies/verification-code.strategy.js +0 -44
  105. package/dist/strategies/verification-code.strategy.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"biometric-auth.service.d.ts","sourceRoot":"","sources":["../../src/services/biometric-auth.service.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC1E,OAAO,EAAE,uBAAuB,EAAE,MAAM,kDAAkD,CAAC;AAC3F,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,8CAA8C,CAAC;AACpF,OAAO,EAAE,WAAW,EAAiB,MAAM,qCAAqC,CAAC;AAuBjF,qBACa,oBAAoB;IAG7B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAE/B,OAAO,CAAC,QAAQ,CAAC,sBAAsB;IAEvC,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IAEpC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,mBAAmB;gBARnB,cAAc,EAAE,eAAe,CAAC,SAAS,CAAC,EAE1C,sBAAsB,EAAE,uBAAuB,EAE/C,mBAAmB,EAAE,oBAAoB,EAEzC,cAAc,EAAE,WAAW,EAC3B,UAAU,EAAE,UAAU,EACtB,mBAAmB,EAAE,mBAAmB;IAUrD,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAkCtF,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgClD,yBAAyB,CAC7B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IAgEnD,kBAAkB,CACtB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CAgB1D"}
1
+ {"version":3,"file":"biometric-auth.service.d.ts","sourceRoot":"","sources":["../../src/services/biometric-auth.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,oBAAoB,EACrB,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4CAA4C,CAAC;AAChF,OAAO,EAAE,WAAW,EAAiB,MAAM,qCAAqC,CAAC;AAEjF,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG7C,MAAM,WAAW,0BAA0B;IACzC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;CACzB;AAGD,KAAK,cAAc,GAAG;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CACjF,CAAC;AA0BF,qBACa,oBAAoB;IAM7B,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IAEpC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAG/B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAX9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyC;IAChE,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAkC;gBAIpD,mBAAmB,EAAE,oBAAoB,EAEzC,cAAc,EAAE,WAAW,EAE5C,SAAS,EAAE,kBAAkB,EAAE,EACd,UAAU,EAAE,yBAAyB,EACrC,WAAW,EAAE,WAAW;IAsBrC,eAAe,CAAC,KAAK,EAAE;QAC3B,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpC,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAgDjC,gBAAgB,CACpB,YAAY,EAAE,MAAM,EACpB,IAAI,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,GAChD,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAqBxE,yBAAyB,CAC7B,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EACvE,IAAI,GAAE;QAAE,GAAG,CAAC,EAAE,cAAc,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GACtE,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IAsFnD,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,EAAE,CAAC;IAWtF,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB3E,OAAO,KAAK,gBAAgB,GAE3B;IAED,OAAO,CAAC,SAAS;CASlB"}
@@ -11,102 +11,143 @@ var __metadata = (this && this.__metadata) || function (k, v) {
11
11
  var __param = (this && this.__param) || function (paramIndex, decorator) {
12
12
  return function (target, key) { decorator(target, key, paramIndex); }
13
13
  };
14
+ var BiometricAuthService_1;
14
15
  Object.defineProperty(exports, "__esModule", { value: true });
15
16
  exports.BiometricAuthService = void 0;
16
17
  const common_1 = require("@nestjs/common");
17
- const jwt_1 = require("@nestjs/jwt");
18
- const refresh_token_service_1 = require("./refresh-token.service");
18
+ const crypto_1 = require("crypto");
19
19
  const auth_logger_interface_1 = require("../interfaces/auth-logger.interface");
20
- let BiometricAuthService = class BiometricAuthService {
21
- constructor(userRepository, refreshTokenRepository, biometricRepository, securityLogger, jwtService, refreshTokenService) {
22
- this.userRepository = userRepository;
23
- this.refreshTokenRepository = refreshTokenRepository;
20
+ const constants_1 = require("../constants");
21
+ const biometric_challenge_service_1 = require("./biometric-challenge.service");
22
+ const auth_service_1 = require("./auth.service");
23
+ let BiometricAuthService = BiometricAuthService_1 = class BiometricAuthService {
24
+ constructor(biometricRepository, securityLogger, verifiers, challenges, authService) {
24
25
  this.biometricRepository = biometricRepository;
25
26
  this.securityLogger = securityLogger;
26
- this.jwtService = jwtService;
27
- this.refreshTokenService = refreshTokenService;
27
+ this.challenges = challenges;
28
+ this.authService = authService;
29
+ this.logger = new common_1.Logger(BiometricAuthService_1.name);
30
+ this.verifiersByAlgorithm = new Map(verifiers.map((v) => [v.algorithm, v]));
28
31
  }
29
- async enableBiometric(userId, deviceId, publicKey) {
30
- if (!deviceId || deviceId.trim().length === 0) {
31
- throw new common_1.BadRequestException('Device ID is required');
32
+ async enrolCredential(input) {
33
+ const algorithm = input.algorithm ?? this.defaultAlgorithm;
34
+ const verifier = this.verifiersByAlgorithm.get(algorithm);
35
+ if (!verifier) {
36
+ throw new common_1.UnauthorizedException(`No biometric verifier is configured for algorithm '${algorithm}'.`);
32
37
  }
33
- const user = await this.userRepository.findById(userId);
34
- if (!user) {
35
- throw new common_1.UnauthorizedException('User not found');
38
+ if (!(await verifier.validatePublicKey(input.publicKey))) {
39
+ throw new common_1.UnauthorizedException(`The public key is not a valid '${algorithm}' key.`);
36
40
  }
37
- await this.userRepository.enableBiometric(userId, deviceId, publicKey);
41
+ const record = {
42
+ credentialId: (0, crypto_1.randomUUID)(),
43
+ userId: input.userId,
44
+ publicKey: input.publicKey,
45
+ algorithm,
46
+ deviceName: input.deviceName,
47
+ createdAt: new Date(),
48
+ lastUsedAt: null,
49
+ isActive: true,
50
+ ...(input.metadata ? { metadata: input.metadata } : {}),
51
+ };
52
+ await this.biometricRepository.storeCredential(record);
38
53
  this.securityLogger.log(auth_logger_interface_1.SecurityEvent.BIOMETRIC_ENROLLED, {
39
- userId,
40
- deviceId,
54
+ userId: input.userId,
55
+ credentialId: record.credentialId,
56
+ algorithm,
41
57
  });
42
- return true;
58
+ return this.summarise(record);
43
59
  }
44
- async disableBiometric(userId) {
45
- const user = await this.userRepository.findById(userId);
46
- if (!user) {
47
- throw new common_1.UnauthorizedException('User not found');
48
- }
49
- await this.userRepository.disableBiometric(userId);
50
- this.securityLogger.log(auth_logger_interface_1.SecurityEvent.BIOMETRIC_DISABLED, {
51
- userId,
52
- });
53
- return true;
60
+ async requestChallenge(credentialId, opts = {}) {
61
+ return this.challenges.issueChallenge(credentialId, opts);
54
62
  }
55
- async authenticateWithBiometric(userId, deviceId) {
56
- if (!deviceId || deviceId.trim().length === 0) {
57
- throw new common_1.UnauthorizedException('Device ID is required');
63
+ async authenticateWithBiometric(input, opts = {}) {
64
+ const fail = (reason, credentialId) => {
65
+ this.securityLogger.log(auth_logger_interface_1.SecurityEvent.BIOMETRIC_LOGIN_FAILURE, {
66
+ credentialId,
67
+ ipAddress: opts.ipAddress,
68
+ realm: opts.realm,
69
+ reason,
70
+ });
71
+ throw new common_1.UnauthorizedException('Biometric authentication failed');
72
+ };
73
+ const challenge = await this.challenges.consumeChallenge(input.challengeId);
74
+ if (!challenge) {
75
+ return fail('challenge_unavailable', input.credentialId);
76
+ }
77
+ if (challenge.credentialId !== input.credentialId) {
78
+ return fail('challenge_credential_mismatch', input.credentialId);
58
79
  }
59
- const user = await this.userRepository.findById(userId);
60
- if (!user) {
61
- throw new common_1.UnauthorizedException('Invalid biometric credentials');
80
+ const credential = await this.biometricRepository.getCredential(input.credentialId);
81
+ if (!credential) {
82
+ return fail('credential_unknown', input.credentialId);
62
83
  }
63
- const credentials = await this.biometricRepository.listBiometricCredentials(userId);
64
- if (credentials.length === 0) {
65
- throw new common_1.UnauthorizedException('Biometric authentication not enabled');
84
+ if (!credential.isActive) {
85
+ return fail('credential_inactive', input.credentialId);
66
86
  }
67
- const isValidDevice = credentials.some((cred) => cred.credentialId === deviceId);
68
- if (!isValidDevice) {
69
- throw new common_1.UnauthorizedException('Biometric authentication not enabled on this device');
87
+ const verifier = this.verifiersByAlgorithm.get(credential.algorithm);
88
+ if (!verifier) {
89
+ this.logger.error(`Credential ${input.credentialId} is enrolled under algorithm ` +
90
+ `'${credential.algorithm}', for which no verifier is configured. ` +
91
+ 'Add it to biometric.verifiers, or deactivate the credential.');
92
+ return fail('verifier_missing', input.credentialId);
70
93
  }
71
- const accessToken = this.jwtService.sign({
72
- userId: user.id,
73
- email: user.email,
94
+ const valid = await verifier.verify({
95
+ publicKey: credential.publicKey,
96
+ challenge: challenge.challenge,
97
+ signature: input.signature,
74
98
  });
75
- const { token: refreshToken, hash: refreshTokenHash } = this.refreshTokenService.generateToken();
76
- await this.refreshTokenRepository.create({
77
- userId: user.id,
78
- token: refreshToken,
79
- hashedToken: refreshTokenHash,
80
- expiresAt: this.refreshTokenService.getExpiryDate(),
99
+ if (!valid) {
100
+ return fail('signature_invalid', input.credentialId);
101
+ }
102
+ const session = await this.authService.issueAuthSession(credential.userId, opts.res, opts.realm);
103
+ void this.biometricRepository
104
+ .touchCredentialLastUsed(input.credentialId)
105
+ .catch((error) => {
106
+ this.logger.warn(`Recording last use of credential ${input.credentialId} failed: ${error instanceof Error ? error.message : String(error)}`);
81
107
  });
82
- await this.userRepository.updateLastBiometricLogin(userId);
83
108
  this.securityLogger.log(auth_logger_interface_1.SecurityEvent.BIOMETRIC_LOGIN_SUCCESS, {
84
- userId,
109
+ userId: credential.userId,
110
+ credentialId: input.credentialId,
111
+ ipAddress: opts.ipAddress,
112
+ realm: opts.realm,
85
113
  });
86
- return { accessToken, refreshToken };
114
+ return session;
87
115
  }
88
- async getBiometricStatus(userId) {
89
- const user = await this.userRepository.findById(userId);
90
- if (!user) {
91
- throw new common_1.UnauthorizedException('User not found');
116
+ async listCredentials(userId, realm) {
117
+ const credentials = await this.biometricRepository.listCredentials(userId, realm);
118
+ return credentials.filter((c) => c.isActive).map((c) => this.summarise(c));
119
+ }
120
+ async removeCredential(userId, credentialId) {
121
+ const credential = await this.biometricRepository.getCredential(credentialId);
122
+ if (!credential || credential.userId !== userId) {
123
+ throw new common_1.UnauthorizedException('Biometric credential not found');
92
124
  }
93
- const credentials = await this.biometricRepository.listBiometricCredentials(userId);
94
- const enabled = credentials.length > 0;
95
- const deviceId = credentials.length > 0 ? credentials[0].credentialId : null;
125
+ await this.biometricRepository.deactivateCredential(credentialId);
126
+ this.securityLogger.log(auth_logger_interface_1.SecurityEvent.BIOMETRIC_DEVICE_REMOVED, {
127
+ userId,
128
+ credentialId,
129
+ });
130
+ }
131
+ get defaultAlgorithm() {
132
+ return this.verifiersByAlgorithm.keys().next().value;
133
+ }
134
+ summarise(record) {
96
135
  return {
97
- enabled,
98
- deviceId,
136
+ credentialId: record.credentialId,
137
+ deviceName: record.deviceName,
138
+ algorithm: record.algorithm,
139
+ createdAt: record.createdAt,
140
+ lastUsedAt: record.lastUsedAt,
99
141
  };
100
142
  }
101
143
  };
102
144
  exports.BiometricAuthService = BiometricAuthService;
103
- exports.BiometricAuthService = BiometricAuthService = __decorate([
145
+ exports.BiometricAuthService = BiometricAuthService = BiometricAuthService_1 = __decorate([
104
146
  (0, common_1.Injectable)(),
105
- __param(0, (0, common_1.Inject)('USER_REPOSITORY')),
106
- __param(1, (0, common_1.Inject)('REFRESH_TOKEN_REPOSITORY')),
107
- __param(2, (0, common_1.Inject)('BIOMETRIC_REPOSITORY')),
108
- __param(3, (0, common_1.Inject)('AUTH_LOGGER')),
109
- __metadata("design:paramtypes", [Object, Object, Object, Object, jwt_1.JwtService,
110
- refresh_token_service_1.RefreshTokenService])
147
+ __param(0, (0, common_1.Inject)(constants_1.BIOMETRIC_REPOSITORY)),
148
+ __param(1, (0, common_1.Inject)(constants_1.AUTH_LOGGER)),
149
+ __param(2, (0, common_1.Inject)(constants_1.BIOMETRIC_VERIFIERS)),
150
+ __metadata("design:paramtypes", [Object, Object, Array, biometric_challenge_service_1.BiometricChallengeService,
151
+ auth_service_1.AuthService])
111
152
  ], BiometricAuthService);
112
153
  //# sourceMappingURL=biometric-auth.service.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"biometric-auth.service.js","sourceRoot":"","sources":["../../src/services/biometric-auth.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"biometric-auth.service.js","sourceRoot":"","sources":["../../src/services/biometric-auth.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { BiometricChallengeRecord, IBiometricChallengeStore } from '../interfaces/biometric-repository.interface';
2
+ import { IRateLimiter } from '../interfaces/rate-limiter.interface';
3
+ import { IAuthLogger } from '../interfaces/auth-logger.interface';
4
+ import type { AuthModuleOptions } from '../auth.module';
5
+ export declare class BiometricChallengeService {
6
+ private readonly store;
7
+ private readonly rateLimiter;
8
+ private readonly securityLogger;
9
+ private readonly options;
10
+ private lastSweepAt;
11
+ private readonly ipHashSalt;
12
+ constructor(store: IBiometricChallengeStore, rateLimiter: IRateLimiter, securityLogger: IAuthLogger, options: AuthModuleOptions);
13
+ private get expirySeconds();
14
+ private get rateLimit();
15
+ issueChallenge(credentialId: string, opts?: {
16
+ ipAddress?: string;
17
+ realm?: string;
18
+ }): Promise<{
19
+ challengeId: string;
20
+ challenge: string;
21
+ expiresAt: Date;
22
+ } | null>;
23
+ private withinLimit;
24
+ consumeChallenge(challengeId: string): Promise<BiometricChallengeRecord | null>;
25
+ private sweep;
26
+ }
27
+ //# sourceMappingURL=biometric-challenge.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"biometric-challenge.service.d.ts","sourceRoot":"","sources":["../../src/services/biometric-challenge.service.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACzB,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACpE,OAAO,EAAE,WAAW,EAAiB,MAAM,qCAAqC,CAAC;AAGjF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAyBxD,qBACa,yBAAyB;IAgBlC,OAAO,CAAC,QAAQ,CAAC,KAAK;IAEtB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAE5B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAE/B,OAAO,CAAC,QAAQ,CAAC,OAAO;IArB1B,OAAO,CAAC,WAAW,CAAK;IAWxB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAIjB,KAAK,EAAE,wBAAwB,EAE/B,WAAW,EAAE,YAAY,EAEzB,cAAc,EAAE,WAAW,EAE3B,OAAO,EAAE,iBAAiB;IAK7C,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,KAAK,SAAS,GAEpB;IAgCK,cAAc,CAClB,YAAY,EAAE,MAAM,EACpB,IAAI,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,GAChD,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;YAoDhE,WAAW;IAsBnB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC;YAqBvE,KAAK;CAkBpB"}
@@ -0,0 +1,116 @@
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.BiometricChallengeService = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const crypto_1 = require("crypto");
18
+ const auth_logger_interface_1 = require("../interfaces/auth-logger.interface");
19
+ const constants_1 = require("../constants");
20
+ const ip_hash_1 = require("../utils/ip-hash");
21
+ const CHALLENGE_BYTES = 32;
22
+ const DEFAULT_EXPIRY_SECONDS = 60;
23
+ const DEFAULT_RATE_LIMIT = { maxAttempts: 5, windowMs: 60_000 };
24
+ const SWEEP_THROTTLE_MS = 2 * 60_000;
25
+ let BiometricChallengeService = class BiometricChallengeService {
26
+ constructor(store, rateLimiter, securityLogger, options) {
27
+ this.store = store;
28
+ this.rateLimiter = rateLimiter;
29
+ this.securityLogger = securityLogger;
30
+ this.options = options;
31
+ this.lastSweepAt = 0;
32
+ this.ipHashSalt = process.env.AUTH_IP_HASH_SALT || this.options.jwtSecret || '';
33
+ }
34
+ get expirySeconds() {
35
+ return this.options.biometric?.challengeExpirySeconds ?? DEFAULT_EXPIRY_SECONDS;
36
+ }
37
+ get rateLimit() {
38
+ return this.options.biometric?.challengeRateLimit ?? DEFAULT_RATE_LIMIT;
39
+ }
40
+ async issueChallenge(credentialId, opts = {}) {
41
+ const { ipAddress, realm } = opts;
42
+ const { maxAttempts, windowMs } = this.rateLimit;
43
+ const scope = realm ? `${realm}:` : '';
44
+ const credentialKey = `auth:biometricChallenge:${scope}${credentialId}`;
45
+ if (!(await this.withinLimit(credentialKey, maxAttempts, windowMs))) {
46
+ this.securityLogger.log(auth_logger_interface_1.SecurityEvent.BIOMETRIC_LOGIN_FAILURE, {
47
+ credentialId,
48
+ realm,
49
+ reason: 'challenge_rate_limited',
50
+ });
51
+ return null;
52
+ }
53
+ if (ipAddress) {
54
+ const ipKey = `auth:biometricChallengeIp:${scope}${(0, ip_hash_1.hashIp)(ipAddress, this.ipHashSalt)}`;
55
+ if (!(await this.withinLimit(ipKey, maxAttempts * 10, windowMs))) {
56
+ this.securityLogger.log(auth_logger_interface_1.SecurityEvent.BIOMETRIC_LOGIN_FAILURE, {
57
+ ipAddress,
58
+ realm,
59
+ reason: 'challenge_ip_rate_limited',
60
+ });
61
+ return null;
62
+ }
63
+ }
64
+ const challenge = (0, crypto_1.randomBytes)(CHALLENGE_BYTES).toString('base64');
65
+ const expiresAt = new Date(Date.now() + this.expirySeconds * 1000);
66
+ const challengeId = await this.store.storeChallenge({
67
+ credentialId,
68
+ challenge,
69
+ expiresAt,
70
+ });
71
+ void this.sweep();
72
+ return { challengeId, challenge, expiresAt };
73
+ }
74
+ async withinLimit(key, limit, windowMs) {
75
+ const { allowed } = await this.rateLimiter.checkRateLimit(key, limit, windowMs);
76
+ if (!allowed) {
77
+ return false;
78
+ }
79
+ await this.rateLimiter.recordAttempt(key, windowMs);
80
+ return true;
81
+ }
82
+ async consumeChallenge(challengeId) {
83
+ const record = await this.store.consumeChallenge(challengeId);
84
+ if (!record) {
85
+ this.securityLogger.log(auth_logger_interface_1.SecurityEvent.BIOMETRIC_LOGIN_FAILURE, {
86
+ challengeId,
87
+ reason: 'challenge_unavailable',
88
+ });
89
+ return null;
90
+ }
91
+ return record;
92
+ }
93
+ async sweep() {
94
+ const now = Date.now();
95
+ if (now - this.lastSweepAt < SWEEP_THROTTLE_MS) {
96
+ return;
97
+ }
98
+ this.lastSweepAt = now;
99
+ try {
100
+ await this.store.deleteExpiredChallenges();
101
+ }
102
+ catch (error) {
103
+ this.securityLogger.warn(`Sweeping expired biometric challenges failed: ${error instanceof Error ? error.message : String(error)}. Challenges still expire — consumeChallenge re-checks it.`, 'BiometricChallengeService');
104
+ }
105
+ }
106
+ };
107
+ exports.BiometricChallengeService = BiometricChallengeService;
108
+ exports.BiometricChallengeService = BiometricChallengeService = __decorate([
109
+ (0, common_1.Injectable)(),
110
+ __param(0, (0, common_1.Inject)(constants_1.BIOMETRIC_REPOSITORY)),
111
+ __param(1, (0, common_1.Inject)(constants_1.RATE_LIMITER)),
112
+ __param(2, (0, common_1.Inject)(constants_1.AUTH_LOGGER)),
113
+ __param(3, (0, common_1.Inject)(constants_1.AUTH_MODULE_OPTIONS)),
114
+ __metadata("design:paramtypes", [Object, Object, Object, Object])
115
+ ], BiometricChallengeService);
116
+ //# sourceMappingURL=biometric-challenge.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"biometric-challenge.service.js","sourceRoot":"","sources":["../../src/services/biometric-challenge.service.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"biometric-verification.service.d.ts","sourceRoot":"","sources":["../../src/services/biometric-verification.service.ts"],"names":[],"mappings":"AA6BA,qBACa,4BAA4B;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiD;IACxE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAa;IAiB3C,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC;IA4Cb,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA2C/D,OAAO,CAAC,cAAc;IAkDtB,sBAAsB,IAAI,MAAM,EAAE;CAGnC"}
1
+ {"version":3,"file":"biometric-verification.service.d.ts","sourceRoot":"","sources":["../../src/services/biometric-verification.service.ts"],"names":[],"mappings":"AA6BA,qBACa,4BAA4B;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiD;IACxE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAa;IAiB3C,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC;IA4Cb,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA2C/D,OAAO,CAAC,cAAc;IA6DtB,sBAAsB,IAAI,MAAM,EAAE;CAGnC"}
@@ -61,6 +61,10 @@ let BiometricVerificationService = BiometricVerificationService_1 = class Biomet
61
61
  if (publicKey.asymmetricKeyType !== 'ec') {
62
62
  throw new Error(`Invalid key type: expected 'ec', got '${publicKey.asymmetricKeyType}'`);
63
63
  }
64
+ const namedCurve = publicKey.asymmetricKeyDetails?.namedCurve;
65
+ if (namedCurve !== 'prime256v1') {
66
+ throw new Error(`Invalid curve: expected 'prime256v1' (P-256), got '${namedCurve ?? 'unknown'}'`);
67
+ }
64
68
  return publicKey;
65
69
  }
66
70
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"biometric-verification.service.js","sourceRoot":"","sources":["../../src/services/biometric-verification.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"biometric-verification.service.js","sourceRoot":"","sources":["../../src/services/biometric-verification.service.ts"],"names":[],"mappings":"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"}
@@ -43,7 +43,8 @@ export declare class VerificationService {
43
43
  verifyCredential(identifier: string, type: 'email' | 'password-reset', submitted: string, realm?: string): Promise<boolean>;
44
44
  generateToken(identifier: string, type: 'email' | 'password-reset', realm?: string): Promise<string>;
45
45
  verifyToken(identifier: string, type: 'email' | 'password-reset', token: string, realm?: string): Promise<boolean>;
46
- buildVerificationUrl(token: string, type: 'email' | 'password-reset', email: string): string;
46
+ buildVerificationUrl(token: string, type: 'email' | 'password-reset', email: string, realm?: string): string;
47
+ private resolveBaseUrl;
47
48
  private verificationPath;
48
49
  private buildPageUrl;
49
50
  private hashToken;
@@ -1 +1 @@
1
- {"version":3,"file":"verification.service.d.ts","sourceRoot":"","sources":["../../src/services/verification.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"verification.service.d.ts","sourceRoot":"","sources":["../../src/services/verification.service.ts"],"names":[],"mappings":"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"}
@@ -18,6 +18,7 @@ const crypto_1 = require("crypto");
18
18
  const constants_1 = require("../constants");
19
19
  const auth_logger_interface_1 = require("../interfaces/auth-logger.interface");
20
20
  const verification_type_enum_1 = require("../enums/verification-type.enum");
21
+ const verification_base_url_1 = require("../utils/verification-base-url");
21
22
  let VerificationService = class VerificationService {
22
23
  constructor(options, userRepository, verificationRepository, securityLogger) {
23
24
  this.options = options;
@@ -202,7 +203,7 @@ let VerificationService = class VerificationService {
202
203
  const token = await this.generateToken(identifier, type, realm);
203
204
  return {
204
205
  credential: token,
205
- url: this.buildVerificationUrl(token, type, identifier),
206
+ url: this.buildVerificationUrl(token, type, identifier, realm),
206
207
  expiresInMinutes: this.tokenExpiresInMinutes,
207
208
  mode,
208
209
  };
@@ -210,7 +211,7 @@ let VerificationService = class VerificationService {
210
211
  const code = await this.generateCode(identifier, type, realm);
211
212
  return {
212
213
  credential: code,
213
- url: this.buildPageUrl(type),
214
+ url: this.buildPageUrl(type, realm),
214
215
  expiresInMinutes: this.codeExpiresInMinutes,
215
216
  mode,
216
217
  };
@@ -281,22 +282,51 @@ let VerificationService = class VerificationService {
281
282
  });
282
283
  return true;
283
284
  }
284
- buildVerificationUrl(token, type, email) {
285
- const baseUrl = this.options.verification?.baseUrl;
285
+ buildVerificationUrl(token, type, email, realm) {
286
+ const where = realm ? `realm "${realm}"` : 'a request with no realm';
287
+ let baseUrl;
288
+ try {
289
+ baseUrl = this.resolveBaseUrl(realm);
290
+ }
291
+ catch (error) {
292
+ throw new Error(`verification.baseUrl resolver threw for ${where}: ` +
293
+ `${error instanceof Error ? error.message : String(error)}. ` +
294
+ 'In token mode the link is the credential, so there is no usable email ' +
295
+ 'to send without it.');
296
+ }
286
297
  if (!baseUrl) {
287
- throw new Error('verification.baseUrl is required to build verification URLs. ' +
288
- 'Configure it in AuthModuleOptions.verification.baseUrl.');
298
+ throw new Error(`verification.baseUrl produced no URL for ${where}. ` +
299
+ 'Configure it in AuthModuleOptions.verification.baseUrl, and if it is a ' +
300
+ 'resolver, make sure it returns a URL for every realm.');
289
301
  }
302
+ (0, verification_base_url_1.assertUsableBaseUrl)(baseUrl, `verification.baseUrl for ${where}`);
290
303
  const url = new URL(this.verificationPath(type), baseUrl);
291
304
  url.searchParams.set('token', token);
292
305
  url.searchParams.set('email', email);
293
306
  return url.toString();
294
307
  }
308
+ resolveBaseUrl(realm) {
309
+ const configured = this.options.verification?.baseUrl;
310
+ if (typeof configured === 'function') {
311
+ return configured(realm);
312
+ }
313
+ return configured;
314
+ }
295
315
  verificationPath(type) {
296
316
  return type === 'email' ? '/verify-email' : '/reset-password';
297
317
  }
298
- buildPageUrl(type) {
299
- const configured = this.options.verification?.baseUrl;
318
+ buildPageUrl(type, realm) {
319
+ let configured;
320
+ try {
321
+ configured = this.resolveBaseUrl(realm);
322
+ }
323
+ catch (error) {
324
+ this.securityLogger.warn('verification.baseUrl resolver threw for ' +
325
+ `${realm ? `realm "${realm}"` : 'a request with no realm'}: ` +
326
+ `${error instanceof Error ? error.message : String(error)}. ` +
327
+ 'Sending the email without a link; the 6-digit code is unaffected.', 'VerificationService');
328
+ configured = undefined;
329
+ }
300
330
  const legacy = process.env.FRONTEND_URL;
301
331
  if (!configured && legacy && !this.warnedLegacyBaseUrl) {
302
332
  this.warnedLegacyBaseUrl = true;