nuxt-users 1.11.0 → 1.12.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 (38) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/cli.mjs +2 -3
  3. package/dist/module.d.mts +1 -1
  4. package/dist/module.d.ts +1 -1
  5. package/dist/module.json +1 -1
  6. package/dist/module.mjs +30 -9
  7. package/dist/runtime/assets/nuxt-users.css +1 -0
  8. package/dist/runtime/components/NUsersList.vue +136 -0
  9. package/dist/runtime/components/NUsersList.vue.d.ts +74 -0
  10. package/dist/runtime/components/{LoginForm.vue → NUsersLoginForm.vue} +20 -23
  11. package/dist/runtime/components/{LoginForm.vue.d.ts → NUsersLoginForm.vue.d.ts} +5 -9
  12. package/dist/runtime/components/{LogoutLink.vue → NUsersLogoutLink.vue} +2 -6
  13. package/dist/runtime/components/{PasswordStrengthIndicator.vue → NUsersPasswordStrengthIndicator.vue} +18 -22
  14. package/dist/runtime/components/{ProfileInfo.vue → NUsersProfileInfo.vue} +5 -7
  15. package/dist/runtime/components/{ResetPasswordForm.vue → NUsersResetPasswordForm.vue} +22 -26
  16. package/dist/runtime/components/{ResetPasswordForm.vue.d.ts → NUsersResetPasswordForm.vue.d.ts} +3 -6
  17. package/dist/runtime/components/NUsersUserCard.vue +93 -0
  18. package/dist/runtime/components/NUsersUserCard.vue.d.ts +33 -0
  19. package/dist/runtime/components/NUsersUserForm.vue +141 -0
  20. package/dist/runtime/components/NUsersUserForm.vue.d.ts +12 -0
  21. package/dist/runtime/composables/useAuthentication.d.ts +2 -0
  22. package/dist/runtime/composables/usePasswordValidation.d.ts +2 -2
  23. package/dist/runtime/server/api/nuxt-users/index.get.d.ts +20 -0
  24. package/dist/runtime/server/api/nuxt-users/index.get.js +58 -0
  25. package/dist/runtime/server/api/nuxt-users/session/index.post.d.ts +1 -0
  26. package/dist/runtime/server/middleware/authorization.server.js +23 -8
  27. package/dist/runtime/server/utils/user.js +8 -5
  28. package/dist/shared/{nuxt-users.C7T1DKBV.d.mts → nuxt-users.B5ttEpIO.d.mts} +1 -0
  29. package/dist/shared/{nuxt-users.C7T1DKBV.d.ts → nuxt-users.B5ttEpIO.d.ts} +1 -0
  30. package/dist/utils.d.mts +1 -2
  31. package/dist/utils.d.ts +1 -2
  32. package/dist/utils.mjs +162 -2
  33. package/package.json +1 -1
  34. package/dist/runtime/assets/colors.css +0 -1
  35. package/dist/shared/nuxt-users.BnOQs2LI.mjs +0 -162
  36. package/dist/runtime/components/{LogoutLink.vue.d.ts → NUsersLogoutLink.vue.d.ts} +4 -4
  37. /package/dist/runtime/components/{PasswordStrengthIndicator.vue.d.ts → NUsersPasswordStrengthIndicator.vue.d.ts} +0 -0
  38. /package/dist/runtime/components/{ProfileInfo.vue.d.ts → NUsersProfileInfo.vue.d.ts} +0 -0
