@ofeklabs/horizon-auth 1.0.6 → 1.0.8

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.
@@ -1,9 +1,27 @@
1
1
  import { PrismaClient } from '@prisma/client';
2
2
  import { User } from '@prisma/client';
3
+ import { HorizonAuthConfig } from '../lib/horizon-auth-config.interface';
3
4
  export type SafeUser = Omit<User, 'passwordHash' | 'emailVerifyToken' | 'resetToken' | 'resetTokenExpiry'>;
4
5
  export declare class UsersService {
6
+ private readonly config;
5
7
  private readonly prisma;
6
- constructor(prisma: PrismaClient);
8
+ constructor(prisma: PrismaClient, config: HorizonAuthConfig);
9
+ private generateOtp;
10
+ generateEmailVerificationOtp(userId: string, otpLength: number, expiryMinutes: number): Promise<{
11
+ otp: string;
12
+ expiresAt: Date;
13
+ }>;
14
+ verifyEmailWithOtp(email: string, otp: string): Promise<User>;
15
+ resendVerification(email: string): Promise<{
16
+ otp?: string;
17
+ token?: string;
18
+ expiresAt: Date;
19
+ }>;
20
+ generatePasswordResetOtp(email: string, otpLength: number, expiryMinutes: number): Promise<{
21
+ otp: string;
22
+ expiresAt: Date;
23
+ }>;
24
+ verifyPasswordResetOtp(email: string, otp: string): Promise<User>;
7
25
  findByEmail(email: string): Promise<User | null>;
8
26
  findById(id: string): Promise<User | null>;
9
27
  create(email: string, passwordHash: string | null, tenantId?: string): Promise<User>;
@@ -18,7 +18,8 @@ const client_1 = require("@prisma/client");
18
18
  const crypto_1 = require("crypto");
19
19
  const constants_1 = require("../common/constants");
20
20
  let UsersService = class UsersService {
21
- constructor(prisma) {
21
+ constructor(prisma, config) {
22
+ this.config = config;
22
23
  this.prisma = prisma;
23
24
  console.log('🔍 UsersService constructor - prisma type:', prisma?.constructor?.name);
24
25
  console.log('🔍 UsersService constructor - prisma defined:', !!prisma);
@@ -29,6 +30,150 @@ let UsersService = class UsersService {
29
30
  `Please ensure your application's PrismaModule is @Global() and provides PRISMA_CLIENT_TOKEN before HorizonAuthModule.`);
30
31
  }
31
32
  }
33
+ generateOtp(length) {
34
+ const min = Math.pow(10, length - 1);
35
+ const max = Math.pow(10, length) - 1;
36
+ const otp = (0, crypto_1.randomInt)(min, max + 1);
37
+ return otp.toString().padStart(length, '0');
38
+ }
39
+ async generateEmailVerificationOtp(userId, otpLength, expiryMinutes) {
40
+ const otp = this.generateOtp(otpLength);
41
+ const now = new Date();
42
+ const expiresAt = new Date(now.getTime() + expiryMinutes * 60 * 1000);
43
+ const sentAt = now;
44
+ await this.prisma.user.update({
45
+ where: { id: userId },
46
+ data: {
47
+ emailVerificationOtp: otp,
48
+ emailVerificationExpiresAt: expiresAt,
49
+ emailVerificationSentAt: sentAt,
50
+ emailVerificationAttempts: 0,
51
+ },
52
+ });
53
+ return { otp, expiresAt };
54
+ }
55
+ async verifyEmailWithOtp(email, otp) {
56
+ const user = await this.findByEmail(email);
57
+ if (!user) {
58
+ throw new common_1.NotFoundException('User not found');
59
+ }
60
+ if (!user.emailVerificationOtp) {
61
+ throw new common_1.NotFoundException('No pending email verification found');
62
+ }
63
+ if (!user.emailVerificationExpiresAt || user.emailVerificationExpiresAt < new Date()) {
64
+ throw new common_1.BadRequestException('Verification code has expired');
65
+ }
66
+ if (user.emailVerificationAttempts >= 5) {
67
+ throw new common_1.BadRequestException('Too many failed attempts. Please request a new verification code');
68
+ }
69
+ if (user.emailVerificationOtp !== otp) {
70
+ await this.prisma.user.update({
71
+ where: { id: user.id },
72
+ data: {
73
+ emailVerificationAttempts: user.emailVerificationAttempts + 1,
74
+ },
75
+ });
76
+ throw new common_1.BadRequestException('Invalid verification code');
77
+ }
78
+ return this.prisma.user.update({
79
+ where: { id: user.id },
80
+ data: {
81
+ emailVerified: true,
82
+ emailVerificationOtp: null,
83
+ emailVerificationExpiresAt: null,
84
+ emailVerificationSentAt: null,
85
+ emailVerificationAttempts: 0,
86
+ },
87
+ });
88
+ }
89
+ async resendVerification(email) {
90
+ const user = await this.findByEmail(email);
91
+ if (!user) {
92
+ throw new common_1.NotFoundException('User not found');
93
+ }
94
+ if (user.emailVerificationSentAt) {
95
+ const timeSinceLastSend = Date.now() - user.emailVerificationSentAt.getTime();
96
+ const rateLimitMs = 60 * 1000;
97
+ if (timeSinceLastSend < rateLimitMs) {
98
+ throw new common_1.BadRequestException('Please wait before requesting another verification code');
99
+ }
100
+ }
101
+ const verificationConfig = this.config.emailVerification || { method: 'otp' };
102
+ const method = verificationConfig.method || 'otp';
103
+ const otpLength = verificationConfig.otpLength || 6;
104
+ const otpExpiry = verificationConfig.otpExpiry || 10;
105
+ const tokenExpiry = verificationConfig.tokenExpiry || 24;
106
+ const now = new Date();
107
+ let otp;
108
+ let token;
109
+ let expiresAt;
110
+ const updateData = {
111
+ emailVerificationSentAt: now,
112
+ };
113
+ if (method === 'otp' || method === 'both') {
114
+ otp = this.generateOtp(otpLength);
115
+ expiresAt = new Date(now.getTime() + otpExpiry * 60 * 1000);
116
+ updateData.emailVerificationOtp = otp;
117
+ updateData.emailVerificationExpiresAt = expiresAt;
118
+ updateData.emailVerificationAttempts = 0;
119
+ }
120
+ if (method === 'magic-link' || method === 'both') {
121
+ token = (0, crypto_1.randomUUID)();
122
+ expiresAt = new Date(now.getTime() + tokenExpiry * 60 * 60 * 1000);
123
+ updateData.emailVerifyToken = token;
124
+ }
125
+ if (!expiresAt) {
126
+ expiresAt = new Date(now.getTime() + otpExpiry * 60 * 1000);
127
+ }
128
+ await this.prisma.user.update({
129
+ where: { id: user.id },
130
+ data: updateData,
131
+ });
132
+ return { otp, token, expiresAt };
133
+ }
134
+ async generatePasswordResetOtp(email, otpLength, expiryMinutes) {
135
+ const user = await this.findByEmail(email);
136
+ if (!user) {
137
+ throw new common_1.NotFoundException('If the email exists, a reset code will be sent');
138
+ }
139
+ const otp = this.generateOtp(otpLength);
140
+ const now = new Date();
141
+ const expiresAt = new Date(now.getTime() + expiryMinutes * 60 * 1000);
142
+ await this.prisma.user.update({
143
+ where: { id: user.id },
144
+ data: {
145
+ passwordResetOtp: otp,
146
+ passwordResetOtpExpiresAt: expiresAt,
147
+ passwordResetOtpAttempts: 0,
148
+ },
149
+ });
150
+ return { otp, expiresAt };
151
+ }
152
+ async verifyPasswordResetOtp(email, otp) {
153
+ const user = await this.findByEmail(email);
154
+ if (!user) {
155
+ throw new common_1.NotFoundException('User not found');
156
+ }
157
+ if (!user.passwordResetOtp) {
158
+ throw new common_1.NotFoundException('No pending password reset found');
159
+ }
160
+ if (!user.passwordResetOtpExpiresAt || user.passwordResetOtpExpiresAt < new Date()) {
161
+ throw new common_1.BadRequestException('Reset code has expired');
162
+ }
163
+ if (user.passwordResetOtpAttempts >= 5) {
164
+ throw new common_1.BadRequestException('Too many failed attempts. Please request a new reset code');
165
+ }
166
+ if (user.passwordResetOtp !== otp) {
167
+ await this.prisma.user.update({
168
+ where: { id: user.id },
169
+ data: {
170
+ passwordResetOtpAttempts: user.passwordResetOtpAttempts + 1,
171
+ },
172
+ });
173
+ throw new common_1.BadRequestException('Invalid reset code');
174
+ }
175
+ return user;
176
+ }
32
177
  async findByEmail(email) {
33
178
  console.log('🔍 findByEmail called - this.prisma defined:', !!this.prisma);
34
179
  console.log('🔍 findByEmail called - this.prisma type:', this.prisma?.constructor?.name);
@@ -51,14 +196,31 @@ let UsersService = class UsersService {
51
196
  if (existingUser) {
52
197
  throw new common_1.ConflictException('User with this email already exists');
53
198
  }
199
+ const verificationConfig = this.config.emailVerification || { method: 'otp' };
200
+ const method = verificationConfig.method || 'otp';
201
+ const otpLength = verificationConfig.otpLength || 6;
202
+ const otpExpiry = verificationConfig.otpExpiry || 10;
203
+ const tokenExpiry = verificationConfig.tokenExpiry || 24;
204
+ const now = new Date();
205
+ const createData = {
206
+ email,
207
+ passwordHash,
208
+ tenantId: tenantId || 'default',
209
+ roles: ['user'],
210
+ };
211
+ if (method === 'otp' || method === 'both') {
212
+ const otp = this.generateOtp(otpLength);
213
+ const expiresAt = new Date(now.getTime() + otpExpiry * 60 * 1000);
214
+ createData.emailVerificationOtp = otp;
215
+ createData.emailVerificationExpiresAt = expiresAt;
216
+ createData.emailVerificationSentAt = now;
217
+ createData.emailVerificationAttempts = 0;
218
+ }
219
+ if (method === 'magic-link' || method === 'both') {
220
+ createData.emailVerifyToken = (0, crypto_1.randomUUID)();
221
+ }
54
222
  return this.prisma.user.create({
55
- data: {
56
- email,
57
- passwordHash,
58
- emailVerifyToken: (0, crypto_1.randomUUID)(),
59
- tenantId: tenantId || 'default',
60
- roles: ['user'],
61
- },
223
+ data: createData,
62
224
  });
63
225
  }
64
226
  async update(id, data) {
@@ -123,6 +285,7 @@ exports.UsersService = UsersService;
123
285
  exports.UsersService = UsersService = __decorate([
124
286
  (0, common_1.Injectable)(),
125
287
  __param(0, (0, common_1.Inject)(constants_1.PRISMA_CLIENT_TOKEN)),
126
- __metadata("design:paramtypes", [client_1.PrismaClient])
288
+ __param(1, (0, common_1.Inject)('HORIZON_AUTH_CONFIG')),
289
+ __metadata("design:paramtypes", [client_1.PrismaClient, Object])
127
290
  ], UsersService);
128
291
  //# sourceMappingURL=users.service.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"users.service.js","sourceRoot":"","sources":["../../src/users/users.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"users.service.js","sourceRoot":"","sources":["../../src/users/users.service.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ofeklabs/horizon-auth",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Production-ready NestJS authentication module with 2FA, device management, push notifications, and account management",
5
5
  "author": "Ofek Itzhaki",
6
6
  "license": "MIT",
@@ -34,6 +34,14 @@
34
34
  "reflect-metadata": "^0.1.13",
35
35
  "rxjs": "^7.8.0"
36
36
  },
37
+ "peerDependenciesMeta": {
38
+ "resend": {
39
+ "optional": true
40
+ },
41
+ "@sendgrid/mail": {
42
+ "optional": true
43
+ }
44
+ },
37
45
  "dependencies": {
38
46
  "@nestjs/jwt": "^10.2.0",
39
47
  "@nestjs/throttler": "^5.1.0",
@@ -0,0 +1,14 @@
1
+ -- Migration: Add OTP fields for dual email verification support
2
+ -- This migration adds OTP fields for both email verification and password reset
3
+ -- while maintaining backward compatibility with existing magic link fields.
4
+
5
+ -- Add email verification OTP fields
6
+ ALTER TABLE "users" ADD COLUMN "emailVerificationOtp" TEXT;
7
+ ALTER TABLE "users" ADD COLUMN "emailVerificationSentAt" TIMESTAMP(3);
8
+ ALTER TABLE "users" ADD COLUMN "emailVerificationExpiresAt" TIMESTAMP(3);
9
+ ALTER TABLE "users" ADD COLUMN "emailVerificationAttempts" INTEGER NOT NULL DEFAULT 0;
10
+
11
+ -- Add password reset OTP fields
12
+ ALTER TABLE "users" ADD COLUMN "passwordResetOtp" TEXT;
13
+ ALTER TABLE "users" ADD COLUMN "passwordResetOtpExpiresAt" TIMESTAMP(3);
14
+ ALTER TABLE "users" ADD COLUMN "passwordResetOtpAttempts" INTEGER NOT NULL DEFAULT 0;
@@ -11,26 +11,42 @@ datasource db {
11
11
  }
12
12
 
13
13
  model User {
14
- id String @id @default(cuid())
15
- email String @unique
16
- fullName String?
17
- passwordHash String?
18
- emailVerified Boolean @default(false)
19
- emailVerifyToken String? @unique
20
- resetToken String? @unique
21
- resetTokenExpiry DateTime?
22
- tenantId String @default("default")
23
- roles String[] @default(["user"])
24
- isActive Boolean @default(true)
25
- deactivationReason String?
26
- refreshTokens RefreshToken[]
27
- socialAccounts SocialAccount[]
28
- devices Device[]
29
- pushTokens PushToken[]
30
- twoFactorAuth TwoFactorAuth?
31
- backupCodes BackupCode[]
32
- createdAt DateTime @default(now())
33
- updatedAt DateTime @updatedAt
14
+ id String @id @default(cuid())
15
+ email String @unique
16
+ fullName String?
17
+ passwordHash String?
18
+ emailVerified Boolean @default(false)
19
+
20
+ // Email verification - OTP fields
21
+ emailVerificationOtp String?
22
+ emailVerificationSentAt DateTime?
23
+ emailVerificationExpiresAt DateTime?
24
+ emailVerificationAttempts Int @default(0)
25
+
26
+ // Email verification - Magic link (existing)
27
+ emailVerifyToken String? @unique
28
+
29
+ // Password reset - OTP fields
30
+ passwordResetOtp String?
31
+ passwordResetOtpExpiresAt DateTime?
32
+ passwordResetOtpAttempts Int @default(0)
33
+
34
+ // Password reset - Magic link (existing)
35
+ resetToken String? @unique
36
+ resetTokenExpiry DateTime?
37
+
38
+ tenantId String @default("default")
39
+ roles String[] @default(["user"])
40
+ isActive Boolean @default(true)
41
+ deactivationReason String?
42
+ refreshTokens RefreshToken[]
43
+ socialAccounts SocialAccount[]
44
+ devices Device[]
45
+ pushTokens PushToken[]
46
+ twoFactorAuth TwoFactorAuth?
47
+ backupCodes BackupCode[]
48
+ createdAt DateTime @default(now())
49
+ updatedAt DateTime @updatedAt
34
50
 
35
51
  @@index([email])
36
52
  @@index([tenantId])