nuxt-users 1.21.0 → 1.23.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 +63 -0
- package/dist/module.d.mts +1 -1
- package/dist/module.d.ts +1 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +2 -1
- package/dist/runtime/components/NUsersList.vue.d.ts +7 -14
- package/dist/runtime/components/NUsersLoginForm.vue +4 -4
- package/dist/runtime/components/NUsersLoginForm.vue.d.ts +7 -3
- package/dist/runtime/components/NUsersPasswordStrengthIndicator.vue +2 -2
- package/dist/runtime/components/NUsersPasswordStrengthIndicator.vue.d.ts +1 -1
- package/dist/runtime/components/NUsersResetPasswordForm.vue +0 -1
- package/dist/runtime/components/NUsersResetPasswordForm.vue.d.ts +7 -3
- package/dist/runtime/components/NUsersUserCard.vue +1 -1
- package/dist/runtime/components/NUsersUserCard.vue.d.ts +4 -2
- package/dist/runtime/components/NUsersUserForm.vue +1 -1
- package/dist/runtime/components/NUsersUserForm.vue.d.ts +6 -6
- package/dist/runtime/composables/useAuthentication.d.ts +3 -21
- package/dist/runtime/composables/usePublicPaths.d.ts +24 -0
- package/dist/runtime/composables/usePublicPaths.js +114 -0
- package/dist/runtime/constants.js +1 -1
- package/dist/runtime/server/api/nuxt-users/[id].get.d.ts +1 -1
- package/dist/runtime/server/api/nuxt-users/[id].patch.d.ts +1 -1
- package/dist/runtime/server/api/nuxt-users/index.post.d.ts +1 -1
- package/dist/runtime/server/api/nuxt-users/me.get.d.ts +1 -1
- package/dist/runtime/server/api/nuxt-users/me.patch.d.ts +1 -1
- package/dist/runtime/server/api/nuxt-users/password/forgot.post.js +5 -2
- package/dist/runtime/server/api/nuxt-users/session/index.post.d.ts +1 -10
- package/dist/runtime/server/composables/useNuxtUsersDatabase.d.ts +2 -10
- package/dist/runtime/server/middleware/authorization.server.js +5 -1
- package/dist/runtime/server/services/password.d.ts +1 -1
- package/dist/runtime/server/services/password.js +3 -2
- package/dist/shared/{nuxt-users.xWt1KUwn.d.mts → nuxt-users.CqP-FK1T.d.mts} +4 -4
- package/dist/shared/{nuxt-users.xWt1KUwn.d.ts → nuxt-users.CqP-FK1T.d.ts} +4 -4
- package/dist/utils.d.mts +1 -1
- package/dist/utils.d.ts +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,69 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## v1.23.0
|
|
5
|
+
|
|
6
|
+
[compare changes](https://github.com/rrd108/nuxt-users/compare/v1.22.0...v1.23.0)
|
|
7
|
+
|
|
8
|
+
### 🚀 Enhancements
|
|
9
|
+
|
|
10
|
+
- Password reset url is configurable ([0a3d443](https://github.com/rrd108/nuxt-users/commit/0a3d443))
|
|
11
|
+
- Adds programmatic access control ([8bb517a](https://github.com/rrd108/nuxt-users/commit/8bb517a))
|
|
12
|
+
|
|
13
|
+
### 💅 Refactors
|
|
14
|
+
|
|
15
|
+
- Vue SFC type resolution during module build ([533fa36](https://github.com/rrd108/nuxt-users/commit/533fa36))
|
|
16
|
+
|
|
17
|
+
### 📖 Documentation
|
|
18
|
+
|
|
19
|
+
- Reset-password page info added ([9b4e6c2](https://github.com/rrd108/nuxt-users/commit/9b4e6c2))
|
|
20
|
+
|
|
21
|
+
### 🏡 Chore
|
|
22
|
+
|
|
23
|
+
- Update ip ([3139eab](https://github.com/rrd108/nuxt-users/commit/3139eab))
|
|
24
|
+
- Removes unused import ([61089b4](https://github.com/rrd108/nuxt-users/commit/61089b4))
|
|
25
|
+
- Unused imort removed ([3f3012f](https://github.com/rrd108/nuxt-users/commit/3f3012f))
|
|
26
|
+
- Remove unsued import ([ae1f4e3](https://github.com/rrd108/nuxt-users/commit/ae1f4e3))
|
|
27
|
+
- **release:** V1.22.0 ([914844f](https://github.com/rrd108/nuxt-users/commit/914844f))
|
|
28
|
+
|
|
29
|
+
### ✅ Tests
|
|
30
|
+
|
|
31
|
+
- Fix test cases ([844c3a7](https://github.com/rrd108/nuxt-users/commit/844c3a7))
|
|
32
|
+
|
|
33
|
+
### ❤️ Contributors
|
|
34
|
+
|
|
35
|
+
- Rrd108 ([@rrd108](https://github.com/rrd108))
|
|
36
|
+
|
|
37
|
+
## v1.22.0
|
|
38
|
+
|
|
39
|
+
[compare changes](https://github.com/rrd108/nuxt-users/compare/v1.21.0...v1.22.0)
|
|
40
|
+
|
|
41
|
+
### 🚀 Enhancements
|
|
42
|
+
|
|
43
|
+
- Password reset url is configurable ([0a3d443](https://github.com/rrd108/nuxt-users/commit/0a3d443))
|
|
44
|
+
|
|
45
|
+
### 🩹 Fixes
|
|
46
|
+
|
|
47
|
+
- Imports setup ([dd8e8df](https://github.com/rrd108/nuxt-users/commit/dd8e8df))
|
|
48
|
+
|
|
49
|
+
### 💅 Refactors
|
|
50
|
+
|
|
51
|
+
- Vue SFC type resolution during module build ([533fa36](https://github.com/rrd108/nuxt-users/commit/533fa36))
|
|
52
|
+
|
|
53
|
+
### 🏡 Chore
|
|
54
|
+
|
|
55
|
+
- Remove unused file ([14bea18](https://github.com/rrd108/nuxt-users/commit/14bea18))
|
|
56
|
+
- Lint fix ([a11887b](https://github.com/rrd108/nuxt-users/commit/a11887b))
|
|
57
|
+
- **release:** V1.21.0 ([3eb08bd](https://github.com/rrd108/nuxt-users/commit/3eb08bd))
|
|
58
|
+
- Update ip ([3139eab](https://github.com/rrd108/nuxt-users/commit/3139eab))
|
|
59
|
+
- Removes unused import ([61089b4](https://github.com/rrd108/nuxt-users/commit/61089b4))
|
|
60
|
+
- Unused imort removed ([3f3012f](https://github.com/rrd108/nuxt-users/commit/3f3012f))
|
|
61
|
+
- Remove unsued import ([ae1f4e3](https://github.com/rrd108/nuxt-users/commit/ae1f4e3))
|
|
62
|
+
|
|
63
|
+
### ❤️ Contributors
|
|
64
|
+
|
|
65
|
+
- Rrd108 ([@rrd108](https://github.com/rrd108))
|
|
66
|
+
|
|
4
67
|
## v1.21.0
|
|
5
68
|
|
|
6
69
|
[compare changes](https://github.com/rrd108/nuxt-users/compare/v1.18.0...v1.21.0)
|
package/dist/module.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
-
import { R as RuntimeModuleOptions, M as ModuleOptions } from './shared/nuxt-users.
|
|
2
|
+
import { R as RuntimeModuleOptions, M as ModuleOptions } from './shared/nuxt-users.CqP-FK1T.mjs';
|
|
3
3
|
export * from '../dist/runtime/server/internal/index.js';
|
|
4
4
|
|
|
5
5
|
declare const defaultOptions: ModuleOptions;
|
package/dist/module.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
-
import { R as RuntimeModuleOptions, M as ModuleOptions } from './shared/nuxt-users.
|
|
2
|
+
import { R as RuntimeModuleOptions, M as ModuleOptions } from './shared/nuxt-users.CqP-FK1T.js';
|
|
3
3
|
export * from '../dist/runtime/server/internal/index.js';
|
|
4
4
|
|
|
5
5
|
declare const defaultOptions: ModuleOptions;
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -31,7 +31,7 @@ const defaultOptions = {
|
|
|
31
31
|
from: '"Nuxt Users Module" <noreply@example.com>'
|
|
32
32
|
}
|
|
33
33
|
},
|
|
34
|
-
|
|
34
|
+
passwordResetUrl: "/reset-password",
|
|
35
35
|
auth: {
|
|
36
36
|
whitelist: [],
|
|
37
37
|
tokenExpiration: 24 * 60,
|
|
@@ -61,6 +61,7 @@ const module = defineNuxtModule({
|
|
|
61
61
|
nuxt.options.runtimeConfig.nuxtUsers = {
|
|
62
62
|
...runtimeConfigOptions,
|
|
63
63
|
apiBasePath: options.apiBasePath || defaultOptions.apiBasePath,
|
|
64
|
+
passwordResetUrl: options.passwordResetUrl || defaultOptions.passwordResetUrl,
|
|
64
65
|
tables: {
|
|
65
66
|
migrations: options.tables?.migrations || defaultOptions.tables.migrations,
|
|
66
67
|
users: options.tables?.users || defaultOptions.tables.users,
|
|
@@ -1,20 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
interface Props {
|
|
2
|
+
displayFields?: string[];
|
|
3
|
+
fieldLabels?: Record<string, string>;
|
|
4
|
+
}
|
|
2
5
|
declare var __VLS_1: {}, __VLS_3: {
|
|
3
6
|
loading: boolean;
|
|
4
7
|
}, __VLS_5: {
|
|
5
8
|
error: string | null;
|
|
6
9
|
}, __VLS_7: {}, __VLS_9: {}, __VLS_11: {
|
|
7
|
-
user:
|
|
8
|
-
id: number;
|
|
9
|
-
email: string;
|
|
10
|
-
name: string;
|
|
11
|
-
password: string;
|
|
12
|
-
role: string;
|
|
13
|
-
active: boolean;
|
|
14
|
-
created_at: string;
|
|
15
|
-
updated_at: string;
|
|
16
|
-
last_login_at?: string | undefined;
|
|
17
|
-
};
|
|
10
|
+
user: any;
|
|
18
11
|
index: number;
|
|
19
12
|
}, __VLS_22: {
|
|
20
13
|
pagination: {
|
|
@@ -54,12 +47,12 @@ type __VLS_Slots = {} & {
|
|
|
54
47
|
} & {
|
|
55
48
|
pagination?: (props: typeof __VLS_24) => any;
|
|
56
49
|
};
|
|
57
|
-
declare const __VLS_component: import("vue").DefineComponent<
|
|
50
|
+
declare const __VLS_component: import("vue").DefineComponent<Props, {
|
|
58
51
|
refresh: () => void;
|
|
59
52
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
60
53
|
delete: (user: User) => void;
|
|
61
54
|
editClick: (user: User) => void;
|
|
62
|
-
}, string, import("vue").PublicProps, Readonly<
|
|
55
|
+
}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
|
|
63
56
|
onDelete?: ((user: User) => any) | undefined;
|
|
64
57
|
onEditClick?: ((user: User) => any) | undefined;
|
|
65
58
|
}>, {
|
|
@@ -6,8 +6,8 @@ const { public: { nuxtUsers } } = useRuntimeConfig();
|
|
|
6
6
|
const { passwordValidation } = nuxtUsers;
|
|
7
7
|
const props = defineProps({
|
|
8
8
|
apiEndpoint: { type: String, required: false },
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
forgotPasswordEndpoint: { type: String, required: false },
|
|
10
|
+
redirectTo: { type: String, required: false }
|
|
11
11
|
});
|
|
12
12
|
const emit = defineEmits(["success", "error", "forgot-password-error", "submit", "forgot-password-success"]);
|
|
13
13
|
const apiEndpoint = computed(() => props.apiEndpoint || `${nuxtUsers?.apiBasePath}/session`);
|
|
@@ -172,7 +172,7 @@ const handleForgotPassword = async () => {
|
|
|
172
172
|
>
|
|
173
173
|
<div
|
|
174
174
|
v-if="forgotPasswordMessage"
|
|
175
|
-
class="success-message"
|
|
175
|
+
class="n-users-success-message"
|
|
176
176
|
>
|
|
177
177
|
{{ forgotPasswordMessage }}
|
|
178
178
|
</div>
|
|
@@ -185,7 +185,7 @@ const handleForgotPassword = async () => {
|
|
|
185
185
|
>
|
|
186
186
|
<div
|
|
187
187
|
v-if="error"
|
|
188
|
-
class="error-message"
|
|
188
|
+
class="n-users-error-message"
|
|
189
189
|
>
|
|
190
190
|
{{ error }}
|
|
191
191
|
</div>
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
interface Props {
|
|
2
|
+
apiEndpoint?: string;
|
|
3
|
+
forgotPasswordEndpoint?: string;
|
|
4
|
+
redirectTo?: string;
|
|
5
|
+
}
|
|
2
6
|
declare var __VLS_1: {}, __VLS_3: {}, __VLS_5: {}, __VLS_7: {}, __VLS_9: {}, __VLS_11: {}, __VLS_13: {
|
|
3
7
|
message: string;
|
|
4
8
|
}, __VLS_15: {
|
|
@@ -21,13 +25,13 @@ type __VLS_Slots = {} & {
|
|
|
21
25
|
} & {
|
|
22
26
|
'error-message'?: (props: typeof __VLS_15) => any;
|
|
23
27
|
};
|
|
24
|
-
declare const __VLS_component: import("vue").DefineComponent<
|
|
28
|
+
declare const __VLS_component: import("vue").DefineComponent<Props, void, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
25
29
|
error: (error: string) => any;
|
|
26
30
|
submit: (data: LoginFormData) => any;
|
|
27
31
|
success: (user: UserWithoutPassword) => any;
|
|
28
32
|
"forgot-password-error": (error: string) => any;
|
|
29
33
|
"forgot-password-success": () => any;
|
|
30
|
-
}, string, import("vue").PublicProps, Readonly<
|
|
34
|
+
}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
|
|
31
35
|
onError?: ((error: string) => any) | undefined;
|
|
32
36
|
onSubmit?: ((data: LoginFormData) => any) | undefined;
|
|
33
37
|
onSuccess?: ((user: UserWithoutPassword) => any) | undefined;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { computed } from "vue";
|
|
3
|
-
import { useRuntimeConfig } from "#
|
|
3
|
+
import { useRuntimeConfig } from "#app";
|
|
4
4
|
const props = defineProps({
|
|
5
5
|
password: { type: String, required: true },
|
|
6
|
-
validationResult: { type:
|
|
6
|
+
validationResult: { type: null, required: true },
|
|
7
7
|
showHints: { type: Boolean, required: false, default: true },
|
|
8
8
|
showRules: { type: Boolean, required: false, default: true }
|
|
9
9
|
});
|
|
@@ -6,7 +6,6 @@ import NUsersPasswordStrengthIndicator from "./NUsersPasswordStrengthIndicator.v
|
|
|
6
6
|
const { public: { nuxtUsers } } = useRuntimeConfig();
|
|
7
7
|
const moduleOptions = nuxtUsers;
|
|
8
8
|
const props = defineProps({
|
|
9
|
-
apiEndpoint: { type: String, required: false },
|
|
10
9
|
updatePasswordEndpoint: { type: String, required: false },
|
|
11
10
|
resetPasswordEndpoint: { type: String, required: false },
|
|
12
11
|
redirectTo: { type: String, required: false }
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
interface Props {
|
|
2
|
+
updatePasswordEndpoint?: string;
|
|
3
|
+
resetPasswordEndpoint?: string;
|
|
4
|
+
redirectTo?: string;
|
|
5
|
+
}
|
|
6
|
+
declare const _default: import("vue").DefineComponent<Props, void, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
3
7
|
error: (error: string) => any;
|
|
4
8
|
success: (user: UserWithoutPassword) => any;
|
|
5
9
|
"password-error": (error: string) => any;
|
|
6
10
|
"password-updated": () => any;
|
|
7
|
-
}, string, import("vue").PublicProps, Readonly<
|
|
11
|
+
}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
|
|
8
12
|
onError?: ((error: string) => any) | undefined;
|
|
9
13
|
onSuccess?: ((user: UserWithoutPassword) => any) | undefined;
|
|
10
14
|
"onPassword-error"?: ((error: string) => any) | undefined;
|
|
@@ -4,7 +4,7 @@ import { useAuthentication } from "../composables/useAuthentication";
|
|
|
4
4
|
import { useRuntimeConfig } from "#imports";
|
|
5
5
|
import { defaultDisplayFields, defaultFieldLabels } from "nuxt-users/utils";
|
|
6
6
|
const props = defineProps({
|
|
7
|
-
user: { type:
|
|
7
|
+
user: { type: null, required: true },
|
|
8
8
|
index: { type: Number, required: true },
|
|
9
9
|
displayFields: { type: Array, required: false, default: () => defaultDisplayFields },
|
|
10
10
|
fieldLabels: { type: Object, required: false, default: () => defaultFieldLabels }
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
interface Props
|
|
1
|
+
import { type User } from 'nuxt-users/utils';
|
|
2
|
+
interface Props {
|
|
3
3
|
user: User;
|
|
4
4
|
index: number;
|
|
5
|
+
displayFields?: string[];
|
|
6
|
+
fieldLabels?: Record<string, string>;
|
|
5
7
|
}
|
|
6
8
|
declare var __VLS_1: {
|
|
7
9
|
user: User;
|
|
@@ -3,7 +3,7 @@ import { ref, computed, watch } from "vue";
|
|
|
3
3
|
import { usePasswordValidation } from "../composables/usePasswordValidation";
|
|
4
4
|
import { useRuntimeConfig } from "#imports";
|
|
5
5
|
const props = defineProps({
|
|
6
|
-
user: { type:
|
|
6
|
+
user: { type: null, required: false }
|
|
7
7
|
});
|
|
8
8
|
const emit = defineEmits(["submit", "cancel"]);
|
|
9
9
|
const emptyFormData = {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { User } from 'nuxt-users/utils';
|
|
2
|
-
|
|
2
|
+
interface Props {
|
|
3
3
|
user?: User | null;
|
|
4
|
-
}
|
|
5
|
-
declare const _default: import("vue").DefineComponent<
|
|
4
|
+
}
|
|
5
|
+
declare const _default: import("vue").DefineComponent<Props, void, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
6
6
|
cancel: () => any;
|
|
7
|
-
submit: (userData:
|
|
8
|
-
}, string, import("vue").PublicProps, Readonly<
|
|
7
|
+
submit: (userData: User) => any;
|
|
8
|
+
}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
|
|
9
9
|
onCancel?: (() => any) | undefined;
|
|
10
|
-
onSubmit?: ((userData:
|
|
10
|
+
onSubmit?: ((userData: User) => any) | undefined;
|
|
11
11
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
12
12
|
export default _default;
|
|
@@ -1,27 +1,9 @@
|
|
|
1
|
-
import type { User
|
|
1
|
+
import type { User } from 'nuxt-users/utils';
|
|
2
2
|
export declare const useAuthentication: () => {
|
|
3
|
-
user: Readonly<import("vue").Ref<
|
|
4
|
-
readonly id: number;
|
|
5
|
-
readonly email: string;
|
|
6
|
-
readonly name: string;
|
|
7
|
-
readonly role: string;
|
|
8
|
-
readonly active: boolean;
|
|
9
|
-
readonly created_at: string;
|
|
10
|
-
readonly updated_at: string;
|
|
11
|
-
readonly last_login_at?: string | undefined;
|
|
12
|
-
} | null, {
|
|
13
|
-
readonly id: number;
|
|
14
|
-
readonly email: string;
|
|
15
|
-
readonly name: string;
|
|
16
|
-
readonly role: string;
|
|
17
|
-
readonly active: boolean;
|
|
18
|
-
readonly created_at: string;
|
|
19
|
-
readonly updated_at: string;
|
|
20
|
-
readonly last_login_at?: string | undefined;
|
|
21
|
-
} | null>>;
|
|
3
|
+
user: Readonly<import("vue").Ref<any, any>>;
|
|
22
4
|
isAuthenticated: import("vue").ComputedRef<boolean>;
|
|
23
5
|
login: (userData: User) => void;
|
|
24
6
|
logout: () => Promise<void>;
|
|
25
|
-
fetchUser: () => Promise<
|
|
7
|
+
fetchUser: () => Promise<any>;
|
|
26
8
|
initializeUser: () => Promise<void>;
|
|
27
9
|
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composable to get public paths and accessible paths for current user
|
|
3
|
+
* @returns Object containing different categories of accessible paths
|
|
4
|
+
*/
|
|
5
|
+
export declare const usePublicPaths: () => {
|
|
6
|
+
getPublicPaths: () => {
|
|
7
|
+
all: any[];
|
|
8
|
+
builtIn: {
|
|
9
|
+
pages: string[];
|
|
10
|
+
api: string[];
|
|
11
|
+
};
|
|
12
|
+
whitelist: any;
|
|
13
|
+
customPasswordResetPath: any;
|
|
14
|
+
apiBasePath: any;
|
|
15
|
+
};
|
|
16
|
+
getAccessiblePaths: () => {
|
|
17
|
+
all: any[];
|
|
18
|
+
public: any[];
|
|
19
|
+
roleBasedPaths: string[];
|
|
20
|
+
userRole: any;
|
|
21
|
+
};
|
|
22
|
+
isPublicPath: (path: string) => boolean;
|
|
23
|
+
isAccessiblePath: (path: string, method?: string) => boolean;
|
|
24
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { useRuntimeConfig } from "#app";
|
|
2
|
+
import { NO_AUTH_PATHS, NO_AUTH_API_PATHS } from "../constants.js";
|
|
3
|
+
import { hasPermission, isWhitelisted } from "../utils/permissions.js";
|
|
4
|
+
import { useAuthentication } from "./useAuthentication.js";
|
|
5
|
+
export const usePublicPaths = () => {
|
|
6
|
+
const { public: { nuxtUsers } } = useRuntimeConfig();
|
|
7
|
+
const config = nuxtUsers;
|
|
8
|
+
const apiBasePath = config.apiBasePath || "/api/nuxt-users";
|
|
9
|
+
const { user } = useAuthentication();
|
|
10
|
+
const getPublicPaths = () => {
|
|
11
|
+
const noAuthPaths = [...NO_AUTH_PATHS];
|
|
12
|
+
const noAuthApiPaths = NO_AUTH_API_PATHS.map((path) => `${apiBasePath}${path}`);
|
|
13
|
+
const whitelistedPaths = config.auth?.whitelist || [];
|
|
14
|
+
const customPasswordResetPath = config.passwordResetUrl && config.passwordResetUrl !== "/reset-password" ? config.passwordResetUrl : null;
|
|
15
|
+
const allPublicPaths = [
|
|
16
|
+
...noAuthPaths,
|
|
17
|
+
...noAuthApiPaths,
|
|
18
|
+
...whitelistedPaths
|
|
19
|
+
];
|
|
20
|
+
if (customPasswordResetPath) {
|
|
21
|
+
allPublicPaths.push(customPasswordResetPath);
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
// All truly public paths (no auth required)
|
|
25
|
+
all: allPublicPaths,
|
|
26
|
+
// Categorized public paths
|
|
27
|
+
builtIn: {
|
|
28
|
+
pages: noAuthPaths,
|
|
29
|
+
api: noAuthApiPaths
|
|
30
|
+
},
|
|
31
|
+
whitelist: whitelistedPaths,
|
|
32
|
+
customPasswordResetPath,
|
|
33
|
+
apiBasePath
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
const getAccessiblePaths = () => {
|
|
37
|
+
const publicPaths = getPublicPaths();
|
|
38
|
+
if (!user.value) {
|
|
39
|
+
return {
|
|
40
|
+
all: publicPaths.all,
|
|
41
|
+
public: publicPaths.all,
|
|
42
|
+
roleBasedPaths: [],
|
|
43
|
+
userRole: null
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const userRole = user.value.role;
|
|
47
|
+
const permissions = config.auth?.permissions || {};
|
|
48
|
+
const rolePermissions = permissions[userRole] || [];
|
|
49
|
+
const roleBasedPaths = [];
|
|
50
|
+
rolePermissions.forEach((permission) => {
|
|
51
|
+
if (typeof permission === "string") {
|
|
52
|
+
roleBasedPaths.push(permission);
|
|
53
|
+
} else if (typeof permission === "object" && permission.path) {
|
|
54
|
+
roleBasedPaths.push(permission.path);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
return {
|
|
58
|
+
all: [...publicPaths.all, ...roleBasedPaths],
|
|
59
|
+
public: publicPaths.all,
|
|
60
|
+
roleBasedPaths,
|
|
61
|
+
userRole
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
const isAccessiblePath = (path, method = "GET") => {
|
|
65
|
+
if (path.includes(".")) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
if (path.startsWith("/_")) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
if (NO_AUTH_PATHS.includes(path)) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
const noAuthApiPaths = NO_AUTH_API_PATHS.map((p) => `${apiBasePath}${p}`);
|
|
75
|
+
if (noAuthApiPaths.includes(path)) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
if (config.passwordResetUrl && config.passwordResetUrl !== "/reset-password" && path === config.passwordResetUrl) {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
if (isWhitelisted(path, config.auth?.whitelist || [])) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
if (user.value) {
|
|
85
|
+
return hasPermission(user.value.role, path, method, config.auth?.permissions || {});
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
};
|
|
89
|
+
const isPublicPath = (path) => {
|
|
90
|
+
if (path.includes(".")) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
if (path.startsWith("/_")) {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
if (NO_AUTH_PATHS.includes(path)) {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
const noAuthApiPaths = NO_AUTH_API_PATHS.map((p) => `${apiBasePath}${p}`);
|
|
100
|
+
if (noAuthApiPaths.includes(path)) {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
if (config.passwordResetUrl && config.passwordResetUrl !== "/reset-password" && path === config.passwordResetUrl) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
return isWhitelisted(path, config.auth?.whitelist || []);
|
|
107
|
+
};
|
|
108
|
+
return {
|
|
109
|
+
getPublicPaths,
|
|
110
|
+
getAccessiblePaths,
|
|
111
|
+
isPublicPath,
|
|
112
|
+
isAccessiblePath
|
|
113
|
+
};
|
|
114
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const NO_AUTH_PATHS = ["/login"];
|
|
1
|
+
export const NO_AUTH_PATHS = ["/login", "/reset-password"];
|
|
2
2
|
export const NO_AUTH_API_PATHS = ["/session", "/password/forgot", "/password/reset"];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineEventHandler, readBody, createError } from "h3";
|
|
1
|
+
import { defineEventHandler, readBody, createError, getHeader } from "h3";
|
|
2
2
|
import { sendPasswordResetLink } from "../../../services/password.js";
|
|
3
3
|
import { useRuntimeConfig } from "#imports";
|
|
4
4
|
export default defineEventHandler(async (event) => {
|
|
@@ -13,7 +13,10 @@ export default defineEventHandler(async (event) => {
|
|
|
13
13
|
});
|
|
14
14
|
}
|
|
15
15
|
try {
|
|
16
|
-
|
|
16
|
+
const host = getHeader(event, "host");
|
|
17
|
+
const protocol = getHeader(event, "x-forwarded-proto") || "http";
|
|
18
|
+
const baseUrl = host ? `${protocol}://${host}` : void 0;
|
|
19
|
+
await sendPasswordResetLink(email, options, baseUrl);
|
|
17
20
|
return { message: "If a user with that email exists, a password reset link has been sent." };
|
|
18
21
|
} catch (error) {
|
|
19
22
|
if (error instanceof Error) {
|
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{
|
|
2
|
-
user:
|
|
3
|
-
id: number;
|
|
4
|
-
email: string;
|
|
5
|
-
name: string;
|
|
6
|
-
role: string;
|
|
7
|
-
active: boolean;
|
|
8
|
-
created_at: string;
|
|
9
|
-
updated_at: string;
|
|
10
|
-
last_login_at?: string;
|
|
11
|
-
};
|
|
2
|
+
user: User;
|
|
12
3
|
}>>;
|
|
13
4
|
export default _default;
|
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
export declare const useNuxtUsersDatabase: () => Promise<{
|
|
2
2
|
database: import("db0").Database<import("db0").Connector<unknown>>;
|
|
3
3
|
options: {
|
|
4
|
-
tables:
|
|
5
|
-
|
|
6
|
-
users: string;
|
|
7
|
-
personalAccessTokens: string;
|
|
8
|
-
passwordResetTokens: string;
|
|
9
|
-
};
|
|
10
|
-
connector: {
|
|
11
|
-
name: import("nuxt-users/utils").DatabaseType;
|
|
12
|
-
options: import("nuxt-users/utils").DatabaseConfig;
|
|
13
|
-
};
|
|
4
|
+
tables: any;
|
|
5
|
+
connector: any;
|
|
14
6
|
};
|
|
15
7
|
}>;
|
|
@@ -11,7 +11,11 @@ export default defineEventHandler(async (event) => {
|
|
|
11
11
|
if (!isPageOrApiRoute) {
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
const noAuthPaths = [...NO_AUTH_PATHS];
|
|
15
|
+
if (options.passwordResetUrl && options.passwordResetUrl !== "/reset-password") {
|
|
16
|
+
noAuthPaths.push(options.passwordResetUrl);
|
|
17
|
+
}
|
|
18
|
+
if (noAuthPaths.includes(event.path)) {
|
|
15
19
|
console.log(`[Nuxt Users] server.middleware.auth.global: NO_AUTH_PATH: ${event.path}`);
|
|
16
20
|
return;
|
|
17
21
|
}
|
|
@@ -2,7 +2,7 @@ import type { ModuleOptions } from 'nuxt-users/utils';
|
|
|
2
2
|
/**
|
|
3
3
|
* Generates a password reset link and sends it to the user's email.
|
|
4
4
|
*/
|
|
5
|
-
export declare const sendPasswordResetLink: (email: string, options: ModuleOptions) => Promise<void>;
|
|
5
|
+
export declare const sendPasswordResetLink: (email: string, options: ModuleOptions, baseUrl?: string) => Promise<void>;
|
|
6
6
|
/**
|
|
7
7
|
* Resets the user's password using a valid token.
|
|
8
8
|
*/
|
|
@@ -3,7 +3,7 @@ import crypto from "node:crypto";
|
|
|
3
3
|
import bcrypt from "bcrypt";
|
|
4
4
|
import { findUserByEmail, updateUserPassword, useDb } from "../utils/index.js";
|
|
5
5
|
const TOKEN_EXPIRATION_HOURS = 1;
|
|
6
|
-
export const sendPasswordResetLink = async (email, options) => {
|
|
6
|
+
export const sendPasswordResetLink = async (email, options, baseUrl) => {
|
|
7
7
|
const user = await findUserByEmail(email, options);
|
|
8
8
|
if (!user) {
|
|
9
9
|
console.log(`[Nuxt Users] Password reset requested for non-existent email: ${email}`);
|
|
@@ -30,7 +30,8 @@ export const sendPasswordResetLink = async (email, options) => {
|
|
|
30
30
|
pass: options.mailer.auth.pass
|
|
31
31
|
}
|
|
32
32
|
});
|
|
33
|
-
const
|
|
33
|
+
const appBaseUrl = baseUrl || "http://localhost:3000";
|
|
34
|
+
const resetUrl = new URL(options.passwordResetUrl, appBaseUrl);
|
|
34
35
|
resetUrl.searchParams.set("token", token);
|
|
35
36
|
resetUrl.searchParams.set("email", email);
|
|
36
37
|
const resetLink = resetUrl.toString();
|
|
@@ -34,10 +34,10 @@ interface RuntimeModuleOptions {
|
|
|
34
34
|
*/
|
|
35
35
|
mailer?: MailerOptions;
|
|
36
36
|
/**
|
|
37
|
-
*
|
|
38
|
-
* @default '
|
|
37
|
+
* URL path for password reset page
|
|
38
|
+
* @default '/reset-password'
|
|
39
39
|
*/
|
|
40
|
-
|
|
40
|
+
passwordResetUrl?: string;
|
|
41
41
|
/**
|
|
42
42
|
* Skip database checks during module setup to prevent hanging
|
|
43
43
|
* @default false
|
|
@@ -114,7 +114,7 @@ interface ModuleOptions {
|
|
|
114
114
|
passwordResetTokens: string;
|
|
115
115
|
};
|
|
116
116
|
mailer?: MailerOptions;
|
|
117
|
-
|
|
117
|
+
passwordResetUrl: string;
|
|
118
118
|
auth: {
|
|
119
119
|
whitelist: string[];
|
|
120
120
|
tokenExpiration: number;
|
|
@@ -34,10 +34,10 @@ interface RuntimeModuleOptions {
|
|
|
34
34
|
*/
|
|
35
35
|
mailer?: MailerOptions;
|
|
36
36
|
/**
|
|
37
|
-
*
|
|
38
|
-
* @default '
|
|
37
|
+
* URL path for password reset page
|
|
38
|
+
* @default '/reset-password'
|
|
39
39
|
*/
|
|
40
|
-
|
|
40
|
+
passwordResetUrl?: string;
|
|
41
41
|
/**
|
|
42
42
|
* Skip database checks during module setup to prevent hanging
|
|
43
43
|
* @default false
|
|
@@ -114,7 +114,7 @@ interface ModuleOptions {
|
|
|
114
114
|
passwordResetTokens: string;
|
|
115
115
|
};
|
|
116
116
|
mailer?: MailerOptions;
|
|
117
|
-
|
|
117
|
+
passwordResetUrl: string;
|
|
118
118
|
auth: {
|
|
119
119
|
whitelist: string[];
|
|
120
120
|
tokenExpiration: number;
|
package/dist/utils.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { g as DatabaseConfig, f as DatabaseType, D as DisplayFieldsProps, L as LoginFormData, c as LoginFormProps, M as ModuleOptions, b as PasswordResetToken, e as Permission, P as PersonalAccessToken, d as ResetPasswordFormProps, R as RuntimeModuleOptions, U as User, a as UserWithoutPassword, h as defaultDisplayFields, i as defaultFieldLabels } from './shared/nuxt-users.
|
|
1
|
+
export { g as DatabaseConfig, f as DatabaseType, D as DisplayFieldsProps, L as LoginFormData, c as LoginFormProps, M as ModuleOptions, b as PasswordResetToken, e as Permission, P as PersonalAccessToken, d as ResetPasswordFormProps, R as RuntimeModuleOptions, U as User, a as UserWithoutPassword, h as defaultDisplayFields, i as defaultFieldLabels } from './shared/nuxt-users.CqP-FK1T.mjs';
|
|
2
2
|
|
|
3
3
|
interface PasswordValidationResult {
|
|
4
4
|
isValid: boolean;
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { g as DatabaseConfig, f as DatabaseType, D as DisplayFieldsProps, L as LoginFormData, c as LoginFormProps, M as ModuleOptions, b as PasswordResetToken, e as Permission, P as PersonalAccessToken, d as ResetPasswordFormProps, R as RuntimeModuleOptions, U as User, a as UserWithoutPassword, h as defaultDisplayFields, i as defaultFieldLabels } from './shared/nuxt-users.
|
|
1
|
+
export { g as DatabaseConfig, f as DatabaseType, D as DisplayFieldsProps, L as LoginFormData, c as LoginFormProps, M as ModuleOptions, b as PasswordResetToken, e as Permission, P as PersonalAccessToken, d as ResetPasswordFormProps, R as RuntimeModuleOptions, U as User, a as UserWithoutPassword, h as defaultDisplayFields, i as defaultFieldLabels } from './shared/nuxt-users.CqP-FK1T.js';
|
|
2
2
|
|
|
3
3
|
interface PasswordValidationResult {
|
|
4
4
|
isValid: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-users",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.23.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",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"lint": "eslint .",
|
|
67
67
|
"lint:fix": "eslint . --fix",
|
|
68
68
|
"pretest": "node -v | grep -q 'v22' || (echo 'Please use Node.js v22 for testing' && exit 1)",
|
|
69
|
-
"test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit",
|
|
69
|
+
"test:types": "yarn dev:prepare && vue-tsc --noEmit && cd playground && vue-tsc --noEmit",
|
|
70
70
|
"test:unit": "./scripts/test-unit.sh",
|
|
71
71
|
"test:sqlite": "./scripts/test-sqlite.sh",
|
|
72
72
|
"test:mysql": "./scripts/test-mysql.sh",
|