@dax-crafta/auth 2.1.2 → 2.1.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dax-crafta/auth",
3
- "version": "2.1.2",
3
+ "version": "2.1.4",
4
4
  "description": "A powerful, flexible, and secure authentication plugin for the Crafta framework. Supports JWT, social login, 2FA, RBAC, audit logging, and enterprise-grade security features.",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -89,10 +89,10 @@ userSchema.methods.comparePassword = async function (candidate) {
89
89
  return bcrypt.compare(candidate, this.password);
90
90
  };
91
91
 
92
- userSchema.methods.recordPasswordHistory = async function () {
92
+ userSchema.methods.recordPasswordHistory = async function (previousPasswordHash) {
93
93
  this.passwordHistory = this.passwordHistory || [];
94
94
  this.passwordHistory.push({
95
- hash: this.password,
95
+ hash: previousPasswordHash || this.password,
96
96
  changedAt: new Date()
97
97
  });
98
98
 
@@ -204,9 +204,10 @@ class AuthService {
204
204
  throw new ApiError('Cannot reuse previous passwords', 400);
205
205
  }
206
206
 
207
+ const previousPasswordHash = user.password;
207
208
  user.password = newPassword;
208
209
 
209
- await user.recordPasswordHistory(); // 🔥 add
210
+ await user.recordPasswordHistory(previousPasswordHash);
210
211
  await user.revokeAllRefreshTokens(); // session invalidate
211
212
  user.passwordResetToken = undefined;
212
213
  user.passwordResetExpires = undefined;
@@ -341,6 +342,43 @@ class AuthService {
341
342
  return true;
342
343
  }
343
344
 
345
+ async handleSocialLogin(provider, profile) {
346
+ if (!profile) {
347
+ throw new ApiError('Social profile is required', 400);
348
+ }
349
+
350
+ const primaryEmail = profile.emails?.[0]?.value;
351
+ if (!primaryEmail) {
352
+ throw new ApiError('Social provider did not return an email', 400);
353
+ }
354
+
355
+ let user = await User.findOne({ email: primaryEmail });
356
+
357
+ if (!user) {
358
+ user = new User({
359
+ email: primaryEmail,
360
+ password: this.generateSecureToken(),
361
+ isVerified: true,
362
+ customFields: {
363
+ socialProvider: provider,
364
+ socialId: profile.id,
365
+ name: profile.displayName
366
+ }
367
+ });
368
+ await user.save();
369
+ } else if (profile.displayName) {
370
+ user.customFields = {
371
+ ...(user.customFields || {}),
372
+ socialProvider: provider,
373
+ socialId: profile.id,
374
+ name: profile.displayName
375
+ };
376
+ await user.save();
377
+ }
378
+
379
+ return user;
380
+ }
381
+
344
382
 
345
383
 
346
384
  /* ---------------------------------------------
@@ -57,7 +57,8 @@ class EmailService {
57
57
  }
58
58
 
59
59
  async sendVerificationEmail(user, token) {
60
- const url = `${this.config.baseUrl}/verify-email?token=${token}`;
60
+ const verifyPath = this.config.routes?.verify || '/verify';
61
+ const url = `${this.config.baseUrl}${verifyPath}?token=${token}`;
61
62
 
62
63
  const html = this.loadTemplate("email-verification", {
63
64
  name: user.name || user.email,
@@ -73,7 +74,8 @@ class EmailService {
73
74
  }
74
75
 
75
76
  async sendPasswordResetEmail(user, token) {
76
- const url = `${this.config.baseUrl}/reset-password?token=${token}`;
77
+ const resetPath = this.config.routes?.resetPassword || '/reset-password';
78
+ const url = `${this.config.baseUrl}${resetPath}?token=${token}`;
77
79
 
78
80
  const html = this.loadTemplate("password-reset", {
79
81
  name: user.name || user.email,