@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.
- package/CHANGELOG.md +300 -0
- package/README.md +411 -3
- package/dist/auth.module.d.ts +15 -1
- package/dist/auth.module.d.ts.map +1 -1
- package/dist/auth.module.js +114 -16
- package/dist/auth.module.js.map +1 -1
- package/dist/constants.d.ts +2 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +3 -1
- package/dist/constants.js.map +1 -1
- package/dist/decorators/require-scopes.decorator.d.ts +2 -0
- package/dist/decorators/require-scopes.decorator.d.ts.map +1 -0
- package/dist/decorators/require-scopes.decorator.js +8 -0
- package/dist/decorators/require-scopes.decorator.js.map +1 -0
- package/dist/guards/csrf.guard.d.ts +2 -0
- package/dist/guards/csrf.guard.d.ts.map +1 -1
- package/dist/guards/csrf.guard.js +9 -2
- package/dist/guards/csrf.guard.js.map +1 -1
- package/dist/guards/scope.guard.d.ts +8 -0
- package/dist/guards/scope.guard.d.ts.map +1 -0
- package/dist/guards/scope.guard.js +53 -0
- package/dist/guards/scope.guard.js.map +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/interfaces/api-key-repository.interface.d.ts +3 -0
- package/dist/interfaces/api-key-repository.interface.d.ts.map +1 -1
- package/dist/interfaces/biometric-repository.interface.d.ts +29 -17
- package/dist/interfaces/biometric-repository.interface.d.ts.map +1 -1
- package/dist/interfaces/biometric-verifier.interface.d.ts +10 -0
- package/dist/interfaces/biometric-verifier.interface.d.ts.map +1 -0
- package/dist/interfaces/{magic-link-repository.interface.js → biometric-verifier.interface.js} +1 -1
- package/dist/interfaces/biometric-verifier.interface.js.map +1 -0
- package/dist/resolvers/base-auth.resolver.d.ts.map +1 -1
- package/dist/resolvers/base-auth.resolver.js +0 -15
- package/dist/resolvers/base-auth.resolver.js.map +1 -1
- package/dist/services/auth.service.d.ts.map +1 -1
- package/dist/services/auth.service.js +10 -3
- package/dist/services/auth.service.js.map +1 -1
- package/dist/services/biometric-auth.service.d.ts +47 -17
- package/dist/services/biometric-auth.service.d.ts.map +1 -1
- package/dist/services/biometric-auth.service.js +109 -68
- package/dist/services/biometric-auth.service.js.map +1 -1
- package/dist/services/biometric-challenge.service.d.ts +27 -0
- package/dist/services/biometric-challenge.service.d.ts.map +1 -0
- package/dist/services/biometric-challenge.service.js +116 -0
- package/dist/services/biometric-challenge.service.js.map +1 -0
- package/dist/services/biometric-verification.service.d.ts.map +1 -1
- package/dist/services/biometric-verification.service.js +4 -0
- package/dist/services/biometric-verification.service.js.map +1 -1
- package/dist/services/verification.service.d.ts +2 -1
- package/dist/services/verification.service.d.ts.map +1 -1
- package/dist/services/verification.service.js +38 -8
- package/dist/services/verification.service.js.map +1 -1
- package/dist/strategies/api-key.strategy.d.ts +6 -1
- package/dist/strategies/api-key.strategy.d.ts.map +1 -1
- package/dist/strategies/api-key.strategy.js +40 -6
- package/dist/strategies/api-key.strategy.js.map +1 -1
- package/dist/strategies/external-jwt.strategy.d.ts +19 -0
- package/dist/strategies/external-jwt.strategy.d.ts.map +1 -0
- package/dist/strategies/external-jwt.strategy.js +124 -0
- package/dist/strategies/external-jwt.strategy.js.map +1 -0
- package/dist/strategies/jwt.strategy.d.ts.map +1 -1
- package/dist/strategies/jwt.strategy.js +1 -0
- package/dist/strategies/jwt.strategy.js.map +1 -1
- package/dist/test-utils/mock-repositories.d.ts.map +1 -1
- package/dist/test-utils/mock-repositories.js +8 -7
- package/dist/test-utils/mock-repositories.js.map +1 -1
- package/dist/utils/provider-helpers.d.ts +6 -0
- package/dist/utils/provider-helpers.d.ts.map +1 -1
- package/dist/utils/provider-helpers.js +4 -0
- package/dist/utils/provider-helpers.js.map +1 -1
- package/dist/utils/verification-base-url.d.ts +2 -0
- package/dist/utils/verification-base-url.d.ts.map +1 -0
- package/dist/utils/verification-base-url.js +19 -0
- package/dist/utils/verification-base-url.js.map +1 -0
- package/dist/verifiers/es256-device-key.verifier.d.ts +14 -0
- package/dist/verifiers/es256-device-key.verifier.d.ts.map +1 -0
- package/dist/verifiers/es256-device-key.verifier.js +42 -0
- package/dist/verifiers/es256-device-key.verifier.js.map +1 -0
- package/package.json +8 -2
- package/dist/interfaces/magic-link-repository.interface.d.ts +0 -6
- package/dist/interfaces/magic-link-repository.interface.d.ts.map +0 -1
- package/dist/interfaces/magic-link-repository.interface.js.map +0 -1
- package/dist/interfaces/password-reset-strategy.interface.d.ts +0 -7
- package/dist/interfaces/password-reset-strategy.interface.d.ts.map +0 -1
- package/dist/interfaces/password-reset-strategy.interface.js +0 -3
- package/dist/interfaces/password-reset-strategy.interface.js.map +0 -1
- package/dist/repositories/noop-biometric.repository.d.ts +0 -26
- package/dist/repositories/noop-biometric.repository.d.ts.map +0 -1
- package/dist/repositories/noop-biometric.repository.js +0 -56
- package/dist/repositories/noop-biometric.repository.js.map +0 -1
- package/dist/repositories/noop-magic-link.repository.d.ts +0 -9
- package/dist/repositories/noop-magic-link.repository.d.ts.map +0 -1
- package/dist/repositories/noop-magic-link.repository.js +0 -37
- package/dist/repositories/noop-magic-link.repository.js.map +0 -1
- package/dist/strategies/magic-link.strategy.d.ts +0 -16
- package/dist/strategies/magic-link.strategy.d.ts.map +0 -1
- package/dist/strategies/magic-link.strategy.js +0 -80
- package/dist/strategies/magic-link.strategy.js.map +0 -1
- package/dist/strategies/verification-code.strategy.d.ts +0 -11
- package/dist/strategies/verification-code.strategy.d.ts.map +0 -1
- package/dist/strategies/verification-code.strategy.js +0 -44
- 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":"
|
|
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
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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.
|
|
27
|
-
this.
|
|
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
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
34
|
-
|
|
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
|
-
|
|
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
|
-
|
|
54
|
+
userId: input.userId,
|
|
55
|
+
credentialId: record.credentialId,
|
|
56
|
+
algorithm,
|
|
41
57
|
});
|
|
42
|
-
return
|
|
58
|
+
return this.summarise(record);
|
|
43
59
|
}
|
|
44
|
-
async
|
|
45
|
-
|
|
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(
|
|
56
|
-
|
|
57
|
-
|
|
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
|
|
60
|
-
if (!
|
|
61
|
-
|
|
80
|
+
const credential = await this.biometricRepository.getCredential(input.credentialId);
|
|
81
|
+
if (!credential) {
|
|
82
|
+
return fail('credential_unknown', input.credentialId);
|
|
62
83
|
}
|
|
63
|
-
|
|
64
|
-
|
|
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
|
|
68
|
-
if (!
|
|
69
|
-
|
|
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
|
|
72
|
-
|
|
73
|
-
|
|
94
|
+
const valid = await verifier.verify({
|
|
95
|
+
publicKey: credential.publicKey,
|
|
96
|
+
challenge: challenge.challenge,
|
|
97
|
+
signature: input.signature,
|
|
74
98
|
});
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
|
114
|
+
return session;
|
|
87
115
|
}
|
|
88
|
-
async
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
98
|
-
|
|
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)(
|
|
106
|
-
__param(1, (0, common_1.Inject)(
|
|
107
|
-
__param(2, (0, common_1.Inject)(
|
|
108
|
-
|
|
109
|
-
|
|
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":"
|
|
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;
|
|
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":";;;;;;;;;;AAAA,2CAAyE;AACzE,mCAAkE;AA6B3D,IAAM,4BAA4B,oCAAlC,MAAM,4BAA4B;IAAlC;QACY,WAAM,GAAG,IAAI,eAAM,CAAC,8BAA4B,CAAC,IAAI,CAAC,CAAC;QACvD,wBAAmB,GAAG,CAAC,OAAO,CAAC,CAAC;
|
|
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":"AAQA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAiB,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,iDAAiD,CAAC;AAC1F,OAAO,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;
|
|
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
|
|
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(
|
|
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
|
-
|
|
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;
|