nuxt-users 1.8.4 → 1.9.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 +47 -0
- package/dist/cli.mjs +3 -2
- package/dist/module.d.mts +1 -133
- package/dist/module.d.ts +1 -133
- package/dist/module.json +1 -1
- package/dist/module.mjs +23 -0
- package/dist/runtime/composables/useNuxtUsersDatabase.d.ts +15 -0
- package/dist/runtime/composables/useNuxtUsersDatabase.js +14 -0
- package/dist/runtime/server/utils/index.d.ts +2 -1
- package/dist/runtime/server/utils/index.js +2 -1
- package/dist/runtime/server/utils/user.d.ts +5 -0
- package/dist/runtime/server/utils/user.js +16 -0
- package/dist/shared/nuxt-users.BnOQs2LI.mjs +162 -0
- package/dist/shared/nuxt-users.CXezgQLO.d.mts +167 -0
- package/dist/shared/nuxt-users.CXezgQLO.d.ts +167 -0
- package/dist/utils.d.mts +3 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.mjs +2 -162
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,53 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## v2.0.0
|
|
5
|
+
|
|
6
|
+
[compare changes](https://github.com/rrd108/nuxt-users/compare/v1.8.5...v2.0.0)
|
|
7
|
+
|
|
8
|
+
### 🚀 Enhancements
|
|
9
|
+
|
|
10
|
+
- ⚠️ Export TypeScript types and utilities for consumers ([729d961](https://github.com/rrd108/nuxt-users/commit/729d961))
|
|
11
|
+
- Add getLastLoginTime function to track user login activity ([001d4f2](https://github.com/rrd108/nuxt-users/commit/001d4f2))
|
|
12
|
+
|
|
13
|
+
### 🏡 Chore
|
|
14
|
+
|
|
15
|
+
- Fix lint ([beb3e43](https://github.com/rrd108/nuxt-users/commit/beb3e43))
|
|
16
|
+
- **release:** V1.8.5 ([403cbd3](https://github.com/rrd108/nuxt-users/commit/403cbd3))
|
|
17
|
+
|
|
18
|
+
### 🎨 Styles
|
|
19
|
+
|
|
20
|
+
- Fix code formatting and remove trailing whitespace ([ea07a3c](https://github.com/rrd108/nuxt-users/commit/ea07a3c))
|
|
21
|
+
|
|
22
|
+
#### ⚠️ Breaking Changes
|
|
23
|
+
|
|
24
|
+
- ⚠️ Export TypeScript types and utilities for consumers ([729d961](https://github.com/rrd108/nuxt-users/commit/729d961))
|
|
25
|
+
|
|
26
|
+
### ❤️ Contributors
|
|
27
|
+
|
|
28
|
+
- Rrd108 ([@rrd108](https://github.com/rrd108))
|
|
29
|
+
|
|
30
|
+
## v1.8.5
|
|
31
|
+
|
|
32
|
+
[compare changes](https://github.com/rrd108/nuxt-users/compare/v1.8.4...v1.8.5)
|
|
33
|
+
|
|
34
|
+
### 🩹 Fixes
|
|
35
|
+
|
|
36
|
+
- Database sharing feature ([3a2e12f](https://github.com/rrd108/nuxt-users/commit/3a2e12f))
|
|
37
|
+
|
|
38
|
+
### 🏡 Chore
|
|
39
|
+
|
|
40
|
+
- **release:** V1.8.4 ([ab7fa92](https://github.com/rrd108/nuxt-users/commit/ab7fa92))
|
|
41
|
+
- Fix lint ([beb3e43](https://github.com/rrd108/nuxt-users/commit/beb3e43))
|
|
42
|
+
|
|
43
|
+
### ✅ Tests
|
|
44
|
+
|
|
45
|
+
- Add to check cli error ([fd338ca](https://github.com/rrd108/nuxt-users/commit/fd338ca))
|
|
46
|
+
|
|
47
|
+
### ❤️ Contributors
|
|
48
|
+
|
|
49
|
+
- Rrd108 ([@rrd108](https://github.com/rrd108))
|
|
50
|
+
|
|
4
51
|
## v1.8.4
|
|
5
52
|
|
|
6
53
|
[compare changes](https://github.com/rrd108/nuxt-users/compare/v1.8.3...v1.8.4)
|
package/dist/cli.mjs
CHANGED
|
@@ -4,7 +4,8 @@ import { defaultOptions } from './module.mjs';
|
|
|
4
4
|
import { loadNuxt } from '@nuxt/kit';
|
|
5
5
|
import { defu } from 'defu';
|
|
6
6
|
import { runMigrations, createUser as createUser$1, createUsersTable as createUsersTable$1, createPersonalAccessTokensTable as createPersonalAccessTokensTable$1, createPasswordResetTokensTable as createPasswordResetTokensTable$1, createMigrationsTable as createMigrationsTable$1 } from '../dist/runtime/server/utils/index.js';
|
|
7
|
-
import { getPasswordValidationOptions, validatePassword } from './
|
|
7
|
+
import { g as getPasswordValidationOptions, v as validatePassword } from './shared/nuxt-users.BnOQs2LI.mjs';
|
|
8
|
+
import '../dist/runtime/server/utils/user.js';
|
|
8
9
|
|
|
9
10
|
const getOptionsFromEnv = () => {
|
|
10
11
|
const connectorName = process.env.DB_CONNECTOR || "sqlite";
|
|
@@ -247,7 +248,7 @@ const main = defineCommand({
|
|
|
247
248
|
meta: {
|
|
248
249
|
name: "nuxt-users",
|
|
249
250
|
description: "CLI for Nuxt Users Module - Manage users, migrations, and database operations",
|
|
250
|
-
version: "1.8.
|
|
251
|
+
version: "1.8.5"
|
|
251
252
|
},
|
|
252
253
|
subCommands: {
|
|
253
254
|
migrate,
|
package/dist/module.d.mts
CHANGED
|
@@ -1,139 +1,7 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
import { R as RuntimeModuleOptions, M as ModuleOptions } from './shared/nuxt-users.CXezgQLO.mjs';
|
|
2
3
|
export * from '../dist/runtime/server/utils/index.js';
|
|
3
4
|
|
|
4
|
-
type DatabaseType = 'sqlite' | 'mysql' | 'postgresql';
|
|
5
|
-
type DatabaseConfig = {
|
|
6
|
-
path?: string;
|
|
7
|
-
host?: string;
|
|
8
|
-
port?: number;
|
|
9
|
-
user?: string;
|
|
10
|
-
password?: string;
|
|
11
|
-
database?: string;
|
|
12
|
-
};
|
|
13
|
-
interface RuntimeModuleOptions {
|
|
14
|
-
connector?: {
|
|
15
|
-
name: DatabaseType;
|
|
16
|
-
options: DatabaseConfig;
|
|
17
|
-
};
|
|
18
|
-
tables?: {
|
|
19
|
-
migrations?: string;
|
|
20
|
-
users?: string;
|
|
21
|
-
personalAccessTokens?: string;
|
|
22
|
-
passwordResetTokens?: string;
|
|
23
|
-
};
|
|
24
|
-
/**
|
|
25
|
-
* Mailer configuration options for sending emails (e.g., password resets)
|
|
26
|
-
* Uses nodemailer
|
|
27
|
-
*/
|
|
28
|
-
mailer?: MailerOptions;
|
|
29
|
-
/**
|
|
30
|
-
* Base URL for password reset links
|
|
31
|
-
* @default 'http://localhost:3000' // Example, will be set in module defaults
|
|
32
|
-
*/
|
|
33
|
-
passwordResetBaseUrl?: string;
|
|
34
|
-
/**
|
|
35
|
-
* Skip database checks during module setup to prevent hanging
|
|
36
|
-
* @default false
|
|
37
|
-
*/
|
|
38
|
-
auth?: {
|
|
39
|
-
/**
|
|
40
|
-
* Whitelisted routes that do not require authentication
|
|
41
|
-
* @default ['/login']
|
|
42
|
-
* @example ['/login', '/register']
|
|
43
|
-
*/
|
|
44
|
-
whitelist?: string[];
|
|
45
|
-
/**
|
|
46
|
-
* Token expiration time in minutes
|
|
47
|
-
* @default 1440
|
|
48
|
-
*/
|
|
49
|
-
tokenExpiration?: number;
|
|
50
|
-
/**
|
|
51
|
-
* Role-based permissions configuration
|
|
52
|
-
* @default {}
|
|
53
|
-
* @example {
|
|
54
|
-
* admin: ['*'], // admin can access everything
|
|
55
|
-
* user: ['/profile', '/api/user/profile'],
|
|
56
|
-
* moderator: ['/admin/*', '/api/admin/*']
|
|
57
|
-
* }
|
|
58
|
-
*/
|
|
59
|
-
permissions?: Record<string, string[]>;
|
|
60
|
-
};
|
|
61
|
-
/**
|
|
62
|
-
* Password validation configuration
|
|
63
|
-
*/
|
|
64
|
-
passwordValidation?: {
|
|
65
|
-
/**
|
|
66
|
-
* Minimum password length
|
|
67
|
-
* @default 8
|
|
68
|
-
*/
|
|
69
|
-
minLength?: number;
|
|
70
|
-
/**
|
|
71
|
-
* Require uppercase letters
|
|
72
|
-
* @default true
|
|
73
|
-
*/
|
|
74
|
-
requireUppercase?: boolean;
|
|
75
|
-
/**
|
|
76
|
-
* Require lowercase letters
|
|
77
|
-
* @default true
|
|
78
|
-
*/
|
|
79
|
-
requireLowercase?: boolean;
|
|
80
|
-
/**
|
|
81
|
-
* Require numbers
|
|
82
|
-
* @default true
|
|
83
|
-
*/
|
|
84
|
-
requireNumbers?: boolean;
|
|
85
|
-
/**
|
|
86
|
-
* Require special characters
|
|
87
|
-
* @default true
|
|
88
|
-
*/
|
|
89
|
-
requireSpecialChars?: boolean;
|
|
90
|
-
/**
|
|
91
|
-
* Prevent common passwords
|
|
92
|
-
* @default true
|
|
93
|
-
*/
|
|
94
|
-
preventCommonPasswords?: boolean;
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
interface ModuleOptions {
|
|
98
|
-
connector: {
|
|
99
|
-
name: DatabaseType;
|
|
100
|
-
options: DatabaseConfig;
|
|
101
|
-
};
|
|
102
|
-
tables: {
|
|
103
|
-
migrations: string;
|
|
104
|
-
users: string;
|
|
105
|
-
personalAccessTokens: string;
|
|
106
|
-
passwordResetTokens: string;
|
|
107
|
-
};
|
|
108
|
-
mailer?: MailerOptions;
|
|
109
|
-
passwordResetBaseUrl?: string;
|
|
110
|
-
auth: {
|
|
111
|
-
whitelist: string[];
|
|
112
|
-
tokenExpiration: number;
|
|
113
|
-
permissions: Record<string, string[]>;
|
|
114
|
-
};
|
|
115
|
-
passwordValidation: {
|
|
116
|
-
minLength: number;
|
|
117
|
-
requireUppercase: boolean;
|
|
118
|
-
requireLowercase: boolean;
|
|
119
|
-
requireNumbers: boolean;
|
|
120
|
-
requireSpecialChars: boolean;
|
|
121
|
-
preventCommonPasswords: boolean;
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
interface MailerOptions {
|
|
125
|
-
host: string;
|
|
126
|
-
port: number;
|
|
127
|
-
secure?: boolean;
|
|
128
|
-
auth: {
|
|
129
|
-
user: string;
|
|
130
|
-
pass: string;
|
|
131
|
-
};
|
|
132
|
-
defaults?: {
|
|
133
|
-
from: string;
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
|
|
137
5
|
declare const defaultOptions: ModuleOptions;
|
|
138
6
|
declare const _default: _nuxt_schema.NuxtModule<RuntimeModuleOptions, RuntimeModuleOptions, false>;
|
|
139
7
|
|
package/dist/module.d.ts
CHANGED
|
@@ -1,139 +1,7 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
import { R as RuntimeModuleOptions, M as ModuleOptions } from './shared/nuxt-users.CXezgQLO.js';
|
|
2
3
|
export * from '../dist/runtime/server/utils/index.js';
|
|
3
4
|
|
|
4
|
-
type DatabaseType = 'sqlite' | 'mysql' | 'postgresql';
|
|
5
|
-
type DatabaseConfig = {
|
|
6
|
-
path?: string;
|
|
7
|
-
host?: string;
|
|
8
|
-
port?: number;
|
|
9
|
-
user?: string;
|
|
10
|
-
password?: string;
|
|
11
|
-
database?: string;
|
|
12
|
-
};
|
|
13
|
-
interface RuntimeModuleOptions {
|
|
14
|
-
connector?: {
|
|
15
|
-
name: DatabaseType;
|
|
16
|
-
options: DatabaseConfig;
|
|
17
|
-
};
|
|
18
|
-
tables?: {
|
|
19
|
-
migrations?: string;
|
|
20
|
-
users?: string;
|
|
21
|
-
personalAccessTokens?: string;
|
|
22
|
-
passwordResetTokens?: string;
|
|
23
|
-
};
|
|
24
|
-
/**
|
|
25
|
-
* Mailer configuration options for sending emails (e.g., password resets)
|
|
26
|
-
* Uses nodemailer
|
|
27
|
-
*/
|
|
28
|
-
mailer?: MailerOptions;
|
|
29
|
-
/**
|
|
30
|
-
* Base URL for password reset links
|
|
31
|
-
* @default 'http://localhost:3000' // Example, will be set in module defaults
|
|
32
|
-
*/
|
|
33
|
-
passwordResetBaseUrl?: string;
|
|
34
|
-
/**
|
|
35
|
-
* Skip database checks during module setup to prevent hanging
|
|
36
|
-
* @default false
|
|
37
|
-
*/
|
|
38
|
-
auth?: {
|
|
39
|
-
/**
|
|
40
|
-
* Whitelisted routes that do not require authentication
|
|
41
|
-
* @default ['/login']
|
|
42
|
-
* @example ['/login', '/register']
|
|
43
|
-
*/
|
|
44
|
-
whitelist?: string[];
|
|
45
|
-
/**
|
|
46
|
-
* Token expiration time in minutes
|
|
47
|
-
* @default 1440
|
|
48
|
-
*/
|
|
49
|
-
tokenExpiration?: number;
|
|
50
|
-
/**
|
|
51
|
-
* Role-based permissions configuration
|
|
52
|
-
* @default {}
|
|
53
|
-
* @example {
|
|
54
|
-
* admin: ['*'], // admin can access everything
|
|
55
|
-
* user: ['/profile', '/api/user/profile'],
|
|
56
|
-
* moderator: ['/admin/*', '/api/admin/*']
|
|
57
|
-
* }
|
|
58
|
-
*/
|
|
59
|
-
permissions?: Record<string, string[]>;
|
|
60
|
-
};
|
|
61
|
-
/**
|
|
62
|
-
* Password validation configuration
|
|
63
|
-
*/
|
|
64
|
-
passwordValidation?: {
|
|
65
|
-
/**
|
|
66
|
-
* Minimum password length
|
|
67
|
-
* @default 8
|
|
68
|
-
*/
|
|
69
|
-
minLength?: number;
|
|
70
|
-
/**
|
|
71
|
-
* Require uppercase letters
|
|
72
|
-
* @default true
|
|
73
|
-
*/
|
|
74
|
-
requireUppercase?: boolean;
|
|
75
|
-
/**
|
|
76
|
-
* Require lowercase letters
|
|
77
|
-
* @default true
|
|
78
|
-
*/
|
|
79
|
-
requireLowercase?: boolean;
|
|
80
|
-
/**
|
|
81
|
-
* Require numbers
|
|
82
|
-
* @default true
|
|
83
|
-
*/
|
|
84
|
-
requireNumbers?: boolean;
|
|
85
|
-
/**
|
|
86
|
-
* Require special characters
|
|
87
|
-
* @default true
|
|
88
|
-
*/
|
|
89
|
-
requireSpecialChars?: boolean;
|
|
90
|
-
/**
|
|
91
|
-
* Prevent common passwords
|
|
92
|
-
* @default true
|
|
93
|
-
*/
|
|
94
|
-
preventCommonPasswords?: boolean;
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
interface ModuleOptions {
|
|
98
|
-
connector: {
|
|
99
|
-
name: DatabaseType;
|
|
100
|
-
options: DatabaseConfig;
|
|
101
|
-
};
|
|
102
|
-
tables: {
|
|
103
|
-
migrations: string;
|
|
104
|
-
users: string;
|
|
105
|
-
personalAccessTokens: string;
|
|
106
|
-
passwordResetTokens: string;
|
|
107
|
-
};
|
|
108
|
-
mailer?: MailerOptions;
|
|
109
|
-
passwordResetBaseUrl?: string;
|
|
110
|
-
auth: {
|
|
111
|
-
whitelist: string[];
|
|
112
|
-
tokenExpiration: number;
|
|
113
|
-
permissions: Record<string, string[]>;
|
|
114
|
-
};
|
|
115
|
-
passwordValidation: {
|
|
116
|
-
minLength: number;
|
|
117
|
-
requireUppercase: boolean;
|
|
118
|
-
requireLowercase: boolean;
|
|
119
|
-
requireNumbers: boolean;
|
|
120
|
-
requireSpecialChars: boolean;
|
|
121
|
-
preventCommonPasswords: boolean;
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
interface MailerOptions {
|
|
125
|
-
host: string;
|
|
126
|
-
port: number;
|
|
127
|
-
secure?: boolean;
|
|
128
|
-
auth: {
|
|
129
|
-
user: string;
|
|
130
|
-
pass: string;
|
|
131
|
-
};
|
|
132
|
-
defaults?: {
|
|
133
|
-
from: string;
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
|
|
137
5
|
declare const defaultOptions: ModuleOptions;
|
|
138
6
|
declare const _default: _nuxt_schema.NuxtModule<RuntimeModuleOptions, RuntimeModuleOptions, false>;
|
|
139
7
|
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -128,6 +128,29 @@ const module = defineNuxtModule({
|
|
|
128
128
|
});
|
|
129
129
|
nuxt.hook("nitro:config", async (nitroConfig) => {
|
|
130
130
|
nitroConfig.experimental = nitroConfig.experimental || {};
|
|
131
|
+
nitroConfig.experimental.database = true;
|
|
132
|
+
nitroConfig.database = nitroConfig.database || {};
|
|
133
|
+
if (!nitroConfig.database.default) {
|
|
134
|
+
const connectorOptions = { ...runtimeConfigOptions.connector.options };
|
|
135
|
+
let nitroConnector;
|
|
136
|
+
switch (runtimeConfigOptions.connector.name) {
|
|
137
|
+
case "sqlite":
|
|
138
|
+
nitroConnector = "better-sqlite3";
|
|
139
|
+
break;
|
|
140
|
+
case "mysql":
|
|
141
|
+
nitroConnector = "mysql2";
|
|
142
|
+
break;
|
|
143
|
+
case "postgresql":
|
|
144
|
+
nitroConnector = "postgresql";
|
|
145
|
+
break;
|
|
146
|
+
default:
|
|
147
|
+
nitroConnector = "better-sqlite3";
|
|
148
|
+
}
|
|
149
|
+
nitroConfig.database.default = {
|
|
150
|
+
connector: nitroConnector,
|
|
151
|
+
options: connectorOptions
|
|
152
|
+
};
|
|
153
|
+
}
|
|
131
154
|
nitroConfig.experimental.tasks = true;
|
|
132
155
|
nitroConfig.scanDirs = nitroConfig.scanDirs || [];
|
|
133
156
|
nitroConfig.scanDirs.push(resolver.resolve("./runtime/server/tasks"));
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const useNuxtUsersDatabase: () => Promise<{
|
|
2
|
+
database: import("db0").Database<import("db0").Connector<Database.Database>>;
|
|
3
|
+
options: {
|
|
4
|
+
tables: {
|
|
5
|
+
migrations: string;
|
|
6
|
+
users: string;
|
|
7
|
+
personalAccessTokens: string;
|
|
8
|
+
passwordResetTokens: string;
|
|
9
|
+
};
|
|
10
|
+
connector: {
|
|
11
|
+
name: import("../../types.js").DatabaseType;
|
|
12
|
+
options: import("../../types.js").DatabaseConfig;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
}>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const useNuxtUsersDatabase = async () => {
|
|
2
|
+
const { useRuntimeConfig } = await import("#imports");
|
|
3
|
+
const { useDb } = await import("../server/utils/db.js");
|
|
4
|
+
const { nuxtUsers } = useRuntimeConfig();
|
|
5
|
+
const options = nuxtUsers;
|
|
6
|
+
const database = await useDb(options);
|
|
7
|
+
return {
|
|
8
|
+
database,
|
|
9
|
+
options: {
|
|
10
|
+
tables: options.tables,
|
|
11
|
+
connector: options.connector
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { useDb, checkTableExists } from './db.js';
|
|
2
|
-
export { createUser, findUserByEmail, updateUserPassword, getCurrentUserFromToken, hasAnyUsers, deleteExpiredPersonalAccessTokens, deleteTokensWithoutExpiration, cleanupPersonalAccessTokens, revokeUserTokens } from './user.js';
|
|
2
|
+
export { createUser, findUserByEmail, updateUserPassword, getCurrentUserFromToken, hasAnyUsers, deleteExpiredPersonalAccessTokens, deleteTokensWithoutExpiration, cleanupPersonalAccessTokens, revokeUserTokens, getLastLoginTime } from './user.js';
|
|
3
3
|
export { createUsersTable } from './create-users-table.js';
|
|
4
4
|
export { createPersonalAccessTokensTable } from './create-personal-access-tokens-table.js';
|
|
5
5
|
export { createPasswordResetTokensTable } from './create-password-reset-tokens-table.js';
|
|
6
6
|
export { createMigrationsTable } from './create-migrations-table.js';
|
|
7
7
|
export { runMigrations } from './migrate.js';
|
|
8
|
+
export { useNuxtUsersDatabase } from '../../composables/useNuxtUsersDatabase.js';
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { useDb, checkTableExists } from "./db.js";
|
|
2
|
-
export { createUser, findUserByEmail, updateUserPassword, getCurrentUserFromToken, hasAnyUsers, deleteExpiredPersonalAccessTokens, deleteTokensWithoutExpiration, cleanupPersonalAccessTokens, revokeUserTokens } from "./user.js";
|
|
2
|
+
export { createUser, findUserByEmail, updateUserPassword, getCurrentUserFromToken, hasAnyUsers, deleteExpiredPersonalAccessTokens, deleteTokensWithoutExpiration, cleanupPersonalAccessTokens, revokeUserTokens, getLastLoginTime } from "./user.js";
|
|
3
3
|
export { createUsersTable } from "./create-users-table.js";
|
|
4
4
|
export { createPersonalAccessTokensTable } from "./create-personal-access-tokens-table.js";
|
|
5
5
|
export { createPasswordResetTokensTable } from "./create-password-reset-tokens-table.js";
|
|
6
6
|
export { createMigrationsTable } from "./create-migrations-table.js";
|
|
7
7
|
export { runMigrations } from "./migrate.js";
|
|
8
|
+
export { useNuxtUsersDatabase } from "../../composables/useNuxtUsersDatabase.js";
|
|
@@ -44,4 +44,9 @@ export declare const cleanupPersonalAccessTokens: (options: ModuleOptions, inclu
|
|
|
44
44
|
* Revokes all tokens for a specific user.
|
|
45
45
|
*/
|
|
46
46
|
export declare const revokeUserTokens: (userId: number, options: ModuleOptions) => Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Gets the last login time for a user based on their most recent personal access token creation.
|
|
49
|
+
* This represents when the user last successfully logged in.
|
|
50
|
+
*/
|
|
51
|
+
export declare const getLastLoginTime: (userId: number, options: ModuleOptions) => Promise<string | null>;
|
|
47
52
|
export {};
|
|
@@ -141,3 +141,19 @@ export const revokeUserTokens = async (userId, options) => {
|
|
|
141
141
|
`;
|
|
142
142
|
console.log(`[Nuxt Users] All tokens revoked for user ID: ${userId}`);
|
|
143
143
|
};
|
|
144
|
+
export const getLastLoginTime = async (userId, options) => {
|
|
145
|
+
const db = await useDb(options);
|
|
146
|
+
const personalAccessTokensTable = options.tables.personalAccessTokens;
|
|
147
|
+
const result = await db.sql`
|
|
148
|
+
SELECT created_at
|
|
149
|
+
FROM {${personalAccessTokensTable}}
|
|
150
|
+
WHERE tokenable_id = ${userId} AND tokenable_type = 'user'
|
|
151
|
+
ORDER BY created_at DESC
|
|
152
|
+
LIMIT 1
|
|
153
|
+
`;
|
|
154
|
+
if (result.rows.length === 0) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
const lastLogin = result.rows[0].created_at;
|
|
158
|
+
return lastLogin instanceof Date ? lastLogin.toISOString() : lastLogin;
|
|
159
|
+
};
|
|
@@ -0,0 +1,162 @@
|
|
|
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 };
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
type DatabaseType = 'sqlite' | 'mysql' | 'postgresql';
|
|
2
|
+
type DatabaseConfig = {
|
|
3
|
+
path?: string;
|
|
4
|
+
host?: string;
|
|
5
|
+
port?: number;
|
|
6
|
+
user?: string;
|
|
7
|
+
password?: string;
|
|
8
|
+
database?: string;
|
|
9
|
+
};
|
|
10
|
+
interface RuntimeModuleOptions {
|
|
11
|
+
connector?: {
|
|
12
|
+
name: DatabaseType;
|
|
13
|
+
options: DatabaseConfig;
|
|
14
|
+
};
|
|
15
|
+
tables?: {
|
|
16
|
+
migrations?: string;
|
|
17
|
+
users?: string;
|
|
18
|
+
personalAccessTokens?: string;
|
|
19
|
+
passwordResetTokens?: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Mailer configuration options for sending emails (e.g., password resets)
|
|
23
|
+
* Uses nodemailer
|
|
24
|
+
*/
|
|
25
|
+
mailer?: MailerOptions;
|
|
26
|
+
/**
|
|
27
|
+
* Base URL for password reset links
|
|
28
|
+
* @default 'http://localhost:3000' // Example, will be set in module defaults
|
|
29
|
+
*/
|
|
30
|
+
passwordResetBaseUrl?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Skip database checks during module setup to prevent hanging
|
|
33
|
+
* @default false
|
|
34
|
+
*/
|
|
35
|
+
auth?: {
|
|
36
|
+
/**
|
|
37
|
+
* Whitelisted routes that do not require authentication
|
|
38
|
+
* @default ['/login']
|
|
39
|
+
* @example ['/login', '/register']
|
|
40
|
+
*/
|
|
41
|
+
whitelist?: string[];
|
|
42
|
+
/**
|
|
43
|
+
* Token expiration time in minutes
|
|
44
|
+
* @default 1440
|
|
45
|
+
*/
|
|
46
|
+
tokenExpiration?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Role-based permissions configuration
|
|
49
|
+
* @default {}
|
|
50
|
+
* @example {
|
|
51
|
+
* admin: ['*'], // admin can access everything
|
|
52
|
+
* user: ['/profile', '/api/user/profile'],
|
|
53
|
+
* moderator: ['/admin/*', '/api/admin/*']
|
|
54
|
+
* }
|
|
55
|
+
*/
|
|
56
|
+
permissions?: Record<string, string[]>;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Password validation configuration
|
|
60
|
+
*/
|
|
61
|
+
passwordValidation?: {
|
|
62
|
+
/**
|
|
63
|
+
* Minimum password length
|
|
64
|
+
* @default 8
|
|
65
|
+
*/
|
|
66
|
+
minLength?: number;
|
|
67
|
+
/**
|
|
68
|
+
* Require uppercase letters
|
|
69
|
+
* @default true
|
|
70
|
+
*/
|
|
71
|
+
requireUppercase?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Require lowercase letters
|
|
74
|
+
* @default true
|
|
75
|
+
*/
|
|
76
|
+
requireLowercase?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Require numbers
|
|
79
|
+
* @default true
|
|
80
|
+
*/
|
|
81
|
+
requireNumbers?: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Require special characters
|
|
84
|
+
* @default true
|
|
85
|
+
*/
|
|
86
|
+
requireSpecialChars?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Prevent common passwords
|
|
89
|
+
* @default true
|
|
90
|
+
*/
|
|
91
|
+
preventCommonPasswords?: boolean;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
interface ModuleOptions {
|
|
95
|
+
connector: {
|
|
96
|
+
name: DatabaseType;
|
|
97
|
+
options: DatabaseConfig;
|
|
98
|
+
};
|
|
99
|
+
tables: {
|
|
100
|
+
migrations: string;
|
|
101
|
+
users: string;
|
|
102
|
+
personalAccessTokens: string;
|
|
103
|
+
passwordResetTokens: string;
|
|
104
|
+
};
|
|
105
|
+
mailer?: MailerOptions;
|
|
106
|
+
passwordResetBaseUrl?: string;
|
|
107
|
+
auth: {
|
|
108
|
+
whitelist: string[];
|
|
109
|
+
tokenExpiration: number;
|
|
110
|
+
permissions: Record<string, string[]>;
|
|
111
|
+
};
|
|
112
|
+
passwordValidation: {
|
|
113
|
+
minLength: number;
|
|
114
|
+
requireUppercase: boolean;
|
|
115
|
+
requireLowercase: boolean;
|
|
116
|
+
requireNumbers: boolean;
|
|
117
|
+
requireSpecialChars: boolean;
|
|
118
|
+
preventCommonPasswords: boolean;
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
interface MailerOptions {
|
|
122
|
+
host: string;
|
|
123
|
+
port: number;
|
|
124
|
+
secure?: boolean;
|
|
125
|
+
auth: {
|
|
126
|
+
user: string;
|
|
127
|
+
pass: string;
|
|
128
|
+
};
|
|
129
|
+
defaults?: {
|
|
130
|
+
from: string;
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
interface User {
|
|
134
|
+
id: number;
|
|
135
|
+
email: string;
|
|
136
|
+
name: string;
|
|
137
|
+
password: string;
|
|
138
|
+
role: string;
|
|
139
|
+
created_at: string;
|
|
140
|
+
updated_at: string;
|
|
141
|
+
}
|
|
142
|
+
type UserWithoutPassword = Omit<User, 'password'>;
|
|
143
|
+
interface PersonalAccessToken {
|
|
144
|
+
id: number;
|
|
145
|
+
tokenable_type: string;
|
|
146
|
+
tokenable_id: number;
|
|
147
|
+
name: string;
|
|
148
|
+
token: string;
|
|
149
|
+
abilities?: string;
|
|
150
|
+
last_used_at?: string;
|
|
151
|
+
expires_at?: string;
|
|
152
|
+
created_at: string;
|
|
153
|
+
updated_at: string;
|
|
154
|
+
}
|
|
155
|
+
interface PasswordResetToken {
|
|
156
|
+
id: number;
|
|
157
|
+
email: string;
|
|
158
|
+
token: string;
|
|
159
|
+
created_at: string;
|
|
160
|
+
}
|
|
161
|
+
interface LoginFormData {
|
|
162
|
+
email: string;
|
|
163
|
+
password: string;
|
|
164
|
+
rememberMe?: boolean;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export type { LoginFormData as L, ModuleOptions as M, PersonalAccessToken as P, RuntimeModuleOptions as R, User as U, UserWithoutPassword as a, PasswordResetToken as b };
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
type DatabaseType = 'sqlite' | 'mysql' | 'postgresql';
|
|
2
|
+
type DatabaseConfig = {
|
|
3
|
+
path?: string;
|
|
4
|
+
host?: string;
|
|
5
|
+
port?: number;
|
|
6
|
+
user?: string;
|
|
7
|
+
password?: string;
|
|
8
|
+
database?: string;
|
|
9
|
+
};
|
|
10
|
+
interface RuntimeModuleOptions {
|
|
11
|
+
connector?: {
|
|
12
|
+
name: DatabaseType;
|
|
13
|
+
options: DatabaseConfig;
|
|
14
|
+
};
|
|
15
|
+
tables?: {
|
|
16
|
+
migrations?: string;
|
|
17
|
+
users?: string;
|
|
18
|
+
personalAccessTokens?: string;
|
|
19
|
+
passwordResetTokens?: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Mailer configuration options for sending emails (e.g., password resets)
|
|
23
|
+
* Uses nodemailer
|
|
24
|
+
*/
|
|
25
|
+
mailer?: MailerOptions;
|
|
26
|
+
/**
|
|
27
|
+
* Base URL for password reset links
|
|
28
|
+
* @default 'http://localhost:3000' // Example, will be set in module defaults
|
|
29
|
+
*/
|
|
30
|
+
passwordResetBaseUrl?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Skip database checks during module setup to prevent hanging
|
|
33
|
+
* @default false
|
|
34
|
+
*/
|
|
35
|
+
auth?: {
|
|
36
|
+
/**
|
|
37
|
+
* Whitelisted routes that do not require authentication
|
|
38
|
+
* @default ['/login']
|
|
39
|
+
* @example ['/login', '/register']
|
|
40
|
+
*/
|
|
41
|
+
whitelist?: string[];
|
|
42
|
+
/**
|
|
43
|
+
* Token expiration time in minutes
|
|
44
|
+
* @default 1440
|
|
45
|
+
*/
|
|
46
|
+
tokenExpiration?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Role-based permissions configuration
|
|
49
|
+
* @default {}
|
|
50
|
+
* @example {
|
|
51
|
+
* admin: ['*'], // admin can access everything
|
|
52
|
+
* user: ['/profile', '/api/user/profile'],
|
|
53
|
+
* moderator: ['/admin/*', '/api/admin/*']
|
|
54
|
+
* }
|
|
55
|
+
*/
|
|
56
|
+
permissions?: Record<string, string[]>;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Password validation configuration
|
|
60
|
+
*/
|
|
61
|
+
passwordValidation?: {
|
|
62
|
+
/**
|
|
63
|
+
* Minimum password length
|
|
64
|
+
* @default 8
|
|
65
|
+
*/
|
|
66
|
+
minLength?: number;
|
|
67
|
+
/**
|
|
68
|
+
* Require uppercase letters
|
|
69
|
+
* @default true
|
|
70
|
+
*/
|
|
71
|
+
requireUppercase?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Require lowercase letters
|
|
74
|
+
* @default true
|
|
75
|
+
*/
|
|
76
|
+
requireLowercase?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Require numbers
|
|
79
|
+
* @default true
|
|
80
|
+
*/
|
|
81
|
+
requireNumbers?: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Require special characters
|
|
84
|
+
* @default true
|
|
85
|
+
*/
|
|
86
|
+
requireSpecialChars?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Prevent common passwords
|
|
89
|
+
* @default true
|
|
90
|
+
*/
|
|
91
|
+
preventCommonPasswords?: boolean;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
interface ModuleOptions {
|
|
95
|
+
connector: {
|
|
96
|
+
name: DatabaseType;
|
|
97
|
+
options: DatabaseConfig;
|
|
98
|
+
};
|
|
99
|
+
tables: {
|
|
100
|
+
migrations: string;
|
|
101
|
+
users: string;
|
|
102
|
+
personalAccessTokens: string;
|
|
103
|
+
passwordResetTokens: string;
|
|
104
|
+
};
|
|
105
|
+
mailer?: MailerOptions;
|
|
106
|
+
passwordResetBaseUrl?: string;
|
|
107
|
+
auth: {
|
|
108
|
+
whitelist: string[];
|
|
109
|
+
tokenExpiration: number;
|
|
110
|
+
permissions: Record<string, string[]>;
|
|
111
|
+
};
|
|
112
|
+
passwordValidation: {
|
|
113
|
+
minLength: number;
|
|
114
|
+
requireUppercase: boolean;
|
|
115
|
+
requireLowercase: boolean;
|
|
116
|
+
requireNumbers: boolean;
|
|
117
|
+
requireSpecialChars: boolean;
|
|
118
|
+
preventCommonPasswords: boolean;
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
interface MailerOptions {
|
|
122
|
+
host: string;
|
|
123
|
+
port: number;
|
|
124
|
+
secure?: boolean;
|
|
125
|
+
auth: {
|
|
126
|
+
user: string;
|
|
127
|
+
pass: string;
|
|
128
|
+
};
|
|
129
|
+
defaults?: {
|
|
130
|
+
from: string;
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
interface User {
|
|
134
|
+
id: number;
|
|
135
|
+
email: string;
|
|
136
|
+
name: string;
|
|
137
|
+
password: string;
|
|
138
|
+
role: string;
|
|
139
|
+
created_at: string;
|
|
140
|
+
updated_at: string;
|
|
141
|
+
}
|
|
142
|
+
type UserWithoutPassword = Omit<User, 'password'>;
|
|
143
|
+
interface PersonalAccessToken {
|
|
144
|
+
id: number;
|
|
145
|
+
tokenable_type: string;
|
|
146
|
+
tokenable_id: number;
|
|
147
|
+
name: string;
|
|
148
|
+
token: string;
|
|
149
|
+
abilities?: string;
|
|
150
|
+
last_used_at?: string;
|
|
151
|
+
expires_at?: string;
|
|
152
|
+
created_at: string;
|
|
153
|
+
updated_at: string;
|
|
154
|
+
}
|
|
155
|
+
interface PasswordResetToken {
|
|
156
|
+
id: number;
|
|
157
|
+
email: string;
|
|
158
|
+
token: string;
|
|
159
|
+
created_at: string;
|
|
160
|
+
}
|
|
161
|
+
interface LoginFormData {
|
|
162
|
+
email: string;
|
|
163
|
+
password: string;
|
|
164
|
+
rememberMe?: boolean;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export type { LoginFormData as L, ModuleOptions as M, PersonalAccessToken as P, RuntimeModuleOptions as R, User as U, UserWithoutPassword as a, PasswordResetToken as b };
|
package/dist/utils.d.mts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
export { L as LoginFormData, M as ModuleOptions, b as PasswordResetToken, P as PersonalAccessToken, U as User, a as UserWithoutPassword } from './shared/nuxt-users.CXezgQLO.mjs';
|
|
2
|
+
export { findUserByEmail, getCurrentUserFromToken, getLastLoginTime } from '../dist/runtime/server/utils/user.js';
|
|
3
|
+
|
|
1
4
|
interface PasswordValidationResult {
|
|
2
5
|
isValid: boolean;
|
|
3
6
|
errors: string[];
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
export { L as LoginFormData, M as ModuleOptions, b as PasswordResetToken, P as PersonalAccessToken, U as User, a as UserWithoutPassword } from './shared/nuxt-users.CXezgQLO.js';
|
|
2
|
+
export { findUserByEmail, getCurrentUserFromToken, getLastLoginTime } from '../dist/runtime/server/utils/user.js';
|
|
3
|
+
|
|
1
4
|
interface PasswordValidationResult {
|
|
2
5
|
isValid: boolean;
|
|
3
6
|
errors: string[];
|
package/dist/utils.mjs
CHANGED
|
@@ -1,162 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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 };
|
|
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';
|
package/package.json
CHANGED