@ambushsoftworks/nestjs-auth-graphql 0.17.1 → 0.18.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 +50 -0
- package/README.md +173 -0
- package/dist/auth.module.d.ts +10 -0
- package/dist/auth.module.d.ts.map +1 -1
- package/dist/auth.module.js +41 -3
- package/dist/auth.module.js.map +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -1
- package/dist/constants.js.map +1 -1
- package/dist/exceptions/email-challenge.exceptions.d.ts +8 -0
- package/dist/exceptions/email-challenge.exceptions.d.ts.map +1 -0
- package/dist/exceptions/email-challenge.exceptions.js +21 -0
- package/dist/exceptions/email-challenge.exceptions.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/interfaces/auth-logger.interface.d.ts +5 -1
- package/dist/interfaces/auth-logger.interface.d.ts.map +1 -1
- package/dist/interfaces/auth-logger.interface.js +4 -0
- package/dist/interfaces/auth-logger.interface.js.map +1 -1
- package/dist/interfaces/email-challenge-repository.interface.d.ts +22 -0
- package/dist/interfaces/email-challenge-repository.interface.d.ts.map +1 -0
- package/dist/interfaces/email-challenge-repository.interface.js +3 -0
- package/dist/interfaces/email-challenge-repository.interface.js.map +1 -0
- package/dist/interfaces/email-service.interface.d.ts +5 -0
- package/dist/interfaces/email-service.interface.d.ts.map +1 -1
- package/dist/interfaces/email-template-renderer.interface.d.ts +7 -0
- package/dist/interfaces/email-template-renderer.interface.d.ts.map +1 -1
- package/dist/interfaces/index.d.ts +1 -0
- package/dist/interfaces/index.d.ts.map +1 -1
- package/dist/interfaces/index.js +1 -0
- package/dist/interfaces/index.js.map +1 -1
- package/dist/repositories/in-memory-email-challenge.repository.d.ts +14 -0
- package/dist/repositories/in-memory-email-challenge.repository.d.ts.map +1 -0
- package/dist/repositories/in-memory-email-challenge.repository.js +55 -0
- package/dist/repositories/in-memory-email-challenge.repository.js.map +1 -0
- package/dist/services/configurable-email.service.d.ts +2 -1
- package/dist/services/configurable-email.service.d.ts.map +1 -1
- package/dist/services/configurable-email.service.js +24 -0
- package/dist/services/configurable-email.service.js.map +1 -1
- package/dist/services/default-email-template-renderer.d.ts +7 -0
- package/dist/services/default-email-template-renderer.d.ts.map +1 -1
- package/dist/services/default-email-template-renderer.js +31 -0
- package/dist/services/default-email-template-renderer.js.map +1 -1
- package/dist/services/email-challenge.service.d.ts +74 -0
- package/dist/services/email-challenge.service.d.ts.map +1 -0
- package/dist/services/email-challenge.service.js +306 -0
- package/dist/services/email-challenge.service.js.map +1 -0
- package/dist/services/passkey.service.d.ts.map +1 -1
- package/dist/services/passkey.service.js +8 -20
- package/dist/services/passkey.service.js.map +1 -1
- package/dist/testing/email-challenge-repository.contract.d.ts +15 -0
- package/dist/testing/email-challenge-repository.contract.d.ts.map +1 -0
- package/dist/testing/email-challenge-repository.contract.js +287 -0
- package/dist/testing/email-challenge-repository.contract.js.map +1 -0
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +4 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/utils/rate-limit-helpers.d.ts +4 -0
- package/dist/utils/rate-limit-helpers.d.ts.map +1 -0
- package/dist/utils/rate-limit-helpers.js +20 -0
- package/dist/utils/rate-limit-helpers.js.map +1 -0
- package/examples/email-challenge/prisma-email-challenge.repository.ts +85 -0
- package/examples/email-challenge/schema.prisma +24 -0
- package/package.json +1 -1
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { AuthModuleOptions } from '../auth.module';
|
|
2
|
+
import { IAuthLogger } from '../interfaces/auth-logger.interface';
|
|
3
|
+
import { IEmailChallengeRepository } from '../interfaces/email-challenge-repository.interface';
|
|
4
|
+
import { IEmailService } from '../interfaces/email-service.interface';
|
|
5
|
+
import { IRateLimiter } from '../interfaces/rate-limiter.interface';
|
|
6
|
+
export declare const DEFAULT_EMAIL_CHALLENGE_ISSUE_LIMITS: {
|
|
7
|
+
readonly cooldownSeconds: 60;
|
|
8
|
+
readonly perHour: 5;
|
|
9
|
+
readonly perIpPerHour: 30;
|
|
10
|
+
};
|
|
11
|
+
export type EmailChallengeFailureReason = 'WRONG' | 'EXPIRED' | 'LOCKED';
|
|
12
|
+
export type EmailChallengeResult = {
|
|
13
|
+
ok: true;
|
|
14
|
+
email: string;
|
|
15
|
+
purpose: string;
|
|
16
|
+
} | {
|
|
17
|
+
ok: false;
|
|
18
|
+
reason: EmailChallengeFailureReason;
|
|
19
|
+
};
|
|
20
|
+
export interface IssuedEmailChallenge {
|
|
21
|
+
challengeId: string;
|
|
22
|
+
expiresAt: Date;
|
|
23
|
+
expiresInMinutes: number;
|
|
24
|
+
}
|
|
25
|
+
interface CallOptions {
|
|
26
|
+
realm?: string | null;
|
|
27
|
+
ipAddress?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare class EmailChallengeService {
|
|
30
|
+
private readonly repository;
|
|
31
|
+
private readonly options;
|
|
32
|
+
private readonly securityLogger;
|
|
33
|
+
private readonly rateLimiter;
|
|
34
|
+
private readonly emailService;
|
|
35
|
+
private readonly logger;
|
|
36
|
+
private readonly key;
|
|
37
|
+
private readonly realmsEnabled;
|
|
38
|
+
private readonly ipHashSalt;
|
|
39
|
+
private lastSweepAt;
|
|
40
|
+
private warnedMissingIp;
|
|
41
|
+
constructor(repository: IEmailChallengeRepository | null, options: AuthModuleOptions, securityLogger: IAuthLogger, rateLimiter: IRateLimiter, emailService?: IEmailService | null);
|
|
42
|
+
get available(): boolean;
|
|
43
|
+
issue(input: {
|
|
44
|
+
email: string;
|
|
45
|
+
purpose: string;
|
|
46
|
+
emailData?: Record<string, unknown>;
|
|
47
|
+
}, opts?: CallOptions & {
|
|
48
|
+
ttlMinutes?: number;
|
|
49
|
+
}): Promise<IssuedEmailChallenge>;
|
|
50
|
+
verify(input: {
|
|
51
|
+
challengeId: string;
|
|
52
|
+
code: string;
|
|
53
|
+
email: string;
|
|
54
|
+
purpose: string;
|
|
55
|
+
}, opts?: CallOptions): Promise<EmailChallengeResult>;
|
|
56
|
+
revoke(input: {
|
|
57
|
+
purpose: string;
|
|
58
|
+
email?: string;
|
|
59
|
+
}, opts?: CallOptions): Promise<number>;
|
|
60
|
+
private requireRepository;
|
|
61
|
+
private requireIssuing;
|
|
62
|
+
private realmOf;
|
|
63
|
+
private mac;
|
|
64
|
+
private hashEmail;
|
|
65
|
+
private hashPurpose;
|
|
66
|
+
private hashCode;
|
|
67
|
+
private issueLimits;
|
|
68
|
+
private assertWithinLimits;
|
|
69
|
+
private record;
|
|
70
|
+
private cancelUnsent;
|
|
71
|
+
private sweep;
|
|
72
|
+
}
|
|
73
|
+
export {};
|
|
74
|
+
//# sourceMappingURL=email-challenge.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-challenge.service.d.ts","sourceRoot":"","sources":["../../src/services/email-challenge.service.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAiB,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAEL,yBAAyB,EAC1B,MAAM,oDAAoD,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAsBpE,eAAO,MAAM,oCAAoC;;;;CAIvC,CAAC;AAWX,MAAM,MAAM,2BAA2B,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEzE,MAAM,MAAM,oBAAoB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,2BAA2B,CAAA;CAAE,CAAC;AAEvD,MAAM,WAAW,oBAAoB;IAEnC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,IAAI,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,UAAU,WAAW;IAEnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAmCD,qBACa,qBAAqB;IAU9B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAE3B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAExB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAE/B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAE5B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAjB/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,eAAe,CAAS;gBAIb,UAAU,EAAE,yBAAyB,GAAG,IAAI,EAE5C,OAAO,EAAE,iBAAiB,EAE1B,cAAc,EAAE,WAAW,EAE3B,WAAW,EAAE,YAAY,EAEzB,YAAY,GAAE,aAAa,GAAG,IAAW;IAqB5D,IAAI,SAAS,IAAI,OAAO,CAEvB;IAqBK,KAAK,CACT,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EAC9E,IAAI,GAAE,WAAW,GAAG;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAO,GAC/C,OAAO,CAAC,oBAAoB,CAAC;IA+E1B,MAAM,CACV,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAC5E,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,oBAAoB,CAAC;IAqE1B,MAAM,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;IAcjG,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,OAAO;IAaf,OAAO,CAAC,GAAG;IAIX,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,WAAW;YAsCL,kBAAkB;YAYlB,MAAM;YAON,YAAY;YAaZ,KAAK;CAgBpB"}
|
|
@@ -0,0 +1,306 @@
|
|
|
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
|
+
var EmailChallengeService_1;
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.EmailChallengeService = exports.DEFAULT_EMAIL_CHALLENGE_ISSUE_LIMITS = void 0;
|
|
17
|
+
const common_1 = require("@nestjs/common");
|
|
18
|
+
const crypto_1 = require("crypto");
|
|
19
|
+
const constants_1 = require("../constants");
|
|
20
|
+
const auth_logger_interface_1 = require("../interfaces/auth-logger.interface");
|
|
21
|
+
const email_challenge_exceptions_1 = require("../exceptions/email-challenge.exceptions");
|
|
22
|
+
const step_up_exceptions_1 = require("../exceptions/step-up.exceptions");
|
|
23
|
+
const ip_hash_1 = require("../utils/ip-hash");
|
|
24
|
+
const rate_limit_helpers_1 = require("../utils/rate-limit-helpers");
|
|
25
|
+
const CODE_ATTEMPTS = 3;
|
|
26
|
+
const DEFAULT_TTL_MINUTES = 15;
|
|
27
|
+
const MAX_TTL_MINUTES = 60;
|
|
28
|
+
const MAX_PURPOSE_LENGTH = 200;
|
|
29
|
+
const MAX_CHALLENGE_ID_LENGTH = 128;
|
|
30
|
+
const CHALLENGE_ID_BYTES = 32;
|
|
31
|
+
const HOUR_MS = 3_600_000;
|
|
32
|
+
const SWEEP_THROTTLE_MS = 2 * 60_000;
|
|
33
|
+
const HKDF_INFO = 'nestjs-auth-graphql email-challenge/v1';
|
|
34
|
+
exports.DEFAULT_EMAIL_CHALLENGE_ISSUE_LIMITS = {
|
|
35
|
+
cooldownSeconds: 60,
|
|
36
|
+
perHour: 5,
|
|
37
|
+
perIpPerHour: 30,
|
|
38
|
+
};
|
|
39
|
+
let EmailChallengeService = EmailChallengeService_1 = class EmailChallengeService {
|
|
40
|
+
constructor(repository, options, securityLogger, rateLimiter, emailService = null) {
|
|
41
|
+
this.repository = repository;
|
|
42
|
+
this.options = options;
|
|
43
|
+
this.securityLogger = securityLogger;
|
|
44
|
+
this.rateLimiter = rateLimiter;
|
|
45
|
+
this.emailService = emailService;
|
|
46
|
+
this.logger = new common_1.Logger(EmailChallengeService_1.name);
|
|
47
|
+
this.lastSweepAt = 0;
|
|
48
|
+
this.warnedMissingIp = false;
|
|
49
|
+
this.key = Buffer.from((0, crypto_1.hkdfSync)('sha256', options.verificationCodeSecret || options.jwtSecret, Buffer.alloc(0), HKDF_INFO, 32));
|
|
50
|
+
this.realmsEnabled = Boolean(options.realmExtractorInstance);
|
|
51
|
+
this.ipHashSalt = process.env.AUTH_IP_HASH_SALT || options.jwtSecret || '';
|
|
52
|
+
}
|
|
53
|
+
get available() {
|
|
54
|
+
return this.repository !== null && typeof this.emailService?.sendEmailChallengeCode === 'function';
|
|
55
|
+
}
|
|
56
|
+
async issue(input, opts = {}) {
|
|
57
|
+
const { repository, send } = this.requireIssuing();
|
|
58
|
+
const realm = this.realmOf(opts);
|
|
59
|
+
const email = (0, rate_limit_helpers_1.normaliseEmail)(input.email);
|
|
60
|
+
const purpose = requirePurpose(input.purpose);
|
|
61
|
+
const emailData = requireEmailData(input.emailData);
|
|
62
|
+
const ttlMinutes = requireTtl(opts.ttlMinutes ?? this.options.emailChallenge?.ttlMinutes);
|
|
63
|
+
const emailHash = this.hashEmail(email, realm);
|
|
64
|
+
const purposeHash = this.hashPurpose(purpose, realm);
|
|
65
|
+
const { cooldown, hourly, perIp } = this.issueLimits(emailHash, purposeHash, realm, opts.ipAddress);
|
|
66
|
+
await this.assertWithinLimits([cooldown, hourly, perIp]);
|
|
67
|
+
await this.record([cooldown, perIp]);
|
|
68
|
+
const id = (0, crypto_1.randomBytes)(CHALLENGE_ID_BYTES).toString('base64url');
|
|
69
|
+
const code = String((0, crypto_1.randomInt)(0, 1_000_000)).padStart(6, '0');
|
|
70
|
+
const now = Date.now();
|
|
71
|
+
const expiresAt = new Date(now + ttlMinutes * 60_000);
|
|
72
|
+
await repository.invalidateChallenges({ purposeHash, emailHash });
|
|
73
|
+
await repository.createChallenge({
|
|
74
|
+
id,
|
|
75
|
+
emailHash,
|
|
76
|
+
purposeHash,
|
|
77
|
+
codeHash: this.hashCode(id, code),
|
|
78
|
+
attempts: 0,
|
|
79
|
+
consumedAt: null,
|
|
80
|
+
expiresAt,
|
|
81
|
+
createdAt: new Date(now),
|
|
82
|
+
});
|
|
83
|
+
try {
|
|
84
|
+
await send(email, code, ttlMinutes, {
|
|
85
|
+
purpose,
|
|
86
|
+
...(emailData !== undefined ? { data: emailData } : {}),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
await this.cancelUnsent(repository, id);
|
|
91
|
+
this.securityLogger.error('Email challenge code could not be sent', error instanceof Error ? error.stack : String(error), 'EmailChallengeService');
|
|
92
|
+
throw new email_challenge_exceptions_1.EmailChallengeSendFailedException();
|
|
93
|
+
}
|
|
94
|
+
await this.record([hourly]);
|
|
95
|
+
this.securityLogger.log(auth_logger_interface_1.SecurityEvent.EMAIL_CHALLENGE_ISSUED, {
|
|
96
|
+
email,
|
|
97
|
+
purpose,
|
|
98
|
+
realm,
|
|
99
|
+
ipAddress: opts.ipAddress,
|
|
100
|
+
challenge: challengeRef(id),
|
|
101
|
+
expiresAt,
|
|
102
|
+
});
|
|
103
|
+
void this.sweep(repository);
|
|
104
|
+
return { challengeId: id, expiresAt, expiresInMinutes: ttlMinutes };
|
|
105
|
+
}
|
|
106
|
+
async verify(input, opts = {}) {
|
|
107
|
+
const repository = this.requireRepository();
|
|
108
|
+
const realm = this.realmOf(opts);
|
|
109
|
+
const email = (0, rate_limit_helpers_1.normaliseEmail)(input.email);
|
|
110
|
+
const purpose = requirePurpose(input.purpose);
|
|
111
|
+
const id = input.challengeId;
|
|
112
|
+
const refuse = (reason, cause) => {
|
|
113
|
+
this.securityLogger.log(reason === 'LOCKED' ? auth_logger_interface_1.SecurityEvent.EMAIL_CHALLENGE_LOCKED : auth_logger_interface_1.SecurityEvent.EMAIL_CHALLENGE_FAILED, {
|
|
114
|
+
email,
|
|
115
|
+
purpose,
|
|
116
|
+
realm,
|
|
117
|
+
ipAddress: opts.ipAddress,
|
|
118
|
+
...(typeof id === 'string' ? { challenge: challengeRef(id) } : {}),
|
|
119
|
+
reason: cause,
|
|
120
|
+
});
|
|
121
|
+
return { ok: false, reason };
|
|
122
|
+
};
|
|
123
|
+
if (typeof id !== 'string' || id === '' || id.length > MAX_CHALLENGE_ID_LENGTH) {
|
|
124
|
+
return refuse('EXPIRED', 'challenge_malformed');
|
|
125
|
+
}
|
|
126
|
+
const challenge = await repository.findChallenge(id);
|
|
127
|
+
if (!challenge)
|
|
128
|
+
return refuse('EXPIRED', 'challenge_unknown');
|
|
129
|
+
if (!sameHash(challenge.emailHash, this.hashEmail(email, realm))) {
|
|
130
|
+
return refuse('EXPIRED', 'email_mismatch');
|
|
131
|
+
}
|
|
132
|
+
if (!sameHash(challenge.purposeHash, this.hashPurpose(purpose, realm))) {
|
|
133
|
+
return refuse('EXPIRED', 'purpose_mismatch');
|
|
134
|
+
}
|
|
135
|
+
if (challenge.expiresAt.getTime() <= Date.now())
|
|
136
|
+
return refuse('EXPIRED', 'challenge_expired');
|
|
137
|
+
if (!(await repository.registerAttempt(id, CODE_ATTEMPTS))) {
|
|
138
|
+
const latest = await repository.findChallenge(id);
|
|
139
|
+
return latest && latest.consumedAt === null
|
|
140
|
+
? refuse('LOCKED', 'attempts_exhausted')
|
|
141
|
+
: refuse('EXPIRED', 'challenge_consumed');
|
|
142
|
+
}
|
|
143
|
+
if (typeof input.code !== 'string' || !sameHash(challenge.codeHash, this.hashCode(id, input.code))) {
|
|
144
|
+
return refuse('WRONG', 'code_wrong');
|
|
145
|
+
}
|
|
146
|
+
if (!(await repository.consumeChallenge(id)))
|
|
147
|
+
return refuse('EXPIRED', 'challenge_consumed');
|
|
148
|
+
this.securityLogger.log(auth_logger_interface_1.SecurityEvent.EMAIL_CHALLENGE_VERIFIED, {
|
|
149
|
+
email,
|
|
150
|
+
purpose,
|
|
151
|
+
realm,
|
|
152
|
+
ipAddress: opts.ipAddress,
|
|
153
|
+
challenge: challengeRef(id),
|
|
154
|
+
});
|
|
155
|
+
return { ok: true, email, purpose };
|
|
156
|
+
}
|
|
157
|
+
async revoke(input, opts = {}) {
|
|
158
|
+
const repository = this.requireRepository();
|
|
159
|
+
const realm = this.realmOf(opts);
|
|
160
|
+
const purpose = requirePurpose(input.purpose);
|
|
161
|
+
return repository.invalidateChallenges({
|
|
162
|
+
purposeHash: this.hashPurpose(purpose, realm),
|
|
163
|
+
...(input.email !== undefined ? { emailHash: this.hashEmail((0, rate_limit_helpers_1.normaliseEmail)(input.email), realm) } : {}),
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
requireRepository() {
|
|
167
|
+
if (!this.repository)
|
|
168
|
+
throw new email_challenge_exceptions_1.EmailChallengeUnavailableException();
|
|
169
|
+
return this.repository;
|
|
170
|
+
}
|
|
171
|
+
requireIssuing() {
|
|
172
|
+
const service = this.emailService;
|
|
173
|
+
const send = service?.sendEmailChallengeCode;
|
|
174
|
+
if (!this.repository || !service || typeof send !== 'function') {
|
|
175
|
+
throw new email_challenge_exceptions_1.EmailChallengeUnavailableException();
|
|
176
|
+
}
|
|
177
|
+
return { repository: this.repository, send: send.bind(service) };
|
|
178
|
+
}
|
|
179
|
+
realmOf(opts) {
|
|
180
|
+
const realm = opts.realm ?? undefined;
|
|
181
|
+
if (this.realmsEnabled && realm === undefined) {
|
|
182
|
+
throw new common_1.BadRequestException('Realm required');
|
|
183
|
+
}
|
|
184
|
+
return realm;
|
|
185
|
+
}
|
|
186
|
+
mac(...parts) {
|
|
187
|
+
return (0, crypto_1.createHmac)('sha256', this.key).update(JSON.stringify(parts)).digest('hex');
|
|
188
|
+
}
|
|
189
|
+
hashEmail(email, realm) {
|
|
190
|
+
return this.mac('email', realm ?? null, email);
|
|
191
|
+
}
|
|
192
|
+
hashPurpose(purpose, realm) {
|
|
193
|
+
return this.mac('purpose', realm ?? null, purpose);
|
|
194
|
+
}
|
|
195
|
+
hashCode(challengeId, code) {
|
|
196
|
+
return this.mac('code', challengeId, code);
|
|
197
|
+
}
|
|
198
|
+
issueLimits(emailHash, purposeHash, realm, ipAddress) {
|
|
199
|
+
const configured = this.options.emailChallenge?.issueLimits;
|
|
200
|
+
const cooldownSeconds = configured?.cooldownSeconds ?? exports.DEFAULT_EMAIL_CHALLENGE_ISSUE_LIMITS.cooldownSeconds;
|
|
201
|
+
const perHour = configured?.perHour ?? exports.DEFAULT_EMAIL_CHALLENGE_ISSUE_LIMITS.perHour;
|
|
202
|
+
const perIpPerHour = configured?.perIpPerHour ?? exports.DEFAULT_EMAIL_CHALLENGE_ISSUE_LIMITS.perIpPerHour;
|
|
203
|
+
const subject = `${emailHash.slice(0, 32)}:${purposeHash.slice(0, 32)}`;
|
|
204
|
+
if (perIpPerHour > 0 && !ipAddress && !this.warnedMissingIp) {
|
|
205
|
+
this.warnedMissingIp = true;
|
|
206
|
+
this.logger.warn('EmailChallengeService.issue was called without opts.ipAddress, so the per-IP limit on ' +
|
|
207
|
+
'sending codes is not applied. Pass the client IP.');
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
...(cooldownSeconds > 0
|
|
211
|
+
? { cooldown: { key: `auth:emailChallenge:cooldown:${subject}`, max: 1, windowMs: cooldownSeconds * 1000 } }
|
|
212
|
+
: {}),
|
|
213
|
+
hourly: { key: `auth:emailChallenge:hour:${subject}`, max: perHour, windowMs: HOUR_MS },
|
|
214
|
+
...(perIpPerHour > 0 && ipAddress
|
|
215
|
+
? {
|
|
216
|
+
perIp: {
|
|
217
|
+
key: `auth:emailChallenge:ip:${(0, rate_limit_helpers_1.realmKeyPrefix)(realm)}${(0, ip_hash_1.hashIp)(ipAddress, this.ipHashSalt)}`,
|
|
218
|
+
max: perIpPerHour,
|
|
219
|
+
windowMs: HOUR_MS,
|
|
220
|
+
},
|
|
221
|
+
}
|
|
222
|
+
: {}),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
async assertWithinLimits(limits) {
|
|
226
|
+
let retryAfter = 0;
|
|
227
|
+
for (const limit of limits) {
|
|
228
|
+
if (!limit)
|
|
229
|
+
continue;
|
|
230
|
+
const { allowed, resetAt } = await this.rateLimiter.checkRateLimit(limit.key, limit.max, limit.windowMs);
|
|
231
|
+
if (!allowed)
|
|
232
|
+
retryAfter = Math.max(retryAfter, (0, rate_limit_helpers_1.retryAfterSeconds)(resetAt));
|
|
233
|
+
}
|
|
234
|
+
if (retryAfter > 0) {
|
|
235
|
+
throw new step_up_exceptions_1.AuthRateLimitException('Too many code requests. Please try again later.', retryAfter);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
async record(limits) {
|
|
239
|
+
for (const limit of limits) {
|
|
240
|
+
if (limit)
|
|
241
|
+
await this.rateLimiter.recordAttempt(limit.key, limit.windowMs);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
async cancelUnsent(repository, id) {
|
|
245
|
+
try {
|
|
246
|
+
await repository.consumeChallenge(id);
|
|
247
|
+
}
|
|
248
|
+
catch (error) {
|
|
249
|
+
this.securityLogger.error('Email challenge could not be cancelled after its email failed to send; it expires on its own', error instanceof Error ? error.stack : String(error), 'EmailChallengeService');
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
async sweep(repository) {
|
|
253
|
+
const now = Date.now();
|
|
254
|
+
if (now - this.lastSweepAt < SWEEP_THROTTLE_MS) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
this.lastSweepAt = now;
|
|
258
|
+
try {
|
|
259
|
+
await repository.deleteExpiredChallenges();
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
this.logger.warn(`Sweeping expired email challenges failed: ${error instanceof Error ? error.message : String(error)}. Challenges still expire: verify checks expiry.`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
exports.EmailChallengeService = EmailChallengeService;
|
|
267
|
+
exports.EmailChallengeService = EmailChallengeService = EmailChallengeService_1 = __decorate([
|
|
268
|
+
(0, common_1.Injectable)(),
|
|
269
|
+
__param(0, (0, common_1.Inject)(constants_1.EMAIL_CHALLENGE_REPOSITORY)),
|
|
270
|
+
__param(1, (0, common_1.Inject)(constants_1.AUTH_MODULE_OPTIONS)),
|
|
271
|
+
__param(2, (0, common_1.Inject)(constants_1.AUTH_LOGGER)),
|
|
272
|
+
__param(3, (0, common_1.Inject)(constants_1.RATE_LIMITER)),
|
|
273
|
+
__param(4, (0, common_1.Inject)(constants_1.EMAIL_SERVICE)),
|
|
274
|
+
__metadata("design:paramtypes", [Object, Object, Object, Object, Object])
|
|
275
|
+
], EmailChallengeService);
|
|
276
|
+
function challengeRef(id) {
|
|
277
|
+
return (0, crypto_1.createHash)('sha256').update(id).digest('hex').slice(0, 16);
|
|
278
|
+
}
|
|
279
|
+
function sameHash(a, b) {
|
|
280
|
+
const left = Buffer.from(String(a), 'utf8');
|
|
281
|
+
const right = Buffer.from(b, 'utf8');
|
|
282
|
+
return left.length === right.length && (0, crypto_1.timingSafeEqual)(left, right);
|
|
283
|
+
}
|
|
284
|
+
function requirePurpose(purpose) {
|
|
285
|
+
if (typeof purpose !== 'string' || purpose.length === 0 || purpose.length > MAX_PURPOSE_LENGTH) {
|
|
286
|
+
throw new common_1.BadRequestException(`An email challenge needs a purpose: a non-empty string of at most ${MAX_PURPOSE_LENGTH} characters`);
|
|
287
|
+
}
|
|
288
|
+
return purpose;
|
|
289
|
+
}
|
|
290
|
+
function requireTtl(ttlMinutes) {
|
|
291
|
+
if (ttlMinutes === undefined)
|
|
292
|
+
return DEFAULT_TTL_MINUTES;
|
|
293
|
+
if (typeof ttlMinutes !== 'number' || !Number.isInteger(ttlMinutes) || ttlMinutes < 1 || ttlMinutes > MAX_TTL_MINUTES) {
|
|
294
|
+
throw new common_1.BadRequestException(`ttlMinutes must be an integer from 1 to ${MAX_TTL_MINUTES}`);
|
|
295
|
+
}
|
|
296
|
+
return ttlMinutes;
|
|
297
|
+
}
|
|
298
|
+
function requireEmailData(data) {
|
|
299
|
+
if (data === undefined)
|
|
300
|
+
return undefined;
|
|
301
|
+
if (typeof data !== 'object' || data === null || Array.isArray(data)) {
|
|
302
|
+
throw new common_1.BadRequestException('emailData must be an object');
|
|
303
|
+
}
|
|
304
|
+
return data;
|
|
305
|
+
}
|
|
306
|
+
//# sourceMappingURL=email-challenge.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-challenge.service.js","sourceRoot":"","sources":["../../src/services/email-challenge.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"passkey.service.d.ts","sourceRoot":"","sources":["../../src/services/passkey.service.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAiB,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,8CAA8C,CAAC;AACnF,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAE1E,OAAO,EACL,kBAAkB,EAKnB,MAAM,4CAA4C,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EACL,eAAe,EAGhB,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"passkey.service.d.ts","sourceRoot":"","sources":["../../src/services/passkey.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,6 +24,7 @@ const webauthn_adapter_1 = require("../passkey/webauthn-adapter");
|
|
|
24
24
|
const passkey_exceptions_1 = require("../exceptions/passkey.exceptions");
|
|
25
25
|
const step_up_exceptions_1 = require("../exceptions/step-up.exceptions");
|
|
26
26
|
const ip_hash_1 = require("../utils/ip-hash");
|
|
27
|
+
const rate_limit_helpers_1 = require("../utils/rate-limit-helpers");
|
|
27
28
|
const provider_helpers_1 = require("../utils/provider-helpers");
|
|
28
29
|
const passkey_rp_1 = require("../utils/passkey-rp");
|
|
29
30
|
const auth_service_1 = require("./auth.service");
|
|
@@ -67,7 +68,7 @@ let PasskeyService = PasskeyService_1 = class PasskeyService {
|
|
|
67
68
|
throw new step_up_exceptions_1.StepUpRequiredException();
|
|
68
69
|
}
|
|
69
70
|
const user = await this.authService.requireActiveUser(userId);
|
|
70
|
-
await this.enforceRateLimit(`auth:passkeyReg:${
|
|
71
|
+
await this.enforceRateLimit(`auth:passkeyReg:${(0, rate_limit_helpers_1.realmKeyPrefix)(opts.realm)}${userId}`);
|
|
71
72
|
const rp = this.relyingParty(opts.realm);
|
|
72
73
|
const existing = await repository.listCredentials(userId, opts.realm);
|
|
73
74
|
const userHandle = existing[0]?.userHandle ?? Buffer.from((0, crypto_1.randomBytes)(USER_HANDLE_BYTES)).toString('base64url');
|
|
@@ -174,7 +175,7 @@ let PasskeyService = PasskeyService_1 = class PasskeyService {
|
|
|
174
175
|
const { webauthn } = this.require();
|
|
175
176
|
this.requireRealm(opts.realm);
|
|
176
177
|
if (opts.ipAddress) {
|
|
177
|
-
await this.enforceRateLimit(`auth:passkeyAuth:${
|
|
178
|
+
await this.enforceRateLimit(`auth:passkeyAuth:${(0, rate_limit_helpers_1.realmKeyPrefix)(opts.realm)}${(0, ip_hash_1.hashIp)(opts.ipAddress, this.ipHashSalt)}`);
|
|
178
179
|
}
|
|
179
180
|
else if (!this.warnedMissingIp) {
|
|
180
181
|
this.warnedMissingIp = true;
|
|
@@ -239,7 +240,7 @@ let PasskeyService = PasskeyService_1 = class PasskeyService {
|
|
|
239
240
|
if (active.length === 0) {
|
|
240
241
|
throw new step_up_exceptions_1.StepUpUnavailableException('passkey');
|
|
241
242
|
}
|
|
242
|
-
await this.enforceRateLimit(`auth:passkeyStepUp:${
|
|
243
|
+
await this.enforceRateLimit(`auth:passkeyStepUp:${(0, rate_limit_helpers_1.realmKeyPrefix)(opts.realm)}${userId}`);
|
|
243
244
|
const timeoutSeconds = this.authenticationTimeoutSeconds;
|
|
244
245
|
const options = await webauthn.authenticationOptions({
|
|
245
246
|
rp: this.relyingParty(opts.realm),
|
|
@@ -289,8 +290,8 @@ let PasskeyService = PasskeyService_1 = class PasskeyService {
|
|
|
289
290
|
async startSignup(input, opts = {}) {
|
|
290
291
|
const { users, tokens, email: mailer } = this.requireSignup();
|
|
291
292
|
this.requireRealm(opts.realm);
|
|
292
|
-
const email = normaliseEmail(input.email);
|
|
293
|
-
const where =
|
|
293
|
+
const email = (0, rate_limit_helpers_1.normaliseEmail)(input.email);
|
|
294
|
+
const where = (0, rate_limit_helpers_1.realmKeyPrefix)(opts.realm);
|
|
294
295
|
if (opts.ipAddress) {
|
|
295
296
|
await this.enforceLimit(`auth:passkeySignupIp:${where}${(0, ip_hash_1.hashIp)(opts.ipAddress, this.ipHashSalt)}`, 5, 3_600_000);
|
|
296
297
|
}
|
|
@@ -514,7 +515,7 @@ let PasskeyService = PasskeyService_1 = class PasskeyService {
|
|
|
514
515
|
async enforceLimit(key, maxAttempts, windowMs) {
|
|
515
516
|
const { allowed, resetAt } = await this.rateLimiter.checkRateLimit(key, maxAttempts, windowMs);
|
|
516
517
|
if (!allowed) {
|
|
517
|
-
throw new step_up_exceptions_1.AuthRateLimitException('Too many sign-up requests. Please try again later.', retryAfterSeconds(resetAt));
|
|
518
|
+
throw new step_up_exceptions_1.AuthRateLimitException('Too many sign-up requests. Please try again later.', (0, rate_limit_helpers_1.retryAfterSeconds)(resetAt));
|
|
518
519
|
}
|
|
519
520
|
await this.rateLimiter.recordAttempt(key, windowMs);
|
|
520
521
|
}
|
|
@@ -654,7 +655,7 @@ let PasskeyService = PasskeyService_1 = class PasskeyService {
|
|
|
654
655
|
const { maxAttempts, windowMs } = this.options.passkey?.rateLimit ?? DEFAULT_RATE_LIMIT;
|
|
655
656
|
const { allowed, resetAt } = await this.rateLimiter.checkRateLimit(key, maxAttempts, windowMs);
|
|
656
657
|
if (!allowed) {
|
|
657
|
-
throw new step_up_exceptions_1.AuthRateLimitException('Too many passkey requests. Please try again later.', retryAfterSeconds(resetAt));
|
|
658
|
+
throw new step_up_exceptions_1.AuthRateLimitException('Too many passkey requests. Please try again later.', (0, rate_limit_helpers_1.retryAfterSeconds)(resetAt));
|
|
658
659
|
}
|
|
659
660
|
await this.rateLimiter.recordAttempt(key, windowMs);
|
|
660
661
|
}
|
|
@@ -736,22 +737,9 @@ exports.PasskeyService = PasskeyService = PasskeyService_1 = __decorate([
|
|
|
736
737
|
__metadata("design:paramtypes", [Object, Object, Object, Object, Object, Object, auth_service_1.AuthService,
|
|
737
738
|
step_up_token_service_1.StepUpTokenService, Object, Object, passkey_signup_token_service_1.PasskeySignupTokenService])
|
|
738
739
|
], PasskeyService);
|
|
739
|
-
function retryAfterSeconds(resetAt) {
|
|
740
|
-
return Math.max(1, Math.ceil((resetAt.getTime() - Date.now()) / 1000));
|
|
741
|
-
}
|
|
742
|
-
function scope(realm) {
|
|
743
|
-
return realm ? `${realm}:` : '';
|
|
744
|
-
}
|
|
745
740
|
function freshBytes(length) {
|
|
746
741
|
return new Uint8Array((0, crypto_1.randomBytes)(length));
|
|
747
742
|
}
|
|
748
|
-
function normaliseEmail(email) {
|
|
749
|
-
const normalised = typeof email === 'string' ? email.trim().toLowerCase() : '';
|
|
750
|
-
if (!/^[^\s@]+@[^\s@]+$/.test(normalised)) {
|
|
751
|
-
throw new common_1.BadRequestException('A valid email address is required');
|
|
752
|
-
}
|
|
753
|
-
return normalised;
|
|
754
|
-
}
|
|
755
743
|
function signupBinding(pending) {
|
|
756
744
|
return `signup:${pending.id}`;
|
|
757
745
|
}
|