arkos 1.0.18-beta → 1.0.20-beta
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/dist/cjs/app.js +1 -1
- package/dist/cjs/app.js.map +1 -1
- package/dist/cjs/exports/middlewares/index.js +7 -0
- package/dist/cjs/exports/middlewares/index.js.map +1 -0
- package/dist/cjs/exports/utils/index.js.map +1 -1
- package/dist/cjs/modules/auth/auth.controller.js +38 -37
- package/dist/cjs/modules/auth/auth.controller.js.map +1 -1
- package/dist/cjs/modules/auth/auth.router.js +4 -5
- package/dist/cjs/modules/auth/auth.router.js.map +1 -1
- package/dist/cjs/modules/auth/auth.service.js +27 -24
- package/dist/cjs/modules/auth/auth.service.js.map +1 -1
- package/dist/cjs/modules/auth/utils/helpers/auth.controller.helpers.js +8 -12
- package/dist/cjs/modules/auth/utils/helpers/auth.controller.helpers.js.map +1 -1
- package/dist/cjs/modules/auth/utils/helpers/auth.helpers.js +19 -0
- package/dist/cjs/modules/auth/utils/helpers/auth.helpers.js.map +1 -0
- package/dist/cjs/modules/base/base.controller.js +2 -29
- package/dist/cjs/modules/base/base.controller.js.map +1 -1
- package/dist/cjs/modules/base/base.middlewares.js +42 -1
- package/dist/cjs/modules/base/base.middlewares.js.map +1 -1
- package/dist/cjs/modules/base/base.router.js +2 -2
- package/dist/cjs/modules/base/base.router.js.map +1 -1
- package/dist/cjs/modules/base/utils/helpers/base.helpers.js +183 -0
- package/dist/cjs/modules/base/utils/helpers/base.helpers.js.map +1 -0
- package/dist/cjs/modules/base/utils/helpers/base.router.helpers.js +2 -3
- package/dist/cjs/modules/base/utils/helpers/base.router.helpers.js.map +1 -1
- package/dist/cjs/modules/base/utils/helpers/base.service.helpers.js +9 -11
- package/dist/cjs/modules/base/utils/helpers/base.service.helpers.js.map +1 -1
- package/dist/cjs/modules/error-handler/error-handler.controller.js +2 -0
- package/dist/cjs/modules/error-handler/error-handler.controller.js.map +1 -1
- package/dist/cjs/modules/error-handler/utils/catch-async.js +1 -1
- package/dist/cjs/modules/error-handler/utils/catch-async.js.map +1 -1
- package/dist/cjs/modules/file-uploader/file-uploader.service.js +4 -4
- package/dist/cjs/modules/file-uploader/file-uploader.service.js.map +1 -1
- package/dist/cjs/modules/file-uploader/utils/helpers/file-uploader.helpers.js +7 -5
- package/dist/cjs/modules/file-uploader/utils/helpers/file-uploader.helpers.js.map +1 -1
- package/dist/cjs/server.js +1 -1
- package/dist/cjs/server.js.map +1 -1
- package/dist/cjs/types/arkos-config.js.map +1 -1
- package/dist/cjs/types/auth.js.map +1 -1
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/types/prisma-model-router-config.js +3 -0
- package/dist/cjs/types/prisma-model-router-config.js.map +1 -0
- package/dist/cjs/utils/features/api.features.js +3 -2
- package/dist/cjs/utils/features/api.features.js.map +1 -1
- package/dist/cjs/utils/helpers/api.features.helpers.js +4 -3
- package/dist/cjs/utils/helpers/api.features.helpers.js.map +1 -1
- package/dist/cjs/utils/helpers/base.controller.helpers.js +77 -35
- package/dist/cjs/utils/helpers/base.controller.helpers.js.map +1 -1
- package/dist/cjs/utils/helpers/change-case.helpers.js +3 -3
- package/dist/cjs/utils/helpers/change-case.helpers.js.map +1 -1
- package/dist/cjs/utils/helpers/fs.helpers.js +14 -45
- package/dist/cjs/utils/helpers/fs.helpers.js.map +1 -1
- package/dist/cjs/utils/helpers/models.helpers.js +35 -30
- package/dist/cjs/utils/helpers/models.helpers.js.map +1 -1
- package/dist/cjs/utils/helpers/prisma.helpers.js +5 -3
- package/dist/cjs/utils/helpers/prisma.helpers.js.map +1 -1
- package/dist/cjs/utils/scripts/export-prisma-types.js +3 -3
- package/dist/cjs/utils/scripts/export-prisma-types.js.map +1 -1
- package/dist/cjs/utils/scripts/generate-insomnia-collection.js +228 -0
- package/dist/cjs/utils/scripts/generate-insomnia-collection.js.map +1 -0
- package/dist/cjs/utils/scripts/generate-zod-schemas.js +4 -3
- package/dist/cjs/utils/scripts/generate-zod-schemas.js.map +1 -1
- package/dist/cjs/utils/scripts/index.js +12 -0
- package/dist/cjs/utils/scripts/index.js.map +1 -0
- package/dist/es2020/app.js +1 -1
- package/dist/es2020/app.js.map +1 -1
- package/dist/es2020/exports/middlewares/index.js +2 -0
- package/dist/es2020/exports/middlewares/index.js.map +1 -0
- package/dist/es2020/exports/utils/index.js.map +1 -1
- package/dist/es2020/modules/auth/auth.controller.js +39 -38
- package/dist/es2020/modules/auth/auth.controller.js.map +1 -1
- package/dist/es2020/modules/auth/auth.router.js +1 -2
- package/dist/es2020/modules/auth/auth.router.js.map +1 -1
- package/dist/es2020/modules/auth/auth.service.js +27 -24
- package/dist/es2020/modules/auth/auth.service.js.map +1 -1
- package/dist/es2020/modules/auth/utils/helpers/auth.controller.helpers.js +8 -12
- package/dist/es2020/modules/auth/utils/helpers/auth.controller.helpers.js.map +1 -1
- package/dist/es2020/modules/auth/utils/helpers/auth.helpers.js +12 -0
- package/dist/es2020/modules/auth/utils/helpers/auth.helpers.js.map +1 -0
- package/dist/es2020/modules/base/base.controller.js +2 -29
- package/dist/es2020/modules/base/base.controller.js.map +1 -1
- package/dist/es2020/modules/base/base.middlewares.js +38 -1
- package/dist/es2020/modules/base/base.middlewares.js.map +1 -1
- package/dist/es2020/modules/base/base.router.js +2 -2
- package/dist/es2020/modules/base/base.router.js.map +1 -1
- package/dist/es2020/modules/base/utils/helpers/base.helpers.js +177 -0
- package/dist/es2020/modules/base/utils/helpers/base.helpers.js.map +1 -0
- package/dist/es2020/modules/base/utils/helpers/base.router.helpers.js +1 -2
- package/dist/es2020/modules/base/utils/helpers/base.router.helpers.js.map +1 -1
- package/dist/es2020/modules/base/utils/helpers/base.service.helpers.js +9 -11
- package/dist/es2020/modules/base/utils/helpers/base.service.helpers.js.map +1 -1
- package/dist/es2020/modules/error-handler/error-handler.controller.js +2 -0
- package/dist/es2020/modules/error-handler/error-handler.controller.js.map +1 -1
- package/dist/es2020/modules/error-handler/utils/catch-async.js +1 -1
- package/dist/es2020/modules/error-handler/utils/catch-async.js.map +1 -1
- package/dist/es2020/modules/file-uploader/file-uploader.service.js +4 -4
- package/dist/es2020/modules/file-uploader/file-uploader.service.js.map +1 -1
- package/dist/es2020/modules/file-uploader/utils/helpers/file-uploader.helpers.js +7 -5
- package/dist/es2020/modules/file-uploader/utils/helpers/file-uploader.helpers.js.map +1 -1
- package/dist/es2020/server.js +1 -1
- package/dist/es2020/server.js.map +1 -1
- package/dist/es2020/types/arkos-config.js.map +1 -1
- package/dist/es2020/types/auth.js.map +1 -1
- package/dist/es2020/types/index.js.map +1 -1
- package/dist/es2020/types/prisma-model-router-config.js +2 -0
- package/dist/es2020/types/prisma-model-router-config.js.map +1 -0
- package/dist/es2020/utils/features/api.features.js +3 -2
- package/dist/es2020/utils/features/api.features.js.map +1 -1
- package/dist/es2020/utils/helpers/api.features.helpers.js +4 -3
- package/dist/es2020/utils/helpers/api.features.helpers.js.map +1 -1
- package/dist/es2020/utils/helpers/base.controller.helpers.js +75 -31
- package/dist/es2020/utils/helpers/base.controller.helpers.js.map +1 -1
- package/dist/es2020/utils/helpers/change-case.helpers.js +3 -3
- package/dist/es2020/utils/helpers/change-case.helpers.js.map +1 -1
- package/dist/es2020/utils/helpers/fs.helpers.js +13 -44
- package/dist/es2020/utils/helpers/fs.helpers.js.map +1 -1
- package/dist/es2020/utils/helpers/models.helpers.js +36 -31
- package/dist/es2020/utils/helpers/models.helpers.js.map +1 -1
- package/dist/es2020/utils/helpers/prisma.helpers.js +6 -4
- package/dist/es2020/utils/helpers/prisma.helpers.js.map +1 -1
- package/dist/es2020/utils/scripts/export-prisma-types.js +3 -3
- package/dist/es2020/utils/scripts/export-prisma-types.js.map +1 -1
- package/dist/es2020/utils/scripts/generate-insomnia-collection.js +189 -0
- package/dist/es2020/utils/scripts/generate-insomnia-collection.js.map +1 -0
- package/dist/es2020/utils/scripts/generate-zod-schemas.js +4 -3
- package/dist/es2020/utils/scripts/generate-zod-schemas.js.map +1 -1
- package/dist/es2020/utils/scripts/index.js +10 -0
- package/dist/es2020/utils/scripts/index.js.map +1 -0
- package/dist/types/exports/middlewares/index.d.ts +1 -0
- package/dist/types/exports/utils/index.d.ts +1 -0
- package/dist/types/modules/auth/auth.service.d.ts +3 -3
- package/dist/types/modules/auth/utils/helpers/auth.helpers.d.ts +2 -0
- package/dist/types/modules/base/base.middlewares.d.ts +6 -1
- package/dist/types/modules/base/utils/helpers/base.helpers.d.ts +5 -0
- package/dist/types/modules/base/utils/helpers/base.service.helpers.d.ts +1 -1
- package/dist/types/types/arkos-config.d.ts +5 -0
- package/dist/types/types/auth.d.ts +9 -8
- package/dist/types/types/index.d.ts +2 -1
- package/dist/types/types/prisma-model-router-config.d.ts +18 -0
- package/dist/types/utils/helpers/base.controller.helpers.d.ts +4 -6
- package/dist/types/utils/helpers/fs.helpers.d.ts +2 -2
- package/dist/types/utils/scripts/generate-insomnia-collection.d.ts +1 -0
- package/dist/types/utils/scripts/index.d.ts +2 -0
- package/package.json +55 -34
|
@@ -12,7 +12,7 @@ import AppError from "../error-handler/utils/app-error";
|
|
|
12
12
|
import authService from "./auth.service";
|
|
13
13
|
import { getBaseServices } from "../base/base.service";
|
|
14
14
|
import { getPrismaInstance } from "../../utils/helpers/prisma.helpers";
|
|
15
|
-
import { importPrismaModelModules } from "../../utils/helpers/models.helpers";
|
|
15
|
+
import { importPrismaModelModules, } from "../../utils/helpers/models.helpers";
|
|
16
16
|
import deepmerge from "../../utils/helpers/deepmerge.helper";
|
|
17
17
|
import arkosEnv from "../../utils/arkos-env";
|
|
18
18
|
import { getArkosConfig } from "../../server";
|
|
@@ -31,8 +31,8 @@ export const authControllerFactory = (...args_1) => __awaiter(void 0, [...args_1
|
|
|
31
31
|
getMe: catchAsync((req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
32
32
|
const user = yield baseServices["user"].findOne({ id: req.user.id }, stringifiedQueryOptions);
|
|
33
33
|
Object.keys(defaultExcludedUserFields).forEach((key) => {
|
|
34
|
-
if (
|
|
35
|
-
delete
|
|
34
|
+
if (user)
|
|
35
|
+
delete user[key];
|
|
36
36
|
});
|
|
37
37
|
if (middlewares === null || middlewares === void 0 ? void 0 : middlewares.afterGetMe) {
|
|
38
38
|
req.responseData = { data: user };
|
|
@@ -46,15 +46,15 @@ export const authControllerFactory = (...args_1) => __awaiter(void 0, [...args_1
|
|
|
46
46
|
throw new AppError("In order to update password use the update-password endpoint.", 400);
|
|
47
47
|
const user = yield baseServices["user"].updateOne({ id: req.user.id }, req.body, stringifiedQueryOptions);
|
|
48
48
|
Object.keys(defaultExcludedUserFields).forEach((key) => {
|
|
49
|
-
if (
|
|
50
|
-
delete
|
|
49
|
+
if (user)
|
|
50
|
+
delete user[key];
|
|
51
51
|
});
|
|
52
52
|
if (middlewares === null || middlewares === void 0 ? void 0 : middlewares.afterGetMe) {
|
|
53
53
|
req.responseData = user;
|
|
54
54
|
req.responseStatus = 200;
|
|
55
55
|
return next();
|
|
56
56
|
}
|
|
57
|
-
res.status(200).json({ data:
|
|
57
|
+
res.status(200).json({ data: user });
|
|
58
58
|
})),
|
|
59
59
|
logout: catchAsync((req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
60
60
|
res.cookie("arkos_access_token", "no-token", {
|
|
@@ -69,18 +69,17 @@ export const authControllerFactory = (...args_1) => __awaiter(void 0, [...args_1
|
|
|
69
69
|
res.status(204).json();
|
|
70
70
|
})),
|
|
71
71
|
login: catchAsync((req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
72
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
72
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
73
73
|
const authConfigs = (_a = getArkosConfig()) === null || _a === void 0 ? void 0 : _a.authentication;
|
|
74
74
|
const usernameField = determineUsernameField(req);
|
|
75
|
-
const
|
|
76
|
-
const usernameValue = req.body[
|
|
75
|
+
const lastField = usernameField.split(".")[usernameField.split(".").length - 1];
|
|
76
|
+
const usernameValue = req.body[lastField];
|
|
77
77
|
const { password } = req.body;
|
|
78
|
-
if (!usernameValue || !password)
|
|
79
|
-
return next(new AppError(`Please provide ${
|
|
80
|
-
}
|
|
78
|
+
if (!usernameValue || !password)
|
|
79
|
+
return next(new AppError(`Please provide both ${lastField} and password`, 400));
|
|
81
80
|
const prisma = getPrismaInstance();
|
|
82
81
|
let whereClause;
|
|
83
|
-
if (usernameField.includes(".")) {
|
|
82
|
+
if ((_b = usernameField === null || usernameField === void 0 ? void 0 : usernameField.includes) === null || _b === void 0 ? void 0 : _b.call(usernameField, ".")) {
|
|
84
83
|
const valueToFind = getNestedValue(req.body, usernameField);
|
|
85
84
|
if (valueToFind === undefined) {
|
|
86
85
|
return next(new AppError(`Invalid ${usernameField} provided`, 400));
|
|
@@ -95,46 +94,46 @@ export const authControllerFactory = (...args_1) => __awaiter(void 0, [...args_1
|
|
|
95
94
|
});
|
|
96
95
|
if (!user ||
|
|
97
96
|
!(yield authService.isCorrectPassword(password, user.password))) {
|
|
98
|
-
return next(new AppError(`Incorrect ${
|
|
97
|
+
return next(new AppError(`Incorrect ${lastField} or password`, 401));
|
|
99
98
|
}
|
|
100
99
|
const token = authService.signJwtToken(user.id);
|
|
101
100
|
const cookieOptions = {
|
|
102
101
|
expires: new Date(Date.now() +
|
|
103
|
-
Number(toMs(((
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
60 *
|
|
108
|
-
1000),
|
|
109
|
-
httpOnly: ((_d = (_c = authConfigs === null || authConfigs === void 0 ? void 0 : authConfigs.jwt) === null || _c === void 0 ? void 0 : _c.cookie) === null || _d === void 0 ? void 0 : _d.httpOnly) ||
|
|
102
|
+
Number(toMs(((_c = authConfigs === null || authConfigs === void 0 ? void 0 : authConfigs.jwt) === null || _c === void 0 ? void 0 : _c.expiresIn) ||
|
|
103
|
+
process.env.JWT_EXPIRES_IN ||
|
|
104
|
+
arkosEnv.JWT_EXPIRES_IN))),
|
|
105
|
+
httpOnly: ((_e = (_d = authConfigs === null || authConfigs === void 0 ? void 0 : authConfigs.jwt) === null || _d === void 0 ? void 0 : _d.cookie) === null || _e === void 0 ? void 0 : _e.httpOnly) ||
|
|
110
106
|
process.env.JWT_COOKIE_HTTP_ONLY === "true" ||
|
|
111
107
|
true,
|
|
112
|
-
secure: ((
|
|
108
|
+
secure: ((_g = (_f = authConfigs === null || authConfigs === void 0 ? void 0 : authConfigs.jwt) === null || _f === void 0 ? void 0 : _f.cookie) === null || _g === void 0 ? void 0 : _g.secure) ||
|
|
113
109
|
process.env.JWT_COOKIE_SECURE === "true" ||
|
|
114
110
|
req.secure ||
|
|
115
111
|
req.headers["x-forwarded-proto"] === "https",
|
|
116
|
-
sameSite: ((
|
|
112
|
+
sameSite: ((_j = (_h = authConfigs === null || authConfigs === void 0 ? void 0 : authConfigs.jwt) === null || _h === void 0 ? void 0 : _h.cookie) === null || _j === void 0 ? void 0 : _j.sameSite) ||
|
|
117
113
|
process.env.JWT_COOKIE_SAME_SITE ||
|
|
118
114
|
process.env.NODE_ENV === "production"
|
|
119
115
|
? "none"
|
|
120
116
|
: "lax",
|
|
121
117
|
};
|
|
122
|
-
if (
|
|
118
|
+
if (((_k = authConfigs === null || authConfigs === void 0 ? void 0 : authConfigs.login) === null || _k === void 0 ? void 0 : _k.sendAccessTokenThrough) === "response-only" ||
|
|
119
|
+
((_l = authConfigs === null || authConfigs === void 0 ? void 0 : authConfigs.login) === null || _l === void 0 ? void 0 : _l.sendAccessTokenThrough) === "both") {
|
|
123
120
|
req.responseData = { accessToken: token };
|
|
121
|
+
}
|
|
122
|
+
else if (((_m = authConfigs === null || authConfigs === void 0 ? void 0 : authConfigs.login) === null || _m === void 0 ? void 0 : _m.sendAccessTokenThrough) === "cookie-only" ||
|
|
123
|
+
((_o = authConfigs === null || authConfigs === void 0 ? void 0 : authConfigs.login) === null || _o === void 0 ? void 0 : _o.sendAccessTokenThrough) === "both")
|
|
124
|
+
res.cookie("arkos_access_token", token, cookieOptions);
|
|
125
|
+
if (middlewares === null || middlewares === void 0 ? void 0 : middlewares.afterLogin) {
|
|
126
|
+
req.additionalData = { user };
|
|
124
127
|
req.responseStatus = 200;
|
|
125
128
|
return next();
|
|
126
129
|
}
|
|
127
|
-
if (((
|
|
128
|
-
|
|
130
|
+
if (((_p = authConfigs === null || authConfigs === void 0 ? void 0 : authConfigs.login) === null || _p === void 0 ? void 0 : _p.sendAccessTokenThrough) === "response-only" ||
|
|
131
|
+
((_q = authConfigs === null || authConfigs === void 0 ? void 0 : authConfigs.login) === null || _q === void 0 ? void 0 : _q.sendAccessTokenThrough) === "both") {
|
|
132
|
+
res.status(200).json(req.responseData);
|
|
129
133
|
}
|
|
130
|
-
else if (((
|
|
131
|
-
|
|
134
|
+
else if (((_r = authConfigs === null || authConfigs === void 0 ? void 0 : authConfigs.login) === null || _r === void 0 ? void 0 : _r.sendAccessTokenThrough) === "cookie-only" ||
|
|
135
|
+
((_s = authConfigs === null || authConfigs === void 0 ? void 0 : authConfigs.login) === null || _s === void 0 ? void 0 : _s.sendAccessTokenThrough) === "both")
|
|
132
136
|
res.status(200).send();
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
res.cookie("arkos_access_token", token, cookieOptions);
|
|
136
|
-
res.status(200).json({ accessToken: token });
|
|
137
|
-
}
|
|
138
137
|
})),
|
|
139
138
|
signup: catchAsync((req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
140
139
|
const userService = baseServices["user"];
|
|
@@ -150,7 +149,7 @@ export const authControllerFactory = (...args_1) => __awaiter(void 0, [...args_1
|
|
|
150
149
|
res.status(201).json({ data: user });
|
|
151
150
|
})),
|
|
152
151
|
updatePassword: catchAsync((req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
153
|
-
var _a
|
|
152
|
+
var _a;
|
|
154
153
|
const { currentPassword, newPassword } = req.body;
|
|
155
154
|
if (!currentPassword || !newPassword)
|
|
156
155
|
return next(new AppError("currentPassword and newPassword are required", 400));
|
|
@@ -158,12 +157,14 @@ export const authControllerFactory = (...args_1) => __awaiter(void 0, [...args_1
|
|
|
158
157
|
if (!user || (user === null || user === void 0 ? void 0 : user.isActive) === false || (user === null || user === void 0 ? void 0 : user.deletedSelfAccountAt))
|
|
159
158
|
return next(new AppError("User not found!", 404));
|
|
160
159
|
const isPasswordCorrect = yield authService.isCorrectPassword(String(currentPassword), String(user.password));
|
|
160
|
+
const configs = getArkosConfig();
|
|
161
|
+
const initAuthConfigs = configs === null || configs === void 0 ? void 0 : configs.authentication;
|
|
161
162
|
if (!isPasswordCorrect)
|
|
162
163
|
return next(new AppError("Current password is incorrect.", 400));
|
|
163
|
-
if (!authService.isPasswordStrong(String(newPassword))
|
|
164
|
-
|
|
165
|
-
return next(new AppError(((
|
|
166
|
-
"
|
|
164
|
+
if (!authService.isPasswordStrong(String(newPassword)) &&
|
|
165
|
+
!(configs === null || configs === void 0 ? void 0 : configs.validation)) {
|
|
166
|
+
return next(new AppError(((_a = initAuthConfigs === null || initAuthConfigs === void 0 ? void 0 : initAuthConfigs.passwordValidation) === null || _a === void 0 ? void 0 : _a.message) ||
|
|
167
|
+
"The new password must contain at least one uppercase letter, one lowercase letter, and one number", 400));
|
|
167
168
|
}
|
|
168
169
|
const prisma = getPrismaInstance();
|
|
169
170
|
yield prisma.user.update({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.controller.js","sourceRoot":"","sources":["../../../../src/modules/auth/auth.controller.ts"],"names":[],"mappings":"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","sourcesContent":["import catchAsync from \"../error-handler/utils/catch-async\";\nimport AppError from \"../error-handler/utils/app-error\";\nimport { CookieOptions } from \"express\";\nimport { ArkosRequest, ArkosResponse, ArkosNextFunction } from \"../../types\";\nimport authService from \"./auth.service\";\nimport { getBaseServices } from \"../base/base.service\";\nimport { User } from \"../../types\";\nimport { getPrismaInstance } from \"../../utils/helpers/prisma.helpers\";\nimport { importPrismaModelModules } from \"../../utils/helpers/models.helpers\";\nimport deepmerge from \"../../utils/helpers/deepmerge.helper\";\nimport arkosEnv from \"../../utils/arkos-env\";\nimport { getArkosConfig } from \"../../server\";\nimport {\n createPrismaWhereClause,\n determineUsernameField,\n getNestedValue,\n MsDuration,\n toMs,\n} from \"./utils/helpers/auth.controller.helpers\";\n\n/**\n * Default fields to exclude from user object when returning to client\n */\nexport const defaultExcludedUserFields = {\n password: false,\n};\n\n/**\n * Factory function to create authentication controller with configurable middlewares\n *\n * @param middlewares - Optional middleware functions to execute after controller actions\n * @returns An object containing all authentication controller methods\n */\nexport const authControllerFactory = async (middlewares: any = {}) => {\n const baseServices = getBaseServices();\n let prismaQueryOptions: Record<string, any> = {};\n\n const userModules = await importPrismaModelModules(\"user\");\n if (userModules) prismaQueryOptions = userModules?.prismaQueryOptions || {};\n\n const stringifiedQueryOptions = JSON.stringify(\n deepmerge(\n prismaQueryOptions?.queryOptions || {},\n prismaQueryOptions?.findOne || {}\n ) || {}\n );\n\n return {\n /**\n * Retrieves the current authenticated user's information\n */\n getMe: catchAsync(\n async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction\n ) => {\n const user = await baseServices[\"user\"].findOne(\n { id: req.user!.id },\n stringifiedQueryOptions\n );\n\n Object.keys(defaultExcludedUserFields).forEach((key) => {\n if (req.user) delete req.user[key as keyof User];\n });\n\n if (middlewares?.afterGetMe) {\n req.responseData = { data: user };\n req.responseStatus = 200;\n return next();\n }\n\n res.status(200).json({ data: user });\n }\n ),\n\n /**\n * Updates the current authenticated user's information\n */\n updateMe: catchAsync(\n async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction\n ) => {\n if (\"password\" in req.body)\n throw new AppError(\n \"In order to update password use the update-password endpoint.\",\n 400\n );\n\n const user = await baseServices[\"user\"].updateOne(\n { id: req.user!.id },\n req.body,\n stringifiedQueryOptions\n );\n\n Object.keys(defaultExcludedUserFields).forEach((key) => {\n if (req.user) delete req.user[key as keyof User];\n });\n\n if (middlewares?.afterGetMe) {\n req.responseData = user;\n req.responseStatus = 200;\n return next();\n }\n\n res.status(200).json({ data: req.user });\n }\n ),\n\n /**\n * Logs out the current user by invalidating their access token cookie\n */\n logout: catchAsync(\n async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction\n ) => {\n res.cookie(\"arkos_access_token\", \"no-token\", {\n expires: new Date(Date.now() + 10 * 1000),\n httpOnly: true,\n });\n\n if (middlewares?.afterLogout) {\n req.responseData = null;\n req.responseStatus = 204;\n return next();\n }\n\n res.status(204).json();\n }\n ),\n\n /**\n * Authenticates a user using configurable username field and password\n * Username field can be specified in query parameter or config\n * Supports nested fields and array queries (e.g., \"profile.nickname\", \"phones.some.number\")\n */\n login: catchAsync(\n async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction\n ) => {\n const authConfigs = getArkosConfig()?.authentication;\n\n const usernameField = determineUsernameField(req);\n\n // For the error message, we only care about the top-level field name\n const topLevelField = usernameField.split(\".\")[0];\n const usernameValue = req.body[topLevelField];\n const { password } = req.body;\n\n if (!usernameValue || !password) {\n return next(\n new AppError(`Please provide ${topLevelField} and password`, 400)\n );\n }\n\n const prisma = getPrismaInstance();\n\n // Create appropriate where clause for the query\n let whereClause: Record<string, any>;\n\n if (usernameField.includes(\".\")) {\n // For nested paths, we need to extract the actual value to search for\n const valueToFind = getNestedValue(req.body, usernameField);\n if (valueToFind === undefined) {\n return next(new AppError(`Invalid ${usernameField} provided`, 400));\n }\n whereClause = createPrismaWhereClause(usernameField, valueToFind);\n } else {\n // Simple field case\n whereClause = { [usernameField]: usernameValue };\n }\n\n // Use findFirst instead of findUnique for complex queries\n const user = await (prisma as any).user.findFirst({\n where: whereClause,\n });\n\n if (\n !user ||\n !(await authService.isCorrectPassword(password, user.password))\n ) {\n return next(\n new AppError(\n `Incorrect ${topLevelField.toLowerCase()} or password`,\n 401\n )\n );\n }\n\n const token = authService.signJwtToken(user.id!);\n\n const cookieOptions: CookieOptions = {\n expires: new Date(\n Date.now() +\n Number(\n toMs(\n authConfigs?.jwt?.expiresIn ||\n (arkosEnv.JWT_EXPIRES_IN as MsDuration)\n )\n ) *\n 24 *\n 60 *\n 60 *\n 1000\n ),\n httpOnly:\n authConfigs?.jwt?.cookie?.httpOnly ||\n process.env.JWT_COOKIE_HTTP_ONLY === \"true\" ||\n true,\n secure:\n authConfigs?.jwt?.cookie?.secure ||\n process.env.JWT_COOKIE_SECURE === \"true\" ||\n req.secure ||\n req.headers[\"x-forwarded-proto\"] === \"https\",\n sameSite:\n authConfigs?.jwt?.cookie?.sameSite ||\n process.env.JWT_COOKIE_SAME_SITE ||\n process.env.NODE_ENV === \"production\"\n ? \"none\"\n : \"lax\",\n };\n\n if (middlewares?.afterLogin) {\n req.responseData = { accessToken: token };\n req.responseStatus = 200;\n return next();\n }\n\n if (authConfigs?.login?.sendAccessTokenThrough === \"response-only\") {\n res.status(200).json({ accessToken: token });\n } else if (\n authConfigs?.login?.sendAccessTokenThrough === \"cookie-only\"\n ) {\n res.cookie(\"arkos_access_token\", token, cookieOptions);\n res.status(200).send();\n } else {\n res.cookie(\"arkos_access_token\", token, cookieOptions);\n res.status(200).json({ accessToken: token });\n }\n }\n ),\n\n /**\n * Creates a new user account\n */\n signup: catchAsync(\n async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction\n ) => {\n const userService = baseServices[\"user\"];\n\n const user = await userService.createOne(\n req.body,\n stringifiedQueryOptions\n );\n\n if (middlewares?.afterSignup) {\n req.responseData = { data: user };\n req.responseStatus = 201;\n return next();\n }\n\n Object.keys(defaultExcludedUserFields).forEach((key) => {\n delete user[key as keyof User];\n });\n\n res.status(201).json({ data: user });\n }\n ),\n\n /**\n * Updates the password of the authenticated user\n */\n updatePassword: catchAsync(\n async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction\n ) => {\n const { currentPassword, newPassword } = req.body;\n\n if (!currentPassword || !newPassword)\n return next(\n new AppError(\"currentPassword and newPassword are required\", 400)\n );\n\n const user = req.user;\n\n if (!user || user?.isActive === false || user?.deletedSelfAccountAt)\n return next(new AppError(\"User not found!\", 404));\n\n // Check if the current password is correct\n const isPasswordCorrect = await authService.isCorrectPassword(\n String(currentPassword),\n String(user.password)\n );\n\n if (!isPasswordCorrect)\n return next(new AppError(\"Current password is incorrect.\", 400));\n\n // Check password strength (optional but recommended)\n if (!authService.isPasswordStrong(String(newPassword))) {\n const initAuthConfigs = getArkosConfig()?.authentication;\n\n return next(\n new AppError(\n initAuthConfigs?.passwordValidation?.message ||\n \"Password must contain at least one uppercase letter, one lowercase letter, and one number\",\n 400\n )\n );\n }\n\n const prisma = getPrismaInstance();\n\n // Update the password\n await (prisma as any).user.update({\n where: { id: user.id },\n data: {\n password: await authService.hashPassword(newPassword),\n passwordChangedAt: new Date(),\n },\n });\n\n if (middlewares?.afterUpdatePassword) {\n (req as any).additionalData = {\n user,\n };\n req.responseData = {\n status: \"success\",\n message: \"Password updated successfully!\",\n };\n req.responseStatus = 200;\n return next();\n }\n\n res.status(200).json({\n status: \"success\",\n message: \"Password updated successfully!\",\n });\n }\n ),\n };\n};\n"]}
|
|
1
|
+
{"version":3,"file":"auth.controller.js","sourceRoot":"","sources":["../../../../src/modules/auth/auth.controller.ts"],"names":[],"mappings":"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","sourcesContent":["import catchAsync from \"../error-handler/utils/catch-async\";\nimport AppError from \"../error-handler/utils/app-error\";\nimport { CookieOptions } from \"express\";\nimport { ArkosRequest, ArkosResponse, ArkosNextFunction } from \"../../types\";\nimport authService from \"./auth.service\";\nimport { getBaseServices } from \"../base/base.service\";\nimport { User } from \"../../types\";\nimport { getPrismaInstance } from \"../../utils/helpers/prisma.helpers\";\nimport {\n getModelModules,\n importPrismaModelModules,\n} from \"../../utils/helpers/models.helpers\";\nimport deepmerge from \"../../utils/helpers/deepmerge.helper\";\nimport arkosEnv from \"../../utils/arkos-env\";\nimport { getArkosConfig } from \"../../server\";\nimport {\n createPrismaWhereClause,\n determineUsernameField,\n getNestedValue,\n MsDuration,\n toMs,\n} from \"./utils/helpers/auth.controller.helpers\";\n\n/**\n * Default fields to exclude from user object when returning to client\n */\nexport const defaultExcludedUserFields = {\n password: false,\n};\n\n/**\n * Factory function to create authentication controller with configurable middlewares\n *\n * @param middlewares - Optional middleware functions to execute after controller actions\n * @returns An object containing all authentication controller methods\n */\nexport const authControllerFactory = async (middlewares: any = {}) => {\n const baseServices = getBaseServices();\n let prismaQueryOptions: Record<string, any> = {};\n\n const userModules = await importPrismaModelModules(\"user\");\n if (userModules) prismaQueryOptions = userModules?.prismaQueryOptions || {};\n\n const stringifiedQueryOptions = JSON.stringify(\n deepmerge(\n prismaQueryOptions?.queryOptions || {},\n prismaQueryOptions?.findOne || {}\n ) || {}\n );\n\n return {\n /**\n * Retrieves the current authenticated user's information\n */\n getMe: catchAsync(\n async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction\n ) => {\n const user = await baseServices[\"user\"].findOne(\n { id: req.user!.id },\n stringifiedQueryOptions\n );\n\n Object.keys(defaultExcludedUserFields).forEach((key) => {\n if (user) delete user[key as keyof User];\n });\n\n if (middlewares?.afterGetMe) {\n req.responseData = { data: user };\n req.responseStatus = 200;\n return next();\n }\n\n res.status(200).json({ data: user });\n }\n ),\n\n /**\n * Updates the current authenticated user's information\n */\n updateMe: catchAsync(\n async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction\n ) => {\n if (\"password\" in req.body)\n throw new AppError(\n \"In order to update password use the update-password endpoint.\",\n 400\n );\n\n const user = await baseServices[\"user\"].updateOne(\n { id: req.user!.id },\n req.body,\n stringifiedQueryOptions\n );\n\n Object.keys(defaultExcludedUserFields).forEach((key) => {\n if (user) delete user[key as keyof User];\n });\n\n if (middlewares?.afterGetMe) {\n req.responseData = user;\n req.responseStatus = 200;\n return next();\n }\n\n res.status(200).json({ data: user });\n }\n ),\n\n /**\n * Logs out the current user by invalidating their access token cookie\n */\n logout: catchAsync(\n async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction\n ) => {\n res.cookie(\"arkos_access_token\", \"no-token\", {\n expires: new Date(Date.now() + 10 * 1000),\n httpOnly: true,\n });\n\n if (middlewares?.afterLogout) {\n req.responseData = null;\n req.responseStatus = 204;\n return next();\n }\n\n res.status(204).json();\n }\n ),\n\n /**\n * Authenticates a user using configurable username field and password\n * Username field can be specified in query parameter or config\n * Supports nested fields and array queries (e.g., \"profile.nickname\", \"phones.some.number\")\n */\n login: catchAsync(\n async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction\n ) => {\n const authConfigs = getArkosConfig()?.authentication;\n\n const usernameField = determineUsernameField(req);\n\n // For the error message, we only care about the top-level field name\n const lastField =\n usernameField.split(\".\")[usernameField.split(\".\").length - 1];\n\n const usernameValue = req.body[lastField];\n\n const { password } = req.body;\n\n if (!usernameValue || !password)\n return next(\n new AppError(`Please provide both ${lastField} and password`, 400)\n );\n\n const prisma = getPrismaInstance();\n\n // Create appropriate where clause for the query\n let whereClause: Record<string, any>;\n\n if (usernameField?.includes?.(\".\")) {\n // For nested paths, we need to extract the actual value to search for\n const valueToFind = getNestedValue(req.body, usernameField);\n if (valueToFind === undefined) {\n return next(new AppError(`Invalid ${usernameField} provided`, 400));\n }\n whereClause = createPrismaWhereClause(usernameField, valueToFind);\n } else {\n // Simple field case\n whereClause = { [usernameField]: usernameValue };\n }\n\n // Use findFirst instead of findUnique for complex queries\n const user = await (prisma as any).user.findFirst({\n where: whereClause,\n // select: {\n // id: true,\n // password: true,\n // },\n });\n\n if (\n !user ||\n !(await authService.isCorrectPassword(password, user.password))\n ) {\n return next(new AppError(`Incorrect ${lastField} or password`, 401));\n }\n\n const token = authService.signJwtToken(user.id!);\n\n const cookieOptions: CookieOptions = {\n expires: new Date(\n Date.now() +\n Number(\n toMs(\n authConfigs?.jwt?.expiresIn ||\n (process.env.JWT_EXPIRES_IN as MsDuration) ||\n (arkosEnv.JWT_EXPIRES_IN as MsDuration)\n )\n )\n ),\n httpOnly:\n authConfigs?.jwt?.cookie?.httpOnly ||\n process.env.JWT_COOKIE_HTTP_ONLY === \"true\" ||\n true,\n secure:\n authConfigs?.jwt?.cookie?.secure ||\n process.env.JWT_COOKIE_SECURE === \"true\" ||\n req.secure ||\n req.headers[\"x-forwarded-proto\"] === \"https\",\n sameSite:\n authConfigs?.jwt?.cookie?.sameSite ||\n process.env.JWT_COOKIE_SAME_SITE ||\n process.env.NODE_ENV === \"production\"\n ? \"none\"\n : \"lax\",\n };\n\n if (\n authConfigs?.login?.sendAccessTokenThrough === \"response-only\" ||\n authConfigs?.login?.sendAccessTokenThrough === \"both\"\n ) {\n req.responseData = { accessToken: token };\n } else if (\n authConfigs?.login?.sendAccessTokenThrough === \"cookie-only\" ||\n authConfigs?.login?.sendAccessTokenThrough === \"both\"\n )\n res.cookie(\"arkos_access_token\", token, cookieOptions);\n\n if (middlewares?.afterLogin) {\n req.additionalData = { user };\n req.responseStatus = 200;\n return next();\n }\n\n if (\n authConfigs?.login?.sendAccessTokenThrough === \"response-only\" ||\n authConfigs?.login?.sendAccessTokenThrough === \"both\"\n ) {\n res.status(200).json(req.responseData);\n } else if (\n authConfigs?.login?.sendAccessTokenThrough === \"cookie-only\" ||\n authConfigs?.login?.sendAccessTokenThrough === \"both\"\n )\n res.status(200).send();\n }\n ),\n\n /**\n * Creates a new user account\n */\n signup: catchAsync(\n async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction\n ) => {\n const userService = baseServices[\"user\"];\n\n const user = await userService.createOne(\n req.body,\n stringifiedQueryOptions\n );\n\n if (middlewares?.afterSignup) {\n req.responseData = { data: user };\n req.responseStatus = 201;\n return next();\n }\n\n Object.keys(defaultExcludedUserFields).forEach((key) => {\n delete user[key as keyof User];\n });\n\n res.status(201).json({ data: user });\n }\n ),\n\n /**\n * Updates the password of the authenticated user\n */\n updatePassword: catchAsync(\n async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction\n ) => {\n const { currentPassword, newPassword } = req.body;\n\n if (!currentPassword || !newPassword)\n return next(\n new AppError(\"currentPassword and newPassword are required\", 400)\n );\n\n const user = req.user;\n\n if (!user || user?.isActive === false || user?.deletedSelfAccountAt)\n return next(new AppError(\"User not found!\", 404));\n\n // Check if the current password is correct\n const isPasswordCorrect = await authService.isCorrectPassword(\n String(currentPassword),\n String(user.password)\n );\n\n const configs = getArkosConfig();\n const initAuthConfigs = configs?.authentication;\n // const modules = getModelModules(\"auth\");\n\n if (!isPasswordCorrect)\n return next(new AppError(\"Current password is incorrect.\", 400));\n\n // Check password strength (optional but recommended)\n if (\n !authService.isPasswordStrong(String(newPassword)) &&\n !configs?.validation\n ) {\n return next(\n new AppError(\n initAuthConfigs?.passwordValidation?.message ||\n \"The new password must contain at least one uppercase letter, one lowercase letter, and one number\",\n 400\n )\n );\n }\n\n const prisma = getPrismaInstance();\n\n // Update the password\n await (prisma as any).user.update({\n where: { id: user.id },\n data: {\n password: await authService.hashPassword(newPassword),\n passwordChangedAt: new Date(),\n },\n });\n\n if (middlewares?.afterUpdatePassword) {\n req.additionalData = {\n user,\n };\n req.responseData = {\n status: \"success\",\n message: \"Password updated successfully!\",\n };\n req.responseStatus = 200;\n return next();\n }\n\n res.status(200).json({\n status: \"success\",\n message: \"Password updated successfully!\",\n });\n }\n ),\n };\n};\n"]}
|
|
@@ -12,9 +12,8 @@ import { authControllerFactory } from "./auth.controller";
|
|
|
12
12
|
import authService from "./auth.service";
|
|
13
13
|
import rateLimit from "express-rate-limit";
|
|
14
14
|
import { importPrismaModelModules } from "../../utils/helpers/models.helpers";
|
|
15
|
-
import { sendResponse } from "../base/base.middlewares";
|
|
15
|
+
import { handleRequestBodyValidationAndTransformation, sendResponse, } from "../base/base.middlewares";
|
|
16
16
|
import deepmerge from "../../utils/helpers/deepmerge.helper";
|
|
17
|
-
import { handleRequestBodyValidationAndTransformation } from "../../utils/helpers/base.controller.helpers";
|
|
18
17
|
const router = Router();
|
|
19
18
|
export function getAuthRouter(arkosConfigs) {
|
|
20
19
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.router.js","sourceRoot":"","sources":["../../../../src/modules/auth/auth.router.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,WAAW,MAAM,gBAAgB,CAAC;AACzC,OAAO,SAAS,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,wBAAwB,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,
|
|
1
|
+
{"version":3,"file":"auth.router.js","sourceRoot":"","sources":["../../../../src/modules/auth/auth.router.ts"],"names":[],"mappings":"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","sourcesContent":["import { Router } from \"express\";\nimport { authControllerFactory } from \"./auth.controller\";\nimport authService from \"./auth.service\";\nimport rateLimit from \"express-rate-limit\";\nimport { importPrismaModelModules } from \"../../utils/helpers/models.helpers\";\nimport {\n handleRequestBodyValidationAndTransformation,\n sendResponse,\n} from \"../base/base.middlewares\";\nimport { ArkosConfig } from \"../../types/arkos-config\";\nimport deepmerge from \"../../utils/helpers/deepmerge.helper\";\n\nconst router: Router = Router();\n\nexport async function getAuthRouter(arkosConfigs: ArkosConfig) {\n const { middlewares } = await importPrismaModelModules(\"auth\");\n const authController = await authControllerFactory(middlewares);\n\n router\n .get(\n \"/users/me\",\n authService.authenticate,\n middlewares?.beforeGetMe ?? authController.getMe,\n middlewares?.beforeGetMe\n ? authController.getMe\n : middlewares?.afterGetMe ?? sendResponse,\n middlewares?.beforeGetMe && middlewares?.afterGetMe\n ? middlewares?.afterGetMe\n : sendResponse,\n sendResponse\n )\n .patch(\n \"/users/me\",\n authService.authenticate,\n handleRequestBodyValidationAndTransformation(\"auth\", \"updateMe\"),\n middlewares?.beforeGetMe ?? authController.getMe,\n middlewares?.beforeGetMe\n ? authController.getMe\n : middlewares?.afterGetMe ?? sendResponse,\n middlewares?.beforeGetMe && middlewares?.afterGetMe\n ? middlewares?.afterGetMe\n : sendResponse,\n sendResponse\n )\n .delete(\n \"/users/me\",\n authService.authenticate,\n middlewares?.beforeGetMe ?? authController.getMe,\n middlewares?.beforeGetMe\n ? authController.getMe\n : middlewares?.afterGetMe ?? sendResponse,\n middlewares?.beforeGetMe && middlewares?.afterGetMe\n ? middlewares?.afterGetMe\n : sendResponse,\n sendResponse\n );\n\n router.use(\n rateLimit(\n deepmerge(\n {\n windowMs: 5000,\n limit: 10,\n standardHeaders: \"draft-7\",\n legacyHeaders: false,\n },\n arkosConfigs?.authentication?.requestRateLimitOptions || {}\n )\n )\n );\n\n router.post(\n \"/auth/login\",\n handleRequestBodyValidationAndTransformation(\"auth\", \"login\"),\n middlewares?.beforeLogin ?? authController.login,\n middlewares?.beforeLogin\n ? authController.login\n : middlewares?.afterLogin ?? sendResponse,\n middlewares?.beforeLogin && middlewares?.afterLogin\n ? middlewares?.afterLogin\n : sendResponse,\n sendResponse\n );\n\n router.delete(\n \"/auth/logout\",\n authService.authenticate,\n middlewares?.beforeLogout ?? authController.logout,\n middlewares?.beforeLogout\n ? authController.logout\n : middlewares?.afterLogout ?? sendResponse,\n middlewares?.beforeLogout && middlewares?.afterLogout\n ? middlewares?.afterLogout\n : sendResponse,\n sendResponse\n );\n\n router.post(\n \"/auth/signup\",\n handleRequestBodyValidationAndTransformation(\"auth\", \"signup\"),\n middlewares?.beforeSignup ?? authController.signup,\n middlewares?.beforeSignup\n ? authController.signup\n : middlewares?.afterSignup ?? sendResponse,\n middlewares?.beforeSignup && middlewares?.afterSignup\n ? middlewares?.afterSignup\n : sendResponse,\n sendResponse\n );\n\n router.post(\n \"/auth/update-password\",\n authService.authenticate,\n handleRequestBodyValidationAndTransformation(\"auth\", \"updatePassword\"),\n middlewares?.beforeUpdatePassword ?? authController.updatePassword,\n middlewares?.beforeUpdatePassword\n ? authController.updatePassword\n : middlewares?.afterUpdatePassword ?? sendResponse,\n middlewares?.beforeUpdatePassword && middlewares?.afterUpdatePassword\n ? middlewares?.afterUpdatePassword\n : sendResponse,\n sendResponse\n );\n\n return router;\n}\n"]}
|
|
@@ -33,8 +33,8 @@ class AuthService {
|
|
|
33
33
|
var _a, _b, _c;
|
|
34
34
|
const { authentication: configs } = getArkosConfig();
|
|
35
35
|
if (process.env.NODE_ENV === "production" &&
|
|
36
|
-
!process.env.JWT_SECRET
|
|
37
|
-
|
|
36
|
+
(!process.env.JWT_SECRET ||
|
|
37
|
+
!((_a = configs === null || configs === void 0 ? void 0 : configs.jwt) === null || _a === void 0 ? void 0 : _a.secret)))
|
|
38
38
|
throw new AppError("Missing JWT secret on production!", 500);
|
|
39
39
|
secret =
|
|
40
40
|
secret ||
|
|
@@ -96,9 +96,9 @@ class AuthService {
|
|
|
96
96
|
});
|
|
97
97
|
});
|
|
98
98
|
}
|
|
99
|
-
handleActionAccessControl(authConfigs, action,
|
|
99
|
+
handleActionAccessControl(authConfigs, action, resourceName) {
|
|
100
100
|
return catchAsync((req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
101
|
-
var _a, _b, _c, _d;
|
|
101
|
+
var _a, _b, _c, _d, _e;
|
|
102
102
|
if (req.user) {
|
|
103
103
|
const user = req.user;
|
|
104
104
|
const prisma = getPrismaInstance();
|
|
@@ -108,14 +108,21 @@ class AuthService {
|
|
|
108
108
|
return;
|
|
109
109
|
}
|
|
110
110
|
if (((_a = configs === null || configs === void 0 ? void 0 : configs.authentication) === null || _a === void 0 ? void 0 : _a.mode) === "dynamic") {
|
|
111
|
-
const
|
|
111
|
+
const matchingRole = yield prisma.userRole.findFirst({
|
|
112
112
|
where: {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
userId: req.user.id,
|
|
114
|
+
role: {
|
|
115
|
+
permissions: {
|
|
116
|
+
some: {
|
|
117
|
+
resource: kebabCase(singular(resourceName)),
|
|
118
|
+
action: action,
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
},
|
|
116
122
|
},
|
|
123
|
+
select: { id: true },
|
|
117
124
|
});
|
|
118
|
-
if (!
|
|
125
|
+
if (!matchingRole)
|
|
119
126
|
return next(new AppError("You do not have permission to perfom this action", 403));
|
|
120
127
|
}
|
|
121
128
|
else if (((_b = configs === null || configs === void 0 ? void 0 : configs.authentication) === null || _b === void 0 ? void 0 : _b.mode) === "static") {
|
|
@@ -126,9 +133,9 @@ class AuthService {
|
|
|
126
133
|
authorizedRoles = accessControl;
|
|
127
134
|
else if (accessControl[action])
|
|
128
135
|
authorizedRoles = accessControl[action];
|
|
129
|
-
if (!authorizedRoles.includes((
|
|
130
|
-
(((
|
|
131
|
-
!(authorizedRoles === null || authorizedRoles === void 0 ? void 0 : authorizedRoles.some((role) => { var _a; return ((_a = req.user) === null || _a === void 0 ? void 0 : _a.roles).includes(role); }))))
|
|
136
|
+
if (!((_c = authorizedRoles === null || authorizedRoles === void 0 ? void 0 : authorizedRoles.includes) === null || _c === void 0 ? void 0 : _c.call(authorizedRoles, (_d = req.user) === null || _d === void 0 ? void 0 : _d.role)) ||
|
|
137
|
+
(((_e = req.user) === null || _e === void 0 ? void 0 : _e.roles).length > 0 &&
|
|
138
|
+
!(authorizedRoles === null || authorizedRoles === void 0 ? void 0 : authorizedRoles.some((role) => { var _a, _b, _c; return (_c = (_b = (_a = req.user) === null || _a === void 0 ? void 0 : _a.roles) === null || _b === void 0 ? void 0 : _b.includes) === null || _c === void 0 ? void 0 : _c.call(_b, role); }))))
|
|
132
139
|
return next(new AppError("You do not have permission to perfom this action", 403));
|
|
133
140
|
}
|
|
134
141
|
}
|
|
@@ -138,7 +145,7 @@ class AuthService {
|
|
|
138
145
|
}
|
|
139
146
|
getAuthenticatedUser(req) {
|
|
140
147
|
return __awaiter(this, void 0, void 0, function* () {
|
|
141
|
-
var _a, _b, _c, _d, _e;
|
|
148
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
142
149
|
const arkosConfig = getArkosConfig();
|
|
143
150
|
if (!(arkosConfig === null || arkosConfig === void 0 ? void 0 : arkosConfig.authentication))
|
|
144
151
|
return null;
|
|
@@ -164,22 +171,18 @@ class AuthService {
|
|
|
164
171
|
throw new AppError("Your auth token is invalid, please login again.", 401);
|
|
165
172
|
const user = yield prisma.user.findUnique({
|
|
166
173
|
where: { id: String(decoded.id) },
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
},
|
|
174
|
-
},
|
|
175
|
-
},
|
|
176
|
-
},
|
|
174
|
+
select: {
|
|
175
|
+
id: true,
|
|
176
|
+
passwordChangedAt: true,
|
|
177
|
+
isActive: true,
|
|
178
|
+
deletedSelfAccountAt: true,
|
|
179
|
+
isSuperUser: true,
|
|
177
180
|
},
|
|
178
181
|
});
|
|
179
182
|
if (!user)
|
|
180
183
|
throw new AppError("The user belonging to this token does no longer exists", 401);
|
|
181
184
|
if (this.userChangedPasswordAfter(user, decoded.iat) &&
|
|
182
|
-
!req.path.includes("logout"))
|
|
185
|
+
!((_g = (_f = req.path) === null || _f === void 0 ? void 0 : _f.includes) === null || _g === void 0 ? void 0 : _g.call(_f, "logout")))
|
|
183
186
|
throw new AppError("User recently changed password! Please log in again.", 401);
|
|
184
187
|
return user;
|
|
185
188
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.service.js","sourceRoot":"","sources":["../../../../src/modules/auth/auth.service.ts"],"names":[],"mappings":"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","sourcesContent":["import jwt, { SignOptions } from \"jsonwebtoken\";\nimport bcrypt from \"bcryptjs\";\nimport { User, UserRole } from \"../../types\";\nimport catchAsync from \"../error-handler/utils/catch-async\";\nimport AppError from \"../error-handler/utils/app-error\";\nimport { callNext } from \"../base/base.middlewares\";\nimport { getArkosConfig } from \"../../server\";\nimport arkosEnv from \"../../utils/arkos-env\";\nimport { getPrismaInstance } from \"../../utils/helpers/prisma.helpers\";\nimport {\n ArkosRequest,\n ArkosResponse,\n ArkosNextFunction,\n ArkosRequestHandler,\n} from \"../../types\";\nimport {\n AuthConfigs,\n AuthJwtPayload,\n ControllerActions,\n} from \"../../types/auth\";\nimport { kebabCase } from \"../../utils/helpers/change-case.helpers\";\nimport { singular } from \"pluralize\";\nimport { MsDuration } from \"./utils/helpers/auth.controller.helpers\";\n\n/**\n * Handles various authentication-related tasks such as JWT signing, password hashing, and verifying user credentials.\n */\nclass AuthService {\n /**\n * Signs a JWT token for the user.\n *\n * @param {number | string} id - The unique identifier of the user to generate the token for.\n * @param {string | number} [expiresIn] - The expiration time for the token. Defaults to environment variable `JWT_EXPIRES_IN`.\n * @param {string} [secret] - The secret key used to sign the token. Defaults to environment variable `JWT_SECRET`.\n * @returns {string} The signed JWT token.\n */\n signJwtToken(\n id: number | string,\n expiresIn?: MsDuration | number,\n secret?: string\n ): string {\n const { authentication: configs } = getArkosConfig();\n\n if (\n process.env.NODE_ENV === \"production\" &&\n !process.env.JWT_SECRET &&\n !configs?.jwt?.secret\n )\n throw new AppError(\"Missing JWT secret on production!\", 500);\n\n secret =\n secret ||\n configs?.jwt?.secret ||\n process.env.JWT_SECRET ||\n arkosEnv.JWT_SECRET;\n\n expiresIn = (expiresIn ||\n configs?.jwt?.expiresIn ||\n process.env.JWT_EXPIRES_IN ||\n arkosEnv.JWT_EXPIRES_IN) as keyof SignOptions[\"expiresIn\"];\n\n return jwt.sign({ id }, secret, {\n expiresIn: expiresIn as any,\n });\n }\n\n /**\n * Compares a candidate password with the stored user password to check if they match.\n *\n * @param {string} candidatePassword - The password provided by the user during login.\n * @param {string} userPassword - The password stored in the database.\n * @returns {Promise<boolean>} Returns true if the passwords match, otherwise false.\n */\n async isCorrectPassword(\n candidatePassword: string,\n userPassword: string\n ): Promise<boolean> {\n return await bcrypt.compare(candidatePassword, userPassword);\n }\n\n /**\n * Hashes a plain text password using bcrypt.\n *\n * @param {string} password - The password to be hashed.\n * @returns {Promise<string>} Returns the hashed password.\n */\n async hashPassword(password: string): Promise<string> {\n return await bcrypt.hash(password, 12);\n }\n\n /**\n * Checks if a password is strong, requiring uppercase, lowercase, and numeric characters as the default.\n *\n * **NB**: You must pay attention when using custom validation with zod or class-validator, try to use the same regex always.\n *\n * **Note**: You can define it when calling arkos.init()\n * ```ts\n * arkos.init({\n * authentication: {\n * passwordValidation:{ regex: /your-desired-regex/, message: 'password must contain...'}\n * }\n * })\n * ```\n *\n * @param {string} password - The password to check.\n * @returns {boolean} Returns true if the password meets the strength criteria, otherwise false.\n */\n public isPasswordStrong(password: string): boolean {\n const initAuthConfigs = getArkosConfig()?.authentication;\n\n const strongPasswordRegex =\n initAuthConfigs?.passwordValidation?.regex ||\n /^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d).+$/;\n return strongPasswordRegex.test(password);\n }\n\n /**\n * Checks if a user has changed their password after the JWT was issued.\n *\n * @param {User} user - The user object containing the passwordChangedAt field.\n * @param {number} JWTTimestamp - The timestamp when the JWT was issued.\n * @returns {boolean} Returns true if the user changed their password after the JWT was issued, otherwise false.\n */\n userChangedPasswordAfter(user: User, JWTTimestamp: number): boolean {\n if (user.passwordChangedAt) {\n const convertedTimestamp = parseInt(\n String(user.passwordChangedAt.getTime() / 1000),\n 10\n );\n\n return JWTTimestamp < convertedTimestamp;\n }\n return false;\n }\n\n /**\n * Verifies the authenticity of a JWT token.\n *\n * @param {string} token - The JWT token to verify.\n * @param {string} [secret] - The secret key used to verify the token. Defaults to environment variable `JWT_SECRET`.\n * @returns {Promise<AuthJwtPayload>} Returns the decoded JWT payload if the token is valid.\n * @throws {Error} Throws an error if the token is invalid or expired.\n */\n async verifyJwtToken(\n token: string,\n secret?: string\n ): Promise<AuthJwtPayload> {\n const { authentication: configs } = getArkosConfig();\n\n if (\n process.env.NODE_ENV === \"production\" &&\n !process.env.JWT_SECRET &&\n !configs?.jwt?.secret\n )\n throw new AppError(\"Missing JWT secret!\", 500);\n\n secret =\n secret ||\n configs?.jwt?.secret ||\n process.env.JWT_SECRET ||\n arkosEnv.JWT_SECRET;\n\n return new Promise((resolve, reject) => {\n jwt.verify(token, secret, (err, decoded) => {\n if (err) reject(err);\n else resolve(decoded as AuthJwtPayload);\n });\n });\n }\n\n /**\n * Middleware function to handle access control based on user roles and permissions.\n *\n * @param {AuthConfigs} authConfigs - The configuration object for authentication and access control.\n * @param {ControllerActions} action - The action being performed (e.g., create, update, delete, view).\n * @param {string} modelName - The model name that the action is being performed on (e.g., \"User\", \"Post\").\n * @returns {ArkosRequestHandler} The middleware function that checks if the user has permission to perform the action.\n */\n handleActionAccessControl(\n authConfigs: AuthConfigs,\n action: ControllerActions,\n modelName: string\n ): ArkosRequestHandler {\n return catchAsync(\n async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction\n ) => {\n if (req.user) {\n const user = req.user as any;\n const prisma = getPrismaInstance();\n const configs = getArkosConfig();\n\n if (user.isSuperUser) {\n next();\n return;\n }\n\n if (configs?.authentication?.mode === \"dynamic\") {\n const permissions = await (prisma as any).authPermission.count({\n where: {\n resource: kebabCase(singular(modelName)),\n action,\n roleId: { in: user.roles.map((role: UserRole) => role.roleId) },\n },\n });\n\n if (!permissions)\n return next(\n new AppError(\n \"You do not have permission to perfom this action\",\n 403\n )\n );\n } else if (configs?.authentication?.mode === \"static\") {\n const accessControl = authConfigs?.accessControl;\n let authorizedRoles: any[] = [];\n\n if (accessControl) {\n if (Array.isArray(accessControl)) authorizedRoles = accessControl;\n else if (accessControl[action])\n authorizedRoles = accessControl[action];\n\n // Checks for both cases if using single role or multiple roles\n if (\n !authorizedRoles.includes(req.user?.role) ||\n ((req.user?.roles as any[]).length > 0 &&\n !authorizedRoles?.some((role) =>\n (req.user?.roles as any[]).includes(role)\n ))\n )\n return next(\n new AppError(\n \"You do not have permission to perfom this action\",\n 403\n )\n );\n }\n }\n }\n\n next();\n }\n );\n }\n\n /**\n * Processes the cookies or authoriation token and returns the user.\n * @param req\n * @returns {Promise<User | null>} - if authentication is turned off in arkosConfig it returns null\n * @throws {AppError} Throws an error if the token is invalid or the user is not logged in.\n */\n async getAuthenticatedUser(req: ArkosRequest): Promise<User | null> {\n const arkosConfig = getArkosConfig();\n if (!arkosConfig?.authentication) return null;\n\n const prisma = getPrismaInstance();\n\n let token: string | undefined;\n\n if (\n req?.headers?.authorization &&\n req?.headers?.authorization.startsWith(\"Bearer\")\n ) {\n token = req?.headers?.authorization.split(\" \")[1];\n } else if (req?.cookies?.arkos_access_token !== \"no-token\" && req.cookies) {\n token = req?.cookies?.arkos_access_token;\n }\n\n if (!token)\n throw new AppError(\n \"You are not logged in! please log in to get access\",\n 401\n );\n\n let decoded: AuthJwtPayload | undefined;\n try {\n decoded = await this.verifyJwtToken(token);\n } catch (err) {\n throw new AppError(\n \"Your auth token is invalid, please login again.\",\n 401\n );\n }\n\n if (!decoded?.id)\n throw new AppError(\n \"Your auth token is invalid, please login again.\",\n 401\n );\n\n const user: any | null = await (prisma as any).user.findUnique({\n where: { id: String(decoded.id) },\n include: {\n roles: {\n include: {\n role: {\n include: {\n permissions: true,\n },\n },\n },\n },\n },\n });\n\n if (!user)\n throw new AppError(\n \"The user belonging to this token does no longer exists\",\n 401\n );\n\n if (\n this.userChangedPasswordAfter(user, decoded.iat!) &&\n !req.path.includes(\"logout\")\n )\n throw new AppError(\n \"User recently changed password! Please log in again.\",\n 401\n );\n\n return user;\n }\n\n /**\n * Middleware function to authenticate the user based on the JWT token.\n *\n * @param {ArkosRequest} req - The request object.\n * @param {ArkosResponse} res - The response object.\n * @param {ArkosNextFunction} next - The next middleware function to be called.\n * @returns {void}\n */\n authenticate = catchAsync(\n async (req: ArkosRequest, res: ArkosResponse, next: ArkosNextFunction) => {\n const arkosConfig = getArkosConfig();\n if (!arkosConfig?.authentication) {\n next();\n return;\n }\n\n req.user = (await this.getAuthenticatedUser(req)) as User;\n next();\n }\n );\n\n /**\n * Handles authentication control by checking the `authenticationControl` configuration in the `authConfigs`.\n *\n * @param {AuthConfigs | undefined} authConfigs - The authentication configuration object.\n * @param {ControllerActions} action - The action being performed (e.g., create, update, delete, view).\n * @returns {ArkosRequestHandler} The middleware function that checks if authentication is required.\n */\n handleAuthenticationControl(\n authConfigs: AuthConfigs | undefined,\n action: ControllerActions\n ): ArkosRequestHandler {\n const authenticationControl = authConfigs?.authenticationControl;\n\n if (authenticationControl && typeof authenticationControl === \"object\") {\n if (authenticationControl[action] === false) return callNext;\n else if (authenticationControl[action] === true) return this.authenticate;\n } else return this.authenticate;\n\n return this.authenticate;\n }\n}\n\n/**\n * Handles various authentication-related tasks such as JWT signing, password hashing, and verifying user credentials.\n */\nconst authService = new AuthService();\n\nexport default authService;\n"]}
|
|
1
|
+
{"version":3,"file":"auth.service.js","sourceRoot":"","sources":["../../../../src/modules/auth/auth.service.ts"],"names":[],"mappings":"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","sourcesContent":["import jwt, { SignOptions } from \"jsonwebtoken\";\nimport bcrypt from \"bcryptjs\";\nimport { AuthPermissionAction, User, UserRole } from \"../../types\";\nimport catchAsync from \"../error-handler/utils/catch-async\";\nimport AppError from \"../error-handler/utils/app-error\";\nimport { callNext } from \"../base/base.middlewares\";\nimport { getArkosConfig } from \"../../server\";\nimport arkosEnv from \"../../utils/arkos-env\";\nimport { getPrismaInstance } from \"../../utils/helpers/prisma.helpers\";\nimport {\n ArkosRequest,\n ArkosResponse,\n ArkosNextFunction,\n ArkosRequestHandler,\n} from \"../../types\";\nimport {\n AuthConfigs,\n AuthJwtPayload,\n BaseControllerActions,\n} from \"../../types/auth\";\nimport { kebabCase } from \"../../utils/helpers/change-case.helpers\";\nimport { singular } from \"pluralize\";\nimport { MsDuration } from \"./utils/helpers/auth.controller.helpers\";\n\n/**\n * Handles various authentication-related tasks such as JWT signing, password hashing, and verifying user credentials.\n */\nclass AuthService {\n /**\n * Signs a JWT token for the user.\n *\n * @param {number | string} id - The unique identifier of the user to generate the token for.\n * @param {string | number} [expiresIn] - The expiration time for the token. Defaults to environment variable `JWT_EXPIRES_IN`.\n * @param {string} [secret] - The secret key used to sign the token. Defaults to environment variable `JWT_SECRET`.\n * @returns {string} The signed JWT token.\n */\n signJwtToken(\n id: number | string,\n expiresIn?: MsDuration | number,\n secret?: string\n ): string {\n const { authentication: configs } = getArkosConfig();\n\n if (\n process.env.NODE_ENV === \"production\" &&\n (!process.env.JWT_SECRET ||\n !configs?.jwt?.secret)\n )\n throw new AppError(\"Missing JWT secret on production!\", 500);\n\n secret =\n secret ||\n configs?.jwt?.secret ||\n process.env.JWT_SECRET ||\n arkosEnv.JWT_SECRET;\n\n expiresIn = (expiresIn ||\n configs?.jwt?.expiresIn ||\n process.env.JWT_EXPIRES_IN ||\n arkosEnv.JWT_EXPIRES_IN) as keyof SignOptions[\"expiresIn\"];\n\n return jwt.sign({ id }, secret, {\n expiresIn: expiresIn as MsDuration,\n });\n }\n\n /**\n * Compares a candidate password with the stored user password to check if they match.\n *\n * @param {string} candidatePassword - The password provided by the user during login.\n * @param {string} userPassword - The password stored in the database.\n * @returns {Promise<boolean>} Returns true if the passwords match, otherwise false.\n */\n async isCorrectPassword(\n candidatePassword: string,\n userPassword: string\n ): Promise<boolean> {\n return await bcrypt.compare(candidatePassword, userPassword);\n }\n\n /**\n * Hashes a plain text password using bcrypt.\n *\n * @param {string} password - The password to be hashed.\n * @returns {Promise<string>} Returns the hashed password.\n */\n async hashPassword(password: string): Promise<string> {\n return await bcrypt.hash(password, 12);\n }\n\n /**\n * Checks if a password is strong, requiring uppercase, lowercase, and numeric characters as the default.\n *\n * **NB**: You must pay attention when using custom validation with zod or class-validator, try to use the same regex always.\n *\n * **Note**: You can define it when calling arkos.init()\n * ```ts\n * arkos.init({\n * authentication: {\n * passwordValidation:{ regex: /your-desired-regex/, message: 'password must contain...'}\n * }\n * })\n * ```\n *\n * @param {string} password - The password to check.\n * @returns {boolean} Returns true if the password meets the strength criteria, otherwise false.\n */\n public isPasswordStrong(password: string): boolean {\n const initAuthConfigs = getArkosConfig()?.authentication;\n\n const strongPasswordRegex =\n initAuthConfigs?.passwordValidation?.regex ||\n /^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d).+$/;\n return strongPasswordRegex.test(password);\n }\n\n /**\n * Checks if a user has changed their password after the JWT was issued.\n *\n * @param {User} user - The user object containing the passwordChangedAt field.\n * @param {number} JWTTimestamp - The timestamp when the JWT was issued.\n * @returns {boolean} Returns true if the user changed their password after the JWT was issued, otherwise false.\n */\n userChangedPasswordAfter(user: User, JWTTimestamp: number): boolean {\n if (user.passwordChangedAt) {\n const convertedTimestamp = parseInt(\n String(user.passwordChangedAt.getTime() / 1000),\n 10\n );\n\n return JWTTimestamp < convertedTimestamp;\n }\n return false;\n }\n\n /**\n * Verifies the authenticity of a JWT token.\n *\n * @param {string} token - The JWT token to verify.\n * @param {string} [secret] - The secret key used to verify the token. Defaults to environment variable `JWT_SECRET`.\n * @returns {Promise<AuthJwtPayload>} Returns the decoded JWT payload if the token is valid.\n * @throws {Error} Throws an error if the token is invalid or expired.\n */\n async verifyJwtToken(\n token: string,\n secret?: string\n ): Promise<AuthJwtPayload> {\n const { authentication: configs } = getArkosConfig();\n\n if (\n process.env.NODE_ENV === \"production\" &&\n !process.env.JWT_SECRET &&\n !configs?.jwt?.secret\n )\n throw new AppError(\"Missing JWT secret!\", 500);\n\n secret =\n secret ||\n configs?.jwt?.secret ||\n process.env.JWT_SECRET ||\n arkosEnv.JWT_SECRET;\n\n return new Promise((resolve, reject) => {\n jwt.verify(token, secret, (err, decoded) => {\n if (err) reject(err);\n else resolve(decoded as AuthJwtPayload);\n });\n });\n }\n\n /**\n * Middleware function to handle access control based on user roles and permissions.\n *\n * @param {AuthConfigs} authConfigs - The configuration object for authentication and access control.\n * @param {ControllerActions} action - The action being performed (e.g., create, update, delete, view).\n * @param {string} resourceName - The resource name that the action is being performed on (e.g., \"User\", \"Post\").\n * @returns {ArkosRequestHandler} The middleware function that checks if the user has permission to perform the action.\n */\n handleActionAccessControl(\n authConfigs: AuthConfigs,\n action: BaseControllerActions,\n resourceName: string\n ): ArkosRequestHandler {\n return catchAsync(\n async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction\n ) => {\n if (req.user) {\n const user = req.user as any;\n const prisma = getPrismaInstance();\n const configs = getArkosConfig();\n\n if (user.isSuperUser) {\n next();\n return;\n }\n\n if (configs?.authentication?.mode === \"dynamic\") {\n const matchingRole = await prisma.userRole.findFirst({\n where: {\n userId: req.user.id,\n role: {\n permissions: {\n some: {\n resource: kebabCase(singular(resourceName)),\n action: action,\n },\n },\n },\n },\n select: { id: true },\n });\n\n if (!matchingRole)\n return next(\n new AppError(\n \"You do not have permission to perfom this action\",\n 403\n )\n );\n } else if (configs?.authentication?.mode === \"static\") {\n const accessControl = authConfigs?.accessControl;\n let authorizedRoles: any[] = [];\n\n if (accessControl) {\n if (Array.isArray(accessControl)) authorizedRoles = accessControl;\n else if (accessControl[action])\n authorizedRoles = accessControl[action];\n\n // Checks for both cases if using single role or multiple roles\n if (\n !authorizedRoles?.includes?.(req.user?.role) ||\n ((req.user?.roles as any[]).length > 0 &&\n !authorizedRoles?.some((role) =>\n (req.user?.roles as any[])?.includes?.(role)\n ))\n )\n return next(\n new AppError(\n \"You do not have permission to perfom this action\",\n 403\n )\n );\n }\n }\n }\n\n next();\n }\n );\n }\n\n /**\n * Processes the cookies or authoriation token and returns the user.\n * @param req\n * @returns {Promise<User | null>} - if authentication is turned off in arkosConfig it returns null\n * @throws {AppError} Throws an error if the token is invalid or the user is not logged in.\n */\n async getAuthenticatedUser(req: ArkosRequest): Promise<User | null> {\n const arkosConfig = getArkosConfig();\n if (!arkosConfig?.authentication) return null;\n\n const prisma = getPrismaInstance();\n\n let token: string | undefined;\n\n if (\n req?.headers?.authorization &&\n req?.headers?.authorization.startsWith(\"Bearer\")\n ) {\n token = req?.headers?.authorization.split(\" \")[1];\n } else if (req?.cookies?.arkos_access_token !== \"no-token\" && req.cookies) {\n token = req?.cookies?.arkos_access_token;\n }\n\n if (!token)\n throw new AppError(\n \"You are not logged in! please log in to get access\",\n 401\n );\n\n let decoded: AuthJwtPayload | undefined;\n try {\n decoded = await this.verifyJwtToken(token);\n } catch (err) {\n throw new AppError(\n \"Your auth token is invalid, please login again.\",\n 401\n );\n }\n\n if (!decoded?.id)\n throw new AppError(\n \"Your auth token is invalid, please login again.\",\n 401\n );\n\n const user: any | null = await (prisma as any).user.findUnique({\n where: { id: String(decoded.id) },\n select: {\n id: true,\n passwordChangedAt: true,\n isActive: true,\n deletedSelfAccountAt: true,\n isSuperUser: true,\n },\n });\n\n if (!user)\n throw new AppError(\n \"The user belonging to this token does no longer exists\",\n 401\n );\n\n if (\n this.userChangedPasswordAfter(user, decoded.iat!) &&\n !req.path?.includes?.(\"logout\")\n )\n throw new AppError(\n \"User recently changed password! Please log in again.\",\n 401\n );\n\n return user;\n }\n\n /**\n * Middleware function to authenticate the user based on the JWT token.\n *\n * @param {ArkosRequest} req - The request object.\n * @param {ArkosResponse} res - The response object.\n * @param {ArkosNextFunction} next - The next middleware function to be called.\n * @returns {void}\n */\n authenticate = catchAsync(\n async (req: ArkosRequest, res: ArkosResponse, next: ArkosNextFunction) => {\n const arkosConfig = getArkosConfig();\n if (!arkosConfig?.authentication) {\n next();\n return;\n }\n\n req.user = (await this.getAuthenticatedUser(req)) as User;\n next();\n }\n );\n\n /**\n * Handles authentication control by checking the `authenticationControl` configuration in the `authConfigs`.\n *\n * @param {AuthConfigs | undefined} authConfigs - The authentication configuration object.\n * @param {ControllerActions} action - The action being performed (e.g., create, update, delete, view).\n * @returns {ArkosRequestHandler} The middleware function that checks if authentication is required.\n */\n handleAuthenticationControl(\n authConfigs: AuthConfigs | undefined,\n action: BaseControllerActions\n ): ArkosRequestHandler {\n const authenticationControl = authConfigs?.authenticationControl;\n\n if (authenticationControl && typeof authenticationControl === \"object\") {\n if (authenticationControl[action] === false) return callNext;\n else if (authenticationControl[action] === true) return this.authenticate;\n } else return this.authenticate;\n\n return this.authenticate;\n }\n}\n\n/**\n * Handles various authentication-related tasks such as JWT signing, password hashing, and verifying user credentials.\n */\nconst authService = new AuthService();\n\nexport default authService;\n"]}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { getArkosConfig } from "../../../../server";
|
|
2
2
|
import AppError from "../../../error-handler/utils/app-error";
|
|
3
3
|
export const determineUsernameField = (req) => {
|
|
4
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
4
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
5
5
|
const authConfigs = (_a = getArkosConfig()) === null || _a === void 0 ? void 0 : _a.authentication;
|
|
6
6
|
if (((_b = req.query) === null || _b === void 0 ? void 0 : _b.usernameField) &&
|
|
7
7
|
typeof ((_c = req.query) === null || _c === void 0 ? void 0 : _c.usernameField) === "string" &&
|
|
8
|
-
((_e = (_d = authConfigs === null || authConfigs === void 0 ? void 0 : authConfigs.login) === null || _d === void 0 ? void 0 : _d.allowedUsernames) === null || _e === void 0 ? void 0 : _e.includes(req.query.usernameField)))
|
|
8
|
+
((_f = (_e = (_d = authConfigs === null || authConfigs === void 0 ? void 0 : authConfigs.login) === null || _d === void 0 ? void 0 : _d.allowedUsernames) === null || _e === void 0 ? void 0 : _e.includes) === null || _f === void 0 ? void 0 : _f.call(_e, req.query.usernameField)))
|
|
9
9
|
return req.query.usernameField;
|
|
10
|
-
else if ((
|
|
10
|
+
else if ((_g = req.query) === null || _g === void 0 ? void 0 : _g.usernameField)
|
|
11
11
|
throw new AppError("Invalid usernameField parameter, it is not allowed!", 400);
|
|
12
|
-
return ((
|
|
12
|
+
return ((_j = (_h = authConfigs === null || authConfigs === void 0 ? void 0 : authConfigs.login) === null || _h === void 0 ? void 0 : _h.allowedUsernames) === null || _j === void 0 ? void 0 : _j[0]) || "username";
|
|
13
13
|
};
|
|
14
14
|
export const createPrismaWhereClause = (path, value) => {
|
|
15
15
|
if (!path)
|
|
@@ -33,15 +33,11 @@ export const getNestedValue = (obj, path) => {
|
|
|
33
33
|
if (!obj || !path)
|
|
34
34
|
return undefined;
|
|
35
35
|
const properties = path.split(".");
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return undefined;
|
|
40
|
-
if (prop !== "some") {
|
|
41
|
-
value = value[prop];
|
|
42
|
-
}
|
|
36
|
+
const lastProperty = properties[properties.length - 1];
|
|
37
|
+
if (lastProperty in obj) {
|
|
38
|
+
return obj[lastProperty];
|
|
43
39
|
}
|
|
44
|
-
return
|
|
40
|
+
return undefined;
|
|
45
41
|
};
|
|
46
42
|
function normalizeDuration(input) {
|
|
47
43
|
return input
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.controller.helpers.js","sourceRoot":"","sources":["../../../../../../src/modules/auth/utils/helpers/auth.controller.helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,QAAQ,MAAM,wCAAwC,CAAC;AAc9D,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,GAAiB,EAAU,EAAE;;IAClE,MAAM,WAAW,GAAG,MAAA,cAAc,EAAE,0CAAE,cAAc,CAAC;IAErD,IACE,CAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,aAAa;QACxB,OAAO,CAAA,MAAA,GAAG,CAAC,KAAK,0CAAE,aAAa,CAAA,KAAK,QAAQ;SAC5C,MAAA,MAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,KAAK,0CAAE,gBAAgB,0CAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"auth.controller.helpers.js","sourceRoot":"","sources":["../../../../../../src/modules/auth/utils/helpers/auth.controller.helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import { getArkosConfig } from \"../../../../server\";\nimport { ArkosRequest } from \"../../../../types\";\nimport AppError from \"../../../error-handler/utils/app-error\";\n\n/**\n * Determines the username field to use for authentication and supports nested paths\n * Priority:\n * 1. req.query.usernameField\n * 2. config setting\n * 3. default \"username\"\n *\n * Supports dot notation for nested fields and array queries (e.g., \"profile.nickname\", \"phones.some.number\")\n *\n * @param req - The request object\n * @returns The field name to use for username identification\n */\nexport const determineUsernameField = (req: ArkosRequest): string => {\n const authConfigs = getArkosConfig()?.authentication;\n\n if (\n req.query?.usernameField &&\n typeof req.query?.usernameField === \"string\" &&\n authConfigs?.login?.allowedUsernames?.includes?.(req.query.usernameField)\n )\n return req.query.usernameField;\n else if (req.query?.usernameField)\n throw new AppError(\n \"Invalid usernameField parameter, it is not allowed!\",\n 400\n );\n\n return authConfigs?.login?.allowedUsernames?.[0] || \"username\";\n};\n\n/**\n * Creates a Prisma-compatible where clause from a path using dot notation\n * Handles nested objects and array queries with \"some\" operator\n * Example: createPrismaWhereClause(\"profile.nickname\", \"john\") or createPrismaWhereClause(\"phones.some.number\", \"1234567890\")\n *\n * @param path - The dot notation path (e.g., \"profile.nickname\" or \"phones.some.number\")\n * @param value - The value to search for\n * @returns A nested object suitable for Prisma's where clause\n */\nexport const createPrismaWhereClause = (\n path: string,\n value: any\n): Record<string, any> => {\n if (!path) return {};\n\n const parts = path.split(\".\");\n const whereClause: Record<string, any> = {};\n\n // Handle simple field case\n if (parts.length === 1) {\n whereClause[parts[0]] = value;\n return whereClause;\n }\n\n // Handle nested fields\n let current = whereClause;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n current[part] = {};\n current = current[part];\n }\n\n current[parts[parts.length - 1]] = value;\n\n return whereClause;\n};\n\n/**\n * Access a value from a simple object based on a dot notation path\n * The object will only contain a single property that matches the last part of the path\n * Example: getNestedValue({nickname: \"john\"}, \"profile.nickname\") => \"john\"\n *\n * @param obj - The object containing the value (simple key-value pair)\n * @param path - The dot notation path (only the last part is used to access the object)\n * @returns The value from the object if the key matches the last part of the path, or undefined\n */\nexport const getNestedValue = (obj: any, path: string): any => {\n if (!obj || !path) return undefined;\n\n const properties = path.split(\".\");\n const lastProperty = properties[properties.length - 1];\n\n // If the last property exists in the object, return its value\n if (lastProperty in obj) {\n return obj[lastProperty];\n }\n\n return undefined;\n};\n\n/**\n * MsDuration type allows specific units for durations\n *\n * **For example**: 90d, 10ms, 50s.\n *\n * **Available metrics**: ms, s, m, h, d, w, y.\n * */\nexport type MsDuration =\n | number\n | `${number}`\n | `${number}${\"ms\" | \"s\" | \"m\" | \"h\" | \"d\" | \"w\" | \"y\"}`; // Short format (e.g., \"1y\")\n\n// Normalize function to convert long units to short ones\nfunction normalizeDuration(input: string): string {\n return input\n .toLowerCase()\n .replace(/years?|yr|year/g, \"y\")\n .replace(/minutes?|min/g, \"m\")\n .replace(/seconds?|sec|secs/g, \"s\")\n .replace(/hours?|hr/g, \"h\")\n .replace(/days?/g, \"d\")\n .replace(/weeks?/g, \"w\")\n .replace(/milliseconds?/g, \"ms\");\n}\n\nexport function toMs(input: number | MsDuration): number {\n if (typeof input === \"number\") return input * 1000; // If it's a number, assume it's in seconds\n\n // Normalize the string input\n const normalizedInput = normalizeDuration(input.trim());\n\n // Type assertion: we assert that normalizedInput will now match the MsDuration format\n const regex = /^(\\d+(?:\\.\\d+)?)(ms|s|m|h|d|w|y)$/i;\n const match = normalizedInput.match(regex);\n\n if (!match) throw new Error(`Invalid time format: ${input}`);\n\n const value = parseFloat(match[1]);\n const unit = match[2].toLowerCase() as\n | \"ms\"\n | \"s\"\n | \"m\"\n | \"h\"\n | \"d\"\n | \"w\"\n | \"y\";\n\n const multipliers: Record<\"ms\" | \"s\" | \"m\" | \"h\" | \"d\" | \"w\" | \"y\", number> =\n {\n ms: 1,\n s: 1000,\n m: 60000,\n h: 3600000,\n d: 86400000,\n w: 604800000,\n y: 31557600000, // 365.25 days in ms\n };\n\n return value * multipliers[unit];\n}\n"]}
|