@@ -0,0 +1,58 @@
1
+ import { createError, defineEventHandler, getQuery } from "h3";
2
+ import { useRuntimeConfig } from "#imports";
3
+ import { useDb } from "../../utils/db.js";
4
+ import { getLastLoginTime } from "../../utils/user.js";
5
+ export default defineEventHandler(async (event) => {
6
+ const { nuxtUsers } = useRuntimeConfig();
7
+ const options = nuxtUsers;
8
+ const db = await useDb(options);
9
+ const usersTable = options.tables.users;
10
+ const query = getQuery(event);
11
+ const page = Number(query.page) || 1;
12
+ const limit = Number(query.limit) || 10;
13
+ const offset = (page - 1) * limit;
14
+ if (page < 1 || limit < 1 || limit > 100) {
15
+ throw createError({
16
+ statusCode: 400,
17
+ statusMessage: "Invalid pagination parameters. Page must be >= 1, limit must be between 1 and 100."
18
+ });
19
+ }
20
+ try {
21
+ const countResult = await db.sql`SELECT COUNT(*) as total FROM {${usersTable}}`;
22
+ const total = countResult.rows[0].total;
23
+ const usersResult = await db.sql`
24
+ SELECT id, email, name, role, created_at, updated_at
25
+ FROM {${usersTable}}
26
+ ORDER BY name ASC
27
+ LIMIT ${limit} OFFSET ${offset}
28
+ `;
29
+ const users = await Promise.all(usersResult.rows.map(async (user) => {
30
+ const lastLoginTime = await getLastLoginTime(user.id, options);
31
+ return {
32
+ id: user.id,
33
+ email: user.email,
34
+ name: user.name,
35
+ role: user.role,
36
+ created_at: user.created_at instanceof Date ? user.created_at.toISOString() : user.created_at,
37
+ updated_at: user.updated_at instanceof Date ? user.updated_at.toISOString() : user.updated_at,
38
+ last_login_at: lastLoginTime
39
+ };
40
+ }));
41
+ return {
42
+ users,
43
+ pagination: {
44
+ page,
45
+ limit,
46
+ total,
47
+ totalPages: Math.ceil(total / limit),
48
+ hasNext: page * limit < total,
49
+ hasPrev: page > 1
50
+ }
51
+ };
52
+ } catch (error) {
53
+ throw createError({
54
+ statusCode: 500,
55
+ statusMessage: `Error fetching users: ${error instanceof Error ? error.message : String(error)}`
56
+ });
57
+ }
58
+ });
@@ -6,6 +6,7 @@ declare const _default: import("h3").EventHandler<import("h3").EventHandlerReque
6
6
  role: string;
7
7
  created_at: string;
8
8
  updated_at: string;
9
+ last_login_at?: string;
9
10
  };
10
11
  }>>;
11
12
  export default _default;
@@ -1,4 +1,4 @@
1
- import { defineEventHandler, getCookie, sendRedirect } from "h3";
1
+ import { defineEventHandler, getCookie, createError } from "h3";
2
2
  import { useRuntimeConfig } from "#imports";
3
3
  import { getCurrentUserFromToken } from "../utils/index.js";
4
4
  import { hasPermission, isWhitelisted } from "../../utils/permissions.js";
@@ -12,7 +12,7 @@ export default defineEventHandler(async (event) => {
12
12
  return;
13
13
  }
14
14
  if (NO_AUTH_PATHS.includes(event.path)) {
15
- console.log("[Nuxt Users] server.middleware.auth.global: /login");
15
+ console.log(`[Nuxt Users] server.middleware.auth.global: NO_AUTH_PATH: ${event.path}`);
16
16
  return;
17
17
  }
18
18
  const openApiPaths = NO_AUTH_API_PATHS.map((path) => `${base}${path}`);
@@ -25,17 +25,32 @@ export default defineEventHandler(async (event) => {
25
25
  }
26
26
  const token = getCookie(event, "auth_token");
27
27
  if (!token) {
28
- console.log(`[Nuxt Users] server.middleware.auth.global: ${event.path} No token found redirecting to login`);
29
- return sendRedirect(event, "/login");
28
+ if (event.path.startsWith("/api/")) {
29
+ console.log(`[Nuxt Users] server.middleware.auth.global: ${event.path} No token found - API request rejected`);
30
+ throw createError({ statusCode: 401, statusMessage: "Unauthorized" });
31
+ } else {
32
+ console.log(`[Nuxt Users] server.middleware.auth.global: ${event.path} No token found - letting client handle page redirect`);
33
+ return;
34
+ }
30
35
  }
31
36
  const user = await getCurrentUserFromToken(token, options);
32
37
  if (!user) {
33
- console.log(`[Nuxt Users] server.middleware.auth.global: ${event.path} No user found redirecting to login`);
34
- return sendRedirect(event, "/login");
38
+ if (event.path.startsWith("/api/")) {
39
+ console.log(`[Nuxt Users] server.middleware.auth.global: ${event.path} Invalid token - API request rejected`);
40
+ throw createError({ statusCode: 401, statusMessage: "Unauthorized" });
41
+ } else {
42
+ console.log(`[Nuxt Users] server.middleware.auth.global: ${event.path} Invalid token - letting client handle page redirect`);
43
+ return;
44
+ }
35
45
  }
36
46
  if (!hasPermission(user.role, event.path, options.auth.permissions)) {
37
- console.log(`[Nuxt Users] server.middleware.auth.global: ${event.path} User ${user.id} with role ${user.role} denied access`);
38
- return sendRedirect(event, "/login");
47
+ if (event.path.startsWith("/api/")) {
48
+ console.log(`[Nuxt Users] server.middleware.auth.global: ${event.path} User ${user.id} with role ${user.role} denied access - API request rejected`);
49
+ throw createError({ statusCode: 403, statusMessage: "Forbidden" });
50
+ } else {
51
+ console.log(`[Nuxt Users] server.middleware.auth.global: ${event.path} User ${user.id} with role ${user.role} denied access - letting client handle page redirect`);
52
+ return;
53
+ }
39
54
  }
40
55
  console.log(`[Nuxt Users] server.middleware.auth.global: Authenticated request to ${event.path} for ${user.id} with role ${user.role}`);
41
56
  return;
@@ -69,21 +69,24 @@ export const findUserById = async (id, options, withPass = false) => {
69
69
  export const updateUser = async (id, userData, options) => {
70
70
  const db = await useDb(options);
71
71
  const usersTable = options.tables.users;
72
- const currentUser = await findUserById(id, options, true);
72
+ const currentUser = await findUserById(id, options);
73
73
  if (!currentUser) {
74
74
  throw new Error("User not found.");
75
75
  }
76
76
  const fieldsToUpdate = { ...userData };
77
77
  delete fieldsToUpdate.id;
78
+ delete fieldsToUpdate.created_at;
79
+ delete fieldsToUpdate.updated_at;
80
+ delete fieldsToUpdate.last_login_at;
78
81
  delete fieldsToUpdate.password;
79
82
  if (Object.keys(fieldsToUpdate).length === 0) {
80
- const { password, ...user } = currentUser;
81
- return user;
83
+ return currentUser;
82
84
  }
83
- for (const [key, value] of Object.entries(fieldsToUpdate)) {
85
+ const dirtyFields = Object.keys(fieldsToUpdate).filter((key) => currentUser[key] != fieldsToUpdate[key]);
86
+ for (const key of dirtyFields) {
84
87
  await db.sql`
85
88
  UPDATE {${usersTable}}
86
- SET ${key} = ${value}, updated_at = CURRENT_TIMESTAMP
89
+ SET {${key}} = ${fieldsToUpdate[key]}, updated_at = CURRENT_TIMESTAMP
87
90
  WHERE id = ${id}
88
91
  `;
89
92
  }
@@ -144,6 +144,7 @@ interface User {
144
144
  role: string;
145
145
  created_at: string;
146
146
  updated_at: string;
147
+ last_login_at?: string;
147
148
  }
148
149
  type UserWithoutPassword = Omit<User, 'password'>;
149
150
  interface PersonalAccessToken {
@@ -144,6 +144,7 @@ interface User {
144
144
  role: string;
145
145
  created_at: string;
146
146
  updated_at: string;
147
+ last_login_at?: string;
147
148
  }
148
149
  type UserWithoutPassword = Omit<User, 'password'>;
149
150
  interface PersonalAccessToken {
package/dist/utils.d.mts CHANGED
@@ -1,5 +1,4 @@
1
- export { L as LoginFormData, M as ModuleOptions, b as PasswordResetToken, P as PersonalAccessToken, U as User, a as UserWithoutPassword } from './shared/nuxt-users.C7T1DKBV.mjs';
2
- export { findUserByEmail, getCurrentUserFromToken, getLastLoginTime } from '../dist/runtime/server/utils/user.js';
1
+ export { L as LoginFormData, M as ModuleOptions, b as PasswordResetToken, P as PersonalAccessToken, U as User, a as UserWithoutPassword } from './shared/nuxt-users.B5ttEpIO.mjs';
3
2
 
4
3
  interface PasswordValidationResult {
5
4
  isValid: boolean;
package/dist/utils.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- export { L as LoginFormData, M as ModuleOptions, b as PasswordResetToken, P as PersonalAccessToken, U as User, a as UserWithoutPassword } from './shared/nuxt-users.C7T1DKBV.js';
2
- export { findUserByEmail, getCurrentUserFromToken, getLastLoginTime } from '../dist/runtime/server/utils/user.js';
1
+ export { L as LoginFormData, M as ModuleOptions, b as PasswordResetToken, P as PersonalAccessToken, U as User, a as UserWithoutPassword } from './shared/nuxt-users.B5ttEpIO.js';
3
2
 
4
3
  interface PasswordValidationResult {
5
4
  isValid: boolean;
package/dist/utils.mjs CHANGED
@@ -1,2 +1,162 @@
1
- export { a as getPasswordStrengthColor, b as getPasswordStrengthText, g as getPasswordValidationOptions, v as validatePassword } from './shared/nuxt-users.BnOQs2LI.mjs';
2
- export { findUserByEmail, getCurrentUserFromToken, getLastLoginTime } from '../dist/runtime/server/utils/user.js';
1
+ const DEFAULT_OPTIONS = {
2
+ minLength: 8,
3
+ requireUppercase: true,
4
+ requireLowercase: true,
5
+ requireNumbers: true,
6
+ requireSpecialChars: true,
7
+ preventCommonPasswords: true
8
+ };
9
+ const getPasswordValidationOptions = (moduleOptions) => {
10
+ if (!moduleOptions?.passwordValidation) {
11
+ return DEFAULT_OPTIONS;
12
+ }
13
+ return {
14
+ ...DEFAULT_OPTIONS,
15
+ ...moduleOptions.passwordValidation
16
+ };
17
+ };
18
+ const COMMON_PASSWORDS = [
19
+ "password",
20
+ "123456",
21
+ "123456789",
22
+ "qwerty",
23
+ "abc123",
24
+ "password123",
25
+ "admin",
26
+ "letmein",
27
+ "welcome",
28
+ "monkey",
29
+ "dragon",
30
+ "master",
31
+ "hello",
32
+ "freedom",
33
+ "whatever",
34
+ "qazwsx",
35
+ "trustno1",
36
+ "jordan",
37
+ "harley",
38
+ "ranger",
39
+ "buster",
40
+ "thomas",
41
+ "tigger",
42
+ "robert",
43
+ "soccer",
44
+ "batman",
45
+ "test",
46
+ "pass",
47
+ "user",
48
+ "guest",
49
+ "login",
50
+ "secret",
51
+ "god",
52
+ "love",
53
+ "sex",
54
+ "money",
55
+ "password1",
56
+ "12345678",
57
+ "qwerty123",
58
+ "admin123",
59
+ "password!",
60
+ "password1!",
61
+ "password123",
62
+ "password123!"
63
+ ];
64
+ const validatePassword = (password, options = {}) => {
65
+ const config = { ...DEFAULT_OPTIONS, ...options };
66
+ const errors = [];
67
+ const hints = [];
68
+ let score = 0;
69
+ if (password.length < config.minLength) {
70
+ errors.push(`Password must be at least ${config.minLength} characters long`);
71
+ hints.push(`Use at least ${config.minLength} characters`);
72
+ } else {
73
+ score += 20;
74
+ if (password.length < 12) {
75
+ hints.push("Use 12 or more characters for extra security");
76
+ }
77
+ }
78
+ if (config.requireUppercase && !/[A-Z]/.test(password)) {
79
+ errors.push("Password must contain at least one uppercase letter");
80
+ hints.push("Add an uppercase letter (A-Z)");
81
+ } else if (/[A-Z]/.test(password)) {
82
+ score += 15;
83
+ }
84
+ if (config.requireLowercase && !/[a-z]/.test(password)) {
85
+ errors.push("Password must contain at least one lowercase letter");
86
+ hints.push("Add a lowercase letter (a-z)");
87
+ } else if (/[a-z]/.test(password)) {
88
+ score += 15;
89
+ }
90
+ if (config.requireNumbers && !/\d/.test(password)) {
91
+ errors.push("Password must contain at least one number");
92
+ hints.push("Add a number (0-9)");
93
+ } else if (/\d/.test(password)) {
94
+ score += 15;
95
+ }
96
+ if (config.requireSpecialChars && !/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(password)) {
97
+ errors.push("Password must contain at least one special character");
98
+ hints.push("Add a special character (e.g. !@#$%)");
99
+ } else if (/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(password)) {
100
+ score += 15;
101
+ }
102
+ if (config.preventCommonPasswords && COMMON_PASSWORDS.includes(password.toLowerCase())) {
103
+ errors.push("Password is too common. Please choose a more unique password");
104
+ hints.push("Avoid common passwords or names");
105
+ }
106
+ if (password.length >= 12) {
107
+ score += 10;
108
+ } else if (password.length >= 10) {
109
+ score += 5;
110
+ }
111
+ const hasUppercase = /[A-Z]/.test(password);
112
+ const hasLowercase = /[a-z]/.test(password);
113
+ const hasNumbers = /\d/.test(password);
114
+ const hasSpecial = /[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(password);
115
+ const complexityTypes = [hasUppercase, hasLowercase, hasNumbers, hasSpecial].filter(Boolean).length;
116
+ if (complexityTypes >= 4) {
117
+ score += 10;
118
+ } else if (complexityTypes >= 3) {
119
+ score += 5;
120
+ hints.push("Use a mix of uppercase, lowercase, numbers, and special characters");
121
+ }
122
+ let strength = "weak";
123
+ if (score >= 80) {
124
+ strength = "strong";
125
+ } else if (score >= 60) {
126
+ strength = "medium";
127
+ }
128
+ return {
129
+ isValid: errors.length === 0,
130
+ errors,
131
+ strength,
132
+ score: Math.min(score, 100),
133
+ hints: Array.from(new Set(hints))
134
+ // deduplicate
135
+ };
136
+ };
137
+ const getPasswordStrengthColor = (strength) => {
138
+ switch (strength) {
139
+ case "weak":
140
+ return "#dc3545";
141
+ case "medium":
142
+ return "#ffc107";
143
+ case "strong":
144
+ return "#28a745";
145
+ default:
146
+ return "#6c757d";
147
+ }
148
+ };
149
+ const getPasswordStrengthText = (strength) => {
150
+ switch (strength) {
151
+ case "weak":
152
+ return "Weak";
153
+ case "medium":
154
+ return "Medium";
155
+ case "strong":
156
+ return "Strong";
157
+ default:
158
+ return "Unknown";
159
+ }
160
+ };
161
+
162
+ export { getPasswordStrengthColor, getPasswordStrengthText, getPasswordValidationOptions, validatePassword };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-users",
3
- "version": "1.11.0",
3
+ "version": "1.12.0",
4
4
  "description": "A comprehensive user management module for Nuxt 3 and Nuxt 4 applications with authentication, authorization, database support, and CLI tools",
5
5
  "keywords": [
6
6
  "nuxt",
@@ -1 +0,0 @@
1
- :root{--color-primary:#60a5fa;--color-primary-dark:#3b82f6;--color-primary-light:#93c5fd;--color-secondary:#10b981;--color-secondary-dark:#059669;--color-secondary-light:#34d399;--color-white:#000;--color-black:#fff;--color-gray-50:#111827;--color-gray-100:#1f2937;--color-gray-200:#374151;--color-gray-300:#4b5563;--color-gray-400:#6b7280;--color-gray-500:#9ca3af;--color-gray-600:#d1d5db;--color-gray-700:#e5e7eb;--color-gray-800:#f3f4f6;--color-gray-900:#f9fafb;--color-success:#10b981;--color-success-light:#064e3b;--color-warning:#fbbf24;--color-warning-light:#451a03;--color-warning-text:#fef3c7;--color-error:#ef4444;--color-error-light:#450a0a;--color-error-border:#7f1d1d;--color-error-alt:#f87171;--color-border:#374151;--color-border-light:#4b5563;--color-border-dark:#6b7280;--color-bg-primary:#111827;--color-bg-secondary:#1f2937;--color-bg-tertiary:#374151}@media (prefers-color-scheme:light){.light,:root{--color-primary:#3b82f6;--color-primary-dark:#2563eb;--color-primary-light:#60a5fa;--color-secondary:#059669;--color-secondary-dark:#047857;--color-secondary-light:#10b981;--color-white:#fff;--color-black:#000;--color-gray-50:#f9fafb;--color-gray-100:#f3f4f6;--color-gray-200:#e5e7eb;--color-gray-300:#d1d5db;--color-gray-400:#9ca3af;--color-gray-500:#6b7280;--color-gray-600:#4b5563;--color-gray-700:#374151;--color-gray-800:#1f2937;--color-gray-900:#111827;--color-success:#059669;--color-success-light:#f0fdf4;--color-warning:#f59e0b;--color-warning-light:#fef3c7;--color-warning-text:#92400e;--color-error:#dc2626;--color-error-light:#fef2f2;--color-error-border:#fecaca;--color-error-alt:#db5050;--color-border:#e5e7eb;--color-border-light:#d1d5db;--color-border-dark:#ccc;--color-bg-primary:#fff;--color-bg-secondary:#f9fafb;--color-bg-tertiary:#f3f4f6}}
@@ -1,162 +0,0 @@
1
- const DEFAULT_OPTIONS = {
2
- minLength: 8,
3
- requireUppercase: true,
4
- requireLowercase: true,
5
- requireNumbers: true,
6
- requireSpecialChars: true,
7
- preventCommonPasswords: true
8
- };
9
- const getPasswordValidationOptions = (moduleOptions) => {
10
- if (!moduleOptions?.passwordValidation) {
11
- return DEFAULT_OPTIONS;
12
- }
13
- return {
14
- ...DEFAULT_OPTIONS,
15
- ...moduleOptions.passwordValidation
16
- };
17
- };
18
- const COMMON_PASSWORDS = [
19
- "password",
20
- "123456",
21
- "123456789",
22
- "qwerty",
23
- "abc123",
24
- "password123",
25
- "admin",
26
- "letmein",
27
- "welcome",
28
- "monkey",
29
- "dragon",
30
- "master",
31
- "hello",
32
- "freedom",
33
- "whatever",
34
- "qazwsx",
35
- "trustno1",
36
- "jordan",
37
- "harley",
38
- "ranger",
39
- "buster",
40
- "thomas",
41
- "tigger",
42
- "robert",
43
- "soccer",
44
- "batman",
45
- "test",
46
- "pass",
47
- "user",
48
- "guest",
49
- "login",
50
- "secret",
51
- "god",
52
- "love",
53
- "sex",
54
- "money",
55
- "password1",
56
- "12345678",
57
- "qwerty123",
58
- "admin123",
59
- "password!",
60
- "password1!",
61
- "password123",
62
- "password123!"
63
- ];
64
- const validatePassword = (password, options = {}) => {
65
- const config = { ...DEFAULT_OPTIONS, ...options };
66
- const errors = [];
67
- const hints = [];
68
- let score = 0;
69
- if (password.length < config.minLength) {
70
- errors.push(`Password must be at least ${config.minLength} characters long`);
71
- hints.push(`Use at least ${config.minLength} characters`);
72
- } else {
73
- score += 20;
74
- if (password.length < 12) {
75
- hints.push("Use 12 or more characters for extra security");
76
- }
77
- }
78
- if (config.requireUppercase && !/[A-Z]/.test(password)) {
79
- errors.push("Password must contain at least one uppercase letter");
80
- hints.push("Add an uppercase letter (A-Z)");
81
- } else if (/[A-Z]/.test(password)) {
82
- score += 15;
83
- }
84
- if (config.requireLowercase && !/[a-z]/.test(password)) {
85
- errors.push("Password must contain at least one lowercase letter");
86
- hints.push("Add a lowercase letter (a-z)");
87
- } else if (/[a-z]/.test(password)) {
88
- score += 15;
89
- }
90
- if (config.requireNumbers && !/\d/.test(password)) {
91
- errors.push("Password must contain at least one number");
92
- hints.push("Add a number (0-9)");
93
- } else if (/\d/.test(password)) {
94
- score += 15;
95
- }
96
- if (config.requireSpecialChars && !/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(password)) {
97
- errors.push("Password must contain at least one special character");
98
- hints.push("Add a special character (e.g. !@#$%)");
99
- } else if (/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(password)) {
100
- score += 15;
101
- }
102
- if (config.preventCommonPasswords && COMMON_PASSWORDS.includes(password.toLowerCase())) {
103
- errors.push("Password is too common. Please choose a more unique password");
104
- hints.push("Avoid common passwords or names");
105
- }
106
- if (password.length >= 12) {
107
- score += 10;
108
- } else if (password.length >= 10) {
109
- score += 5;
110
- }
111
- const hasUppercase = /[A-Z]/.test(password);
112
- const hasLowercase = /[a-z]/.test(password);
113
- const hasNumbers = /\d/.test(password);
114
- const hasSpecial = /[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(password);
115
- const complexityTypes = [hasUppercase, hasLowercase, hasNumbers, hasSpecial].filter(Boolean).length;
116
- if (complexityTypes >= 4) {
117
- score += 10;
118
- } else if (complexityTypes >= 3) {
119
- score += 5;
120
- hints.push("Use a mix of uppercase, lowercase, numbers, and special characters");
121
- }
122
- let strength = "weak";
123
- if (score >= 80) {
124
- strength = "strong";
125
- } else if (score >= 60) {
126
- strength = "medium";
127
- }
128
- return {
129
- isValid: errors.length === 0,
130
- errors,
131
- strength,
132
- score: Math.min(score, 100),
133
- hints: Array.from(new Set(hints))
134
- // deduplicate
135
- };
136
- };
137
- const getPasswordStrengthColor = (strength) => {
138
- switch (strength) {
139
- case "weak":
140
- return "#dc3545";
141
- case "medium":
142
- return "#ffc107";
143
- case "strong":
144
- return "#28a745";
145
- default:
146
- return "#6c757d";
147
- }
148
- };
149
- const getPasswordStrengthText = (strength) => {
150
- switch (strength) {
151
- case "weak":
152
- return "Weak";
153
- case "medium":
154
- return "Medium";
155
- case "strong":
156
- return "Strong";
157
- default:
158
- return "Unknown";
159
- }
160
- };
161
-
162
- export { getPasswordStrengthColor as a, getPasswordStrengthText as b, getPasswordValidationOptions as g, validatePassword as v };
@@ -16,13 +16,13 @@ type __VLS_Slots = {} & {
16
16
  default?: (props: typeof __VLS_1) => any;
17
17
  };
18
18
  declare const __VLS_component: import("vue").DefineComponent<LogoutLinkProps, void, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
19
- success: () => any;
20
- error: (error: string) => any;
21
19
  click: () => any;
20
+ error: (error: string) => any;
21
+ success: () => any;
22
22
  }, string, import("vue").PublicProps, Readonly<LogoutLinkProps> & Readonly<{
23
- onSuccess?: (() => any) | undefined;
24
- onError?: ((error: string) => any) | undefined;
25
23
  onClick?: (() => any) | undefined;
24
+ onError?: ((error: string) => any) | undefined;
25
+ onSuccess?: (() => any) | undefined;
26
26
  }>, {
27
27
  redirectTo: string;
28
28
  linkText: string;