arkos 1.0.3-alpha → 1.0.4-alpha
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/README.md +0 -32
- package/package.json +1 -1
- package/dist/cjs/modules/auth/__tests__/auth.controller.test.js +0 -494
- package/dist/cjs/modules/auth/__tests__/auth.controller.test.js.map +0 -1
- package/dist/cjs/modules/auth/__tests__/auth.service.test.js +0 -470
- package/dist/cjs/modules/auth/__tests__/auth.service.test.js.map +0 -1
- package/dist/cjs/modules/auth/utils/helpers/__tests__/auth.helpers.test.js +0 -43
- package/dist/cjs/modules/auth/utils/helpers/__tests__/auth.helpers.test.js.map +0 -1
- package/dist/cjs/modules/base/utils/helpers/__tests__/base.helpers.test.js +0 -754
- package/dist/cjs/modules/base/utils/helpers/__tests__/base.helpers.test.js.map +0 -1
- package/dist/cjs/modules/file-upload/file-upload.controller.js +0 -226
- package/dist/cjs/modules/file-upload/file-upload.controller.js.map +0 -1
- package/dist/cjs/modules/file-upload/file-upload.router.js +0 -50
- package/dist/cjs/modules/file-upload/file-upload.router.js.map +0 -1
- package/dist/cjs/modules/file-upload/file-upload.service.js +0 -353
- package/dist/cjs/modules/file-upload/file-upload.service.js.map +0 -1
- package/dist/cjs/modules/file-uploader/__tests__/file-uploader.service.test.js +0 -402
- package/dist/cjs/modules/file-uploader/__tests__/file-uploader.service.test.js.map +0 -1
- package/dist/cjs/modules/file-uploader/utils/helpers/__tests__/file-uploader.helpers.test.js +0 -164
- package/dist/cjs/modules/file-uploader/utils/helpers/__tests__/file-uploader.helpers.test.js.map +0 -1
- package/dist/es2020/modules/file-upload/file-upload.controller.js +0 -220
- package/dist/es2020/modules/file-upload/file-upload.controller.js.map +0 -1
- package/dist/es2020/modules/file-upload/file-upload.router.js +0 -44
- package/dist/es2020/modules/file-upload/file-upload.router.js.map +0 -1
- package/dist/es2020/modules/file-upload/file-upload.service.js +0 -345
- package/dist/es2020/modules/file-upload/file-upload.service.js.map +0 -1
- package/dist/types/modules/file-upload/file-upload.controller.d.ts +0 -3
- package/dist/types/modules/file-upload/file-upload.router.d.ts +0 -3
- package/dist/types/modules/file-upload/file-upload.service.d.ts +0 -30
|
@@ -1,470 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
16
|
-
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
|
17
|
-
const auth_service_1 = __importDefault(require("../auth.service"));
|
|
18
|
-
const prisma_helpers_1 = require("../../../utils/helpers/prisma.helpers");
|
|
19
|
-
const server_1 = require("../../../server");
|
|
20
|
-
const app_error_1 = __importDefault(require("../../error-handler/utils/app-error"));
|
|
21
|
-
jest.mock("jsonwebtoken");
|
|
22
|
-
jest.mock("bcryptjs");
|
|
23
|
-
jest.mock("../../../utils/helpers/prisma.helpers");
|
|
24
|
-
jest.mock("../../../server");
|
|
25
|
-
jest.mock("../../error-handler/utils/app-error");
|
|
26
|
-
jest.mock("../../../utils/helpers/models.helpers", () => ({
|
|
27
|
-
getModels: jest.fn().mockReturnValue([]),
|
|
28
|
-
getModelFields: jest.fn().mockReturnValue([]),
|
|
29
|
-
getPrismaModels: jest.fn().mockReturnValue([]),
|
|
30
|
-
}));
|
|
31
|
-
describe("AuthService", () => {
|
|
32
|
-
let mockReq;
|
|
33
|
-
let mockRes;
|
|
34
|
-
let mockNext;
|
|
35
|
-
let mockPrisma;
|
|
36
|
-
let mockConfig;
|
|
37
|
-
beforeEach(() => {
|
|
38
|
-
jest.resetAllMocks();
|
|
39
|
-
mockReq = {
|
|
40
|
-
headers: {},
|
|
41
|
-
cookies: {},
|
|
42
|
-
path: "/test",
|
|
43
|
-
user: null,
|
|
44
|
-
};
|
|
45
|
-
mockRes = {
|
|
46
|
-
status: jest.fn().mockReturnThis(),
|
|
47
|
-
json: jest.fn(),
|
|
48
|
-
};
|
|
49
|
-
mockNext = jest.fn();
|
|
50
|
-
mockPrisma = {
|
|
51
|
-
user: {
|
|
52
|
-
findUnique: jest.fn(),
|
|
53
|
-
update: jest.fn(),
|
|
54
|
-
},
|
|
55
|
-
authPermission: {
|
|
56
|
-
count: jest.fn(),
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
prisma_helpers_1.getPrismaInstance.mockReturnValue(mockPrisma);
|
|
60
|
-
mockConfig = {
|
|
61
|
-
authentication: {
|
|
62
|
-
mode: "static",
|
|
63
|
-
passwordValidation: {
|
|
64
|
-
regex: /^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).+$/,
|
|
65
|
-
message: "Password must contain at least one uppercase letter, one lowercase letter, and one number",
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
};
|
|
69
|
-
server_1.getArkosConfig.mockReturnValue(mockConfig);
|
|
70
|
-
});
|
|
71
|
-
describe("signJwtToken", () => {
|
|
72
|
-
it("should sign a JWT token with the provided id", () => {
|
|
73
|
-
const userId = "user-123";
|
|
74
|
-
const mockToken = "mock-jwt-token";
|
|
75
|
-
jsonwebtoken_1.default.sign.mockReturnValue(mockToken);
|
|
76
|
-
const result = auth_service_1.default.signJwtToken(userId);
|
|
77
|
-
expect(jsonwebtoken_1.default.sign).toHaveBeenCalledWith({ id: userId }, expect.any(String), { expiresIn: expect.any(String) });
|
|
78
|
-
expect(result).toBe(mockToken);
|
|
79
|
-
});
|
|
80
|
-
it("should use custom expiresIn and secret when provided", () => {
|
|
81
|
-
const userId = "user-123";
|
|
82
|
-
const expiresIn = "1h";
|
|
83
|
-
const secret = "custom-secret";
|
|
84
|
-
const mockToken = "mock-jwt-token";
|
|
85
|
-
jsonwebtoken_1.default.sign.mockReturnValue(mockToken);
|
|
86
|
-
const result = auth_service_1.default.signJwtToken(userId, expiresIn, secret);
|
|
87
|
-
expect(jsonwebtoken_1.default.sign).toHaveBeenCalledWith({ id: userId }, secret, {
|
|
88
|
-
expiresIn,
|
|
89
|
-
});
|
|
90
|
-
expect(result).toBe(mockToken);
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
describe("isCorrectPassword", () => {
|
|
94
|
-
it("should return true if passwords match", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
95
|
-
const candidatePassword = "password123";
|
|
96
|
-
const userPassword = "hashedPassword";
|
|
97
|
-
bcryptjs_1.default.compare.mockResolvedValue(true);
|
|
98
|
-
const result = yield auth_service_1.default.isCorrectPassword(candidatePassword, userPassword);
|
|
99
|
-
expect(bcryptjs_1.default.compare).toHaveBeenCalledWith(candidatePassword, userPassword);
|
|
100
|
-
expect(result).toBe(true);
|
|
101
|
-
}));
|
|
102
|
-
it("should return false if passwords do not match", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
103
|
-
const candidatePassword = "wrongPassword";
|
|
104
|
-
const userPassword = "hashedPassword";
|
|
105
|
-
bcryptjs_1.default.compare.mockResolvedValue(false);
|
|
106
|
-
const result = yield auth_service_1.default.isCorrectPassword(candidatePassword, userPassword);
|
|
107
|
-
expect(bcryptjs_1.default.compare).toHaveBeenCalledWith(candidatePassword, userPassword);
|
|
108
|
-
expect(result).toBe(false);
|
|
109
|
-
}));
|
|
110
|
-
});
|
|
111
|
-
describe("hashPassword", () => {
|
|
112
|
-
it("should hash the password using bcrypt", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
113
|
-
const password = "password123";
|
|
114
|
-
const hashedPassword = "hashedPassword123";
|
|
115
|
-
bcryptjs_1.default.hash.mockResolvedValue(hashedPassword);
|
|
116
|
-
const result = yield auth_service_1.default.hashPassword(password);
|
|
117
|
-
expect(bcryptjs_1.default.hash).toHaveBeenCalledWith(password, 12);
|
|
118
|
-
expect(result).toBe(hashedPassword);
|
|
119
|
-
}));
|
|
120
|
-
});
|
|
121
|
-
describe("isPasswordStrong", () => {
|
|
122
|
-
it("should return true for a strong password matching the regex", () => {
|
|
123
|
-
const strongPassword = "Password123";
|
|
124
|
-
const result = auth_service_1.default.isPasswordStrong(strongPassword);
|
|
125
|
-
expect(result).toBe(true);
|
|
126
|
-
});
|
|
127
|
-
it("should return false for a weak password not matching the regex", () => {
|
|
128
|
-
const weakPassword = "password";
|
|
129
|
-
const result = auth_service_1.default.isPasswordStrong(weakPassword);
|
|
130
|
-
expect(result).toBe(false);
|
|
131
|
-
});
|
|
132
|
-
it("should use custom regex from arkos config when available", () => {
|
|
133
|
-
mockConfig.authentication.passwordValidation.regex =
|
|
134
|
-
/^(?=.*[A-Z])(?=.*[0-9]).{8,}$/;
|
|
135
|
-
const password = "PASSWORD123";
|
|
136
|
-
const result = auth_service_1.default.isPasswordStrong(password);
|
|
137
|
-
expect(result).toBe(true);
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
describe("userChangedPasswordAfter", () => {
|
|
141
|
-
it("should return true if password was changed after JWT was issued", () => {
|
|
142
|
-
const user = {
|
|
143
|
-
passwordChangedAt: new Date(Date.now() + 1000),
|
|
144
|
-
};
|
|
145
|
-
const jwtTimestamp = Math.floor(Date.now() / 1000);
|
|
146
|
-
const result = auth_service_1.default.userChangedPasswordAfter(user, jwtTimestamp);
|
|
147
|
-
expect(result).toBe(true);
|
|
148
|
-
});
|
|
149
|
-
it("should return false if password was changed before JWT was issued", () => {
|
|
150
|
-
const user = {
|
|
151
|
-
passwordChangedAt: new Date(Date.now() - 1000),
|
|
152
|
-
};
|
|
153
|
-
const jwtTimestamp = Math.floor(Date.now() / 1000);
|
|
154
|
-
const result = auth_service_1.default.userChangedPasswordAfter(user, jwtTimestamp);
|
|
155
|
-
expect(result).toBe(false);
|
|
156
|
-
});
|
|
157
|
-
it("should return false if passwordChangedAt is not set", () => {
|
|
158
|
-
const user = {};
|
|
159
|
-
const jwtTimestamp = Math.floor(Date.now() / 1000);
|
|
160
|
-
const result = auth_service_1.default.userChangedPasswordAfter(user, jwtTimestamp);
|
|
161
|
-
expect(result).toBe(false);
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
describe("verifyJwtToken", () => {
|
|
165
|
-
it("should resolve with decoded payload for valid token", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
166
|
-
const token = "valid-token";
|
|
167
|
-
const decodedPayload = { id: "user-123", iat: 1617123456 };
|
|
168
|
-
jsonwebtoken_1.default.verify.mockImplementation((token, secret, callback) => {
|
|
169
|
-
callback(null, decodedPayload);
|
|
170
|
-
});
|
|
171
|
-
const result = yield auth_service_1.default.verifyJwtToken(token);
|
|
172
|
-
expect(jsonwebtoken_1.default.verify).toHaveBeenCalledWith(token, expect.any(String), expect.any(Function));
|
|
173
|
-
expect(result).toEqual(decodedPayload);
|
|
174
|
-
}));
|
|
175
|
-
it("should reject with error for invalid token", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
176
|
-
const token = "invalid-token";
|
|
177
|
-
const jwtError = new Error("Invalid token");
|
|
178
|
-
jsonwebtoken_1.default.verify.mockImplementation((token, secret, callback) => {
|
|
179
|
-
callback(jwtError, null);
|
|
180
|
-
});
|
|
181
|
-
yield expect(auth_service_1.default.verifyJwtToken(token)).rejects.toEqual(jwtError);
|
|
182
|
-
expect(jsonwebtoken_1.default.verify).toHaveBeenCalledWith(token, expect.any(String), expect.any(Function));
|
|
183
|
-
}));
|
|
184
|
-
it("should use custom secret when provided", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
185
|
-
const token = "valid-token";
|
|
186
|
-
const customSecret = "custom-secret-key";
|
|
187
|
-
const decodedPayload = { id: "user-123", iat: 1617123456 };
|
|
188
|
-
jsonwebtoken_1.default.verify.mockImplementation((token, secret, callback) => {
|
|
189
|
-
callback(null, decodedPayload);
|
|
190
|
-
});
|
|
191
|
-
yield auth_service_1.default.verifyJwtToken(token, customSecret);
|
|
192
|
-
expect(jsonwebtoken_1.default.verify).toHaveBeenCalledWith(token, customSecret, expect.any(Function));
|
|
193
|
-
}));
|
|
194
|
-
});
|
|
195
|
-
describe("getAuthenticatedUser", () => {
|
|
196
|
-
it("should return null if authentication is disabled in config", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
197
|
-
server_1.getArkosConfig.mockReturnValue({ authentication: null });
|
|
198
|
-
const result = yield auth_service_1.default.getAuthenticatedUser(mockReq);
|
|
199
|
-
expect(result).toBeNull();
|
|
200
|
-
}));
|
|
201
|
-
it("should throw an error if no token is found", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
202
|
-
mockReq = {};
|
|
203
|
-
yield expect(auth_service_1.default.getAuthenticatedUser(mockReq)).rejects.toBeInstanceOf(app_error_1.default);
|
|
204
|
-
}));
|
|
205
|
-
it("should extract token from Authorization header", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
206
|
-
const token = "bearer-token-123";
|
|
207
|
-
mockReq.headers.authorization = `Bearer ${token}`;
|
|
208
|
-
const decodedToken = { id: "user-123", iat: 1617123456 };
|
|
209
|
-
auth_service_1.default.verifyJwtToken = jest
|
|
210
|
-
.fn()
|
|
211
|
-
.mockResolvedValue(decodedToken);
|
|
212
|
-
const mockUser = { id: "user-123", username: "testuser" };
|
|
213
|
-
mockPrisma.user.findUnique.mockResolvedValue(mockUser);
|
|
214
|
-
const result = yield auth_service_1.default.getAuthenticatedUser(mockReq);
|
|
215
|
-
expect(auth_service_1.default.verifyJwtToken).toHaveBeenCalledWith(token);
|
|
216
|
-
expect(mockPrisma.user.findUnique).toHaveBeenCalledWith({
|
|
217
|
-
where: { id: "user-123" },
|
|
218
|
-
include: expect.objectContaining({
|
|
219
|
-
roles: expect.any(Object),
|
|
220
|
-
}),
|
|
221
|
-
});
|
|
222
|
-
expect(result).toEqual(mockUser);
|
|
223
|
-
}));
|
|
224
|
-
it("should extract token from cookies", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
225
|
-
const token = "cookie-token-123";
|
|
226
|
-
mockReq.cookies = { arkos_access_token: token };
|
|
227
|
-
const decodedToken = { id: "user-123", iat: 1617123456 };
|
|
228
|
-
auth_service_1.default.verifyJwtToken = jest
|
|
229
|
-
.fn()
|
|
230
|
-
.mockResolvedValue(decodedToken);
|
|
231
|
-
const mockUser = { id: "user-123", username: "testuser" };
|
|
232
|
-
mockPrisma.user.findUnique.mockResolvedValue(mockUser);
|
|
233
|
-
const result = yield auth_service_1.default.getAuthenticatedUser(mockReq);
|
|
234
|
-
expect(auth_service_1.default.verifyJwtToken).toHaveBeenCalledWith(token);
|
|
235
|
-
expect(mockPrisma.user.findUnique).toHaveBeenCalled();
|
|
236
|
-
expect(result).toEqual(mockUser);
|
|
237
|
-
}));
|
|
238
|
-
it("should throw an error if token verification fails", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
239
|
-
mockReq.headers.authorization = "Bearer invalid-token";
|
|
240
|
-
auth_service_1.default.verifyJwtToken = jest
|
|
241
|
-
.fn()
|
|
242
|
-
.mockRejectedValue(new Error("Token invalid"));
|
|
243
|
-
yield expect(auth_service_1.default.getAuthenticatedUser(mockReq)).rejects.toBeInstanceOf(app_error_1.default);
|
|
244
|
-
}));
|
|
245
|
-
it("should throw an error if decoded token has no id", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
246
|
-
mockReq.headers.authorization = "Bearer token-without-id";
|
|
247
|
-
auth_service_1.default.verifyJwtToken = jest.fn().mockResolvedValue({});
|
|
248
|
-
yield expect(auth_service_1.default.getAuthenticatedUser(mockReq)).rejects.toBeInstanceOf(app_error_1.default);
|
|
249
|
-
}));
|
|
250
|
-
it("should throw an error if user does not exist", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
251
|
-
mockReq.headers.authorization = "Bearer valid-token";
|
|
252
|
-
auth_service_1.default.verifyJwtToken = jest
|
|
253
|
-
.fn()
|
|
254
|
-
.mockResolvedValue({ id: "non-existent-user" });
|
|
255
|
-
mockPrisma.user.findUnique.mockResolvedValue(null);
|
|
256
|
-
yield expect(auth_service_1.default.getAuthenticatedUser(mockReq)).rejects.toBeInstanceOf(app_error_1.default);
|
|
257
|
-
}));
|
|
258
|
-
it("should throw an error if user changed password after token was issued", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
259
|
-
mockReq.headers.authorization = "Bearer valid-token";
|
|
260
|
-
const decodedToken = { id: "user-123", iat: 1617123456 };
|
|
261
|
-
auth_service_1.default.verifyJwtToken = jest
|
|
262
|
-
.fn()
|
|
263
|
-
.mockResolvedValue(decodedToken);
|
|
264
|
-
const mockUser = {
|
|
265
|
-
id: "user-123",
|
|
266
|
-
username: "testuser",
|
|
267
|
-
passwordChangedAt: new Date(Date.now()),
|
|
268
|
-
};
|
|
269
|
-
mockPrisma.user.findUnique.mockResolvedValue(mockUser);
|
|
270
|
-
auth_service_1.default.userChangedPasswordAfter = jest
|
|
271
|
-
.fn()
|
|
272
|
-
.mockReturnValue(true);
|
|
273
|
-
yield expect(auth_service_1.default.getAuthenticatedUser(mockReq)).rejects.toBeInstanceOf(app_error_1.default);
|
|
274
|
-
}));
|
|
275
|
-
it("should not throw password changed error if path includes logout", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
276
|
-
mockReq.headers.authorization = "Bearer valid-token";
|
|
277
|
-
mockReq.path = "/auth/logout";
|
|
278
|
-
const decodedToken = { id: "user-123", iat: 1617123456 };
|
|
279
|
-
auth_service_1.default.verifyJwtToken = jest
|
|
280
|
-
.fn()
|
|
281
|
-
.mockResolvedValue(decodedToken);
|
|
282
|
-
const mockUser = {
|
|
283
|
-
id: "user-123",
|
|
284
|
-
username: "testuser",
|
|
285
|
-
passwordChangedAt: new Date(Date.now()),
|
|
286
|
-
};
|
|
287
|
-
mockPrisma.user.findUnique.mockResolvedValue(mockUser);
|
|
288
|
-
auth_service_1.default.userChangedPasswordAfter = jest
|
|
289
|
-
.fn()
|
|
290
|
-
.mockReturnValue(true);
|
|
291
|
-
const result = yield auth_service_1.default.getAuthenticatedUser(mockReq);
|
|
292
|
-
expect(result).toEqual(mockUser);
|
|
293
|
-
}));
|
|
294
|
-
});
|
|
295
|
-
describe("authenticate", () => {
|
|
296
|
-
it("should call next() if authentication is disabled", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
297
|
-
server_1.getArkosConfig.mockReturnValue({ authentication: null });
|
|
298
|
-
yield auth_service_1.default.authenticate(mockReq, mockRes, mockNext);
|
|
299
|
-
expect(mockNext).toHaveBeenCalled();
|
|
300
|
-
expect(mockReq.user).toBeNull();
|
|
301
|
-
}));
|
|
302
|
-
it("should set user on request and call next()", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
303
|
-
const mockUser = { id: "user-123", username: "testuser" };
|
|
304
|
-
auth_service_1.default.getAuthenticatedUser = jest
|
|
305
|
-
.fn()
|
|
306
|
-
.mockResolvedValue(mockUser);
|
|
307
|
-
yield auth_service_1.default.authenticate(mockReq, mockRes, mockNext);
|
|
308
|
-
expect(auth_service_1.default.getAuthenticatedUser).toHaveBeenCalledWith(mockReq);
|
|
309
|
-
expect(mockReq.user).toEqual(mockUser);
|
|
310
|
-
expect(mockNext).toHaveBeenCalled();
|
|
311
|
-
}));
|
|
312
|
-
});
|
|
313
|
-
describe("handleActionAccessControl", () => {
|
|
314
|
-
it("should allow access for superusers and call next()", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
315
|
-
mockReq.user = {
|
|
316
|
-
id: "admin-123",
|
|
317
|
-
username: "admin",
|
|
318
|
-
isSuperUser: true,
|
|
319
|
-
};
|
|
320
|
-
const accessControlMiddleware = auth_service_1.default.handleActionAccessControl({}, "create", "User");
|
|
321
|
-
yield accessControlMiddleware(mockReq, mockRes, mockNext);
|
|
322
|
-
expect(mockNext).toHaveBeenCalled();
|
|
323
|
-
}));
|
|
324
|
-
it("should check dynamic permissions when authentication mode is dynamic", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
325
|
-
mockReq.user = {
|
|
326
|
-
id: "user-123",
|
|
327
|
-
username: "testuser",
|
|
328
|
-
isSuperUser: false,
|
|
329
|
-
roles: [{ roleId: 1 }, { roleId: 2 }],
|
|
330
|
-
};
|
|
331
|
-
mockConfig.authentication.mode = "dynamic";
|
|
332
|
-
mockPrisma.authPermission.count.mockResolvedValue(1);
|
|
333
|
-
const accessControlMiddleware = auth_service_1.default.handleActionAccessControl({}, "create", "Users");
|
|
334
|
-
yield accessControlMiddleware(mockReq, mockRes, mockNext);
|
|
335
|
-
expect(mockPrisma.authPermission.count).toHaveBeenCalledWith({
|
|
336
|
-
where: {
|
|
337
|
-
resource: "user",
|
|
338
|
-
action: "create",
|
|
339
|
-
roleId: { in: [1, 2] },
|
|
340
|
-
},
|
|
341
|
-
});
|
|
342
|
-
expect(mockNext).toHaveBeenCalled();
|
|
343
|
-
}));
|
|
344
|
-
it("should deny access if no dynamic permissions found", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
345
|
-
mockReq.user = {
|
|
346
|
-
id: "user-123",
|
|
347
|
-
username: "testuser",
|
|
348
|
-
isSuperUser: false,
|
|
349
|
-
roles: [{ roleId: 1 }],
|
|
350
|
-
};
|
|
351
|
-
mockConfig.authentication.mode = "dynamic";
|
|
352
|
-
mockPrisma.authPermission.count.mockResolvedValue(0);
|
|
353
|
-
const accessControlMiddleware = auth_service_1.default.handleActionAccessControl({}, "create", "Users");
|
|
354
|
-
app_error_1.default.mockImplementation((message, code) => {
|
|
355
|
-
return { message, statusCode: code };
|
|
356
|
-
});
|
|
357
|
-
yield accessControlMiddleware(mockReq, mockRes, mockNext);
|
|
358
|
-
expect(mockNext).toHaveBeenCalledWith(expect.objectContaining({
|
|
359
|
-
message: "You do not have permission to perfom this action",
|
|
360
|
-
statusCode: 403,
|
|
361
|
-
}));
|
|
362
|
-
}));
|
|
363
|
-
it("should check static permissions when authentication mode is static", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
364
|
-
mockReq.user = {
|
|
365
|
-
id: "user-123",
|
|
366
|
-
username: "testuser",
|
|
367
|
-
role: "editor",
|
|
368
|
-
roles: [],
|
|
369
|
-
isSuperUser: false,
|
|
370
|
-
};
|
|
371
|
-
mockConfig.authentication.mode = "static";
|
|
372
|
-
const authConfigs = {
|
|
373
|
-
accessControl: {
|
|
374
|
-
create: ["admin", "editor"],
|
|
375
|
-
},
|
|
376
|
-
};
|
|
377
|
-
const accessControlMiddleware = auth_service_1.default.handleActionAccessControl(authConfigs, "create", "Post");
|
|
378
|
-
yield accessControlMiddleware(mockReq, mockRes, mockNext);
|
|
379
|
-
expect(mockNext).toHaveBeenCalled();
|
|
380
|
-
}));
|
|
381
|
-
it("should deny access if role is not in static accessControl list", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
382
|
-
mockReq.user = {
|
|
383
|
-
id: "user-123",
|
|
384
|
-
username: "testuser",
|
|
385
|
-
role: "viewer",
|
|
386
|
-
roles: [],
|
|
387
|
-
isSuperUser: false,
|
|
388
|
-
};
|
|
389
|
-
mockConfig.authentication.mode = "static";
|
|
390
|
-
const authConfigs = {
|
|
391
|
-
accessControl: {
|
|
392
|
-
create: ["admin", "editor"],
|
|
393
|
-
},
|
|
394
|
-
};
|
|
395
|
-
const accessControlMiddleware = auth_service_1.default.handleActionAccessControl(authConfigs, "create", "Post");
|
|
396
|
-
app_error_1.default.mockImplementation((message, code) => {
|
|
397
|
-
return { message, statusCode: code };
|
|
398
|
-
});
|
|
399
|
-
yield accessControlMiddleware(mockReq, mockRes, mockNext);
|
|
400
|
-
expect(mockNext).toHaveBeenCalledWith(expect.objectContaining({
|
|
401
|
-
message: "You do not have permission to perfom this action",
|
|
402
|
-
statusCode: 403,
|
|
403
|
-
}));
|
|
404
|
-
}));
|
|
405
|
-
it("should handle array-based accessControl configuration", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
406
|
-
mockReq.user = {
|
|
407
|
-
id: "user-123",
|
|
408
|
-
username: "testuser",
|
|
409
|
-
role: "admin",
|
|
410
|
-
roles: [],
|
|
411
|
-
isSuperUser: false,
|
|
412
|
-
};
|
|
413
|
-
mockConfig.authentication.mode = "static";
|
|
414
|
-
const authConfigs = {
|
|
415
|
-
accessControl: ["admin", "editor"],
|
|
416
|
-
};
|
|
417
|
-
const accessControlMiddleware = auth_service_1.default.handleActionAccessControl(authConfigs, "create", "Post");
|
|
418
|
-
yield accessControlMiddleware(mockReq, mockRes, mockNext);
|
|
419
|
-
expect(mockNext).toHaveBeenCalled();
|
|
420
|
-
}));
|
|
421
|
-
it("should check multiple roles when user has roles array", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
422
|
-
mockReq.user = {
|
|
423
|
-
id: "user-123",
|
|
424
|
-
username: "testuser",
|
|
425
|
-
role: "viewer",
|
|
426
|
-
roles: ["editor", "contributor"],
|
|
427
|
-
isSuperUser: false,
|
|
428
|
-
};
|
|
429
|
-
mockConfig.authentication.mode = "static";
|
|
430
|
-
const authConfigs = {
|
|
431
|
-
accessControl: {
|
|
432
|
-
create: ["admin", "editor"],
|
|
433
|
-
},
|
|
434
|
-
};
|
|
435
|
-
const accessControlMiddleware = auth_service_1.default.handleActionAccessControl(authConfigs, "create", "Post");
|
|
436
|
-
yield accessControlMiddleware(mockReq, mockRes, mockNext);
|
|
437
|
-
expect(mockNext).toHaveBeenCalled();
|
|
438
|
-
}));
|
|
439
|
-
});
|
|
440
|
-
describe("handleAuthenticationControl", () => {
|
|
441
|
-
it("should return callNext if authentication control for action is false", () => {
|
|
442
|
-
const authConfigs = {
|
|
443
|
-
authenticationControl: {
|
|
444
|
-
view: false,
|
|
445
|
-
},
|
|
446
|
-
};
|
|
447
|
-
const middleware = auth_service_1.default.handleAuthenticationControl(authConfigs, "view", "User");
|
|
448
|
-
expect(middleware.name).toBe("callNext");
|
|
449
|
-
});
|
|
450
|
-
it("should return authenticate middleware if authentication control for action is true", () => {
|
|
451
|
-
const authConfigs = {
|
|
452
|
-
authenticationControl: {
|
|
453
|
-
create: true,
|
|
454
|
-
},
|
|
455
|
-
};
|
|
456
|
-
const middleware = auth_service_1.default.handleAuthenticationControl(authConfigs, "create", "User");
|
|
457
|
-
expect(middleware).toBe(auth_service_1.default.authenticate);
|
|
458
|
-
});
|
|
459
|
-
it("should return authenticate middleware if authenticationControl is not specified", () => {
|
|
460
|
-
const authConfigs = {};
|
|
461
|
-
const middleware = auth_service_1.default.handleAuthenticationControl(authConfigs, "update", "User");
|
|
462
|
-
expect(middleware).toBe(auth_service_1.default.authenticate);
|
|
463
|
-
});
|
|
464
|
-
it("should return authenticate middleware if authConfigs is undefined", () => {
|
|
465
|
-
const middleware = auth_service_1.default.handleAuthenticationControl(undefined, "delete", "User");
|
|
466
|
-
expect(middleware).toBe(auth_service_1.default.authenticate);
|
|
467
|
-
});
|
|
468
|
-
});
|
|
469
|
-
});
|
|
470
|
-
//# sourceMappingURL=auth.service.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auth.service.test.js","sourceRoot":"","sources":["../../../../../src/modules/auth/__tests__/auth.service.test.ts"],"names":[],"mappings":"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","sourcesContent":["import jwt from \"jsonwebtoken\";\nimport bcrypt from \"bcryptjs\";\nimport authService from \"../auth.service\";\nimport { getPrismaInstance } from \"../../../utils/helpers/prisma.helpers\";\nimport { getArkosConfig } from \"../../../server\";\nimport AppError from \"../../error-handler/utils/app-error\";\n\n// Mock dependencies\njest.mock(\"jsonwebtoken\");\njest.mock(\"bcryptjs\");\njest.mock(\"../../../utils/helpers/prisma.helpers\");\njest.mock(\"../../../server\");\njest.mock(\"../../error-handler/utils/app-error\");\n\njest.mock(\"../../../utils/helpers/models.helpers\", () => ({\n getModels: jest.fn().mockReturnValue([]),\n getModelFields: jest.fn().mockReturnValue([]),\n getPrismaModels: jest.fn().mockReturnValue([]),\n}));\n\ndescribe(\"AuthService\", () => {\n let mockReq: any;\n let mockRes: any;\n let mockNext: any;\n let mockPrisma: any;\n let mockConfig: any;\n\n beforeEach(() => {\n // Reset all mocks\n jest.resetAllMocks();\n\n // Setup mock request, response, and next function\n mockReq = {\n headers: {},\n cookies: {},\n path: \"/test\",\n user: null,\n };\n\n mockRes = {\n status: jest.fn().mockReturnThis(),\n json: jest.fn(),\n };\n\n mockNext = jest.fn();\n\n // Setup mock Prisma client\n mockPrisma = {\n user: {\n findUnique: jest.fn(),\n update: jest.fn(),\n },\n authPermission: {\n count: jest.fn(),\n },\n };\n\n (getPrismaInstance as jest.Mock).mockReturnValue(mockPrisma);\n\n // Setup mock Arkos config\n mockConfig = {\n authentication: {\n mode: \"static\",\n passwordValidation: {\n regex: /^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d).+$/,\n message:\n \"Password must contain at least one uppercase letter, one lowercase letter, and one number\",\n },\n },\n };\n\n (getArkosConfig as jest.Mock).mockReturnValue(mockConfig);\n });\n\n describe(\"signJwtToken\", () => {\n it(\"should sign a JWT token with the provided id\", () => {\n // Setup\n const userId = \"user-123\";\n const mockToken = \"mock-jwt-token\";\n (jwt.sign as jest.Mock).mockReturnValue(mockToken);\n\n // Execute\n const result = authService.signJwtToken(userId);\n\n // Verify\n expect(jwt.sign).toHaveBeenCalledWith(\n { id: userId },\n expect.any(String),\n { expiresIn: expect.any(String) }\n );\n expect(result).toBe(mockToken);\n });\n\n it(\"should use custom expiresIn and secret when provided\", () => {\n // Setup\n const userId = \"user-123\";\n const expiresIn = \"1h\";\n const secret = \"custom-secret\";\n const mockToken = \"mock-jwt-token\";\n (jwt.sign as jest.Mock).mockReturnValue(mockToken);\n\n // Execute\n const result = authService.signJwtToken(userId, expiresIn, secret);\n\n // Verify\n expect(jwt.sign).toHaveBeenCalledWith({ id: userId }, secret, {\n expiresIn,\n });\n expect(result).toBe(mockToken);\n });\n });\n\n describe(\"isCorrectPassword\", () => {\n it(\"should return true if passwords match\", async () => {\n // Setup\n const candidatePassword = \"password123\";\n const userPassword = \"hashedPassword\";\n (bcrypt.compare as jest.Mock).mockResolvedValue(true);\n\n // Execute\n const result = await authService.isCorrectPassword(\n candidatePassword,\n userPassword\n );\n\n // Verify\n expect(bcrypt.compare).toHaveBeenCalledWith(\n candidatePassword,\n userPassword\n );\n expect(result).toBe(true);\n });\n\n it(\"should return false if passwords do not match\", async () => {\n // Setup\n const candidatePassword = \"wrongPassword\";\n const userPassword = \"hashedPassword\";\n (bcrypt.compare as jest.Mock).mockResolvedValue(false);\n\n // Execute\n const result = await authService.isCorrectPassword(\n candidatePassword,\n userPassword\n );\n\n // Verify\n expect(bcrypt.compare).toHaveBeenCalledWith(\n candidatePassword,\n userPassword\n );\n expect(result).toBe(false);\n });\n });\n\n describe(\"hashPassword\", () => {\n it(\"should hash the password using bcrypt\", async () => {\n // Setup\n const password = \"password123\";\n const hashedPassword = \"hashedPassword123\";\n (bcrypt.hash as jest.Mock).mockResolvedValue(hashedPassword);\n\n // Execute\n const result = await authService.hashPassword(password);\n\n // Verify\n expect(bcrypt.hash).toHaveBeenCalledWith(password, 12);\n expect(result).toBe(hashedPassword);\n });\n });\n\n describe(\"isPasswordStrong\", () => {\n it(\"should return true for a strong password matching the regex\", () => {\n // Setup\n const strongPassword = \"Password123\";\n\n // Execute\n const result = authService.isPasswordStrong(strongPassword);\n\n // Verify\n expect(result).toBe(true);\n });\n\n it(\"should return false for a weak password not matching the regex\", () => {\n // Setup\n const weakPassword = \"password\";\n\n // Execute\n const result = authService.isPasswordStrong(weakPassword);\n\n // Verify\n expect(result).toBe(false);\n });\n\n it(\"should use custom regex from arkos config when available\", () => {\n // Setup\n mockConfig.authentication.passwordValidation.regex =\n /^(?=.*[A-Z])(?=.*[0-9]).{8,}$/;\n const password = \"PASSWORD123\"; // Has uppercase and numbers, no lowercase\n\n // Execute\n const result = authService.isPasswordStrong(password);\n\n // Verify\n expect(result).toBe(true);\n });\n });\n\n describe(\"userChangedPasswordAfter\", () => {\n it(\"should return true if password was changed after JWT was issued\", () => {\n // Setup\n const user = {\n passwordChangedAt: new Date(Date.now() + 1000), // 1 second in the future\n } as any;\n const jwtTimestamp = Math.floor(Date.now() / 1000);\n\n // Execute\n const result = authService.userChangedPasswordAfter(user, jwtTimestamp);\n\n // Verify\n expect(result).toBe(true);\n });\n\n it(\"should return false if password was changed before JWT was issued\", () => {\n // Setup\n const user = {\n passwordChangedAt: new Date(Date.now() - 1000), // 1 second in the past\n } as any;\n const jwtTimestamp = Math.floor(Date.now() / 1000);\n\n // Execute\n const result = authService.userChangedPasswordAfter(user, jwtTimestamp);\n\n // Verify\n expect(result).toBe(false);\n });\n\n it(\"should return false if passwordChangedAt is not set\", () => {\n // Setup\n const user = {} as any;\n const jwtTimestamp = Math.floor(Date.now() / 1000);\n\n // Execute\n const result = authService.userChangedPasswordAfter(user, jwtTimestamp);\n\n // Verify\n expect(result).toBe(false);\n });\n });\n\n describe(\"verifyJwtToken\", () => {\n it(\"should resolve with decoded payload for valid token\", async () => {\n // Setup\n const token = \"valid-token\";\n const decodedPayload = { id: \"user-123\", iat: 1617123456 };\n\n // Mock jwt.verify to call the callback with decoded payload\n (jwt.verify as jest.Mock).mockImplementation(\n (token, secret, callback) => {\n callback(null, decodedPayload);\n }\n );\n\n // Execute\n const result = await authService.verifyJwtToken(token);\n\n // Verify\n expect(jwt.verify).toHaveBeenCalledWith(\n token,\n expect.any(String),\n expect.any(Function)\n );\n expect(result).toEqual(decodedPayload);\n });\n\n it(\"should reject with error for invalid token\", async () => {\n // Setup\n const token = \"invalid-token\";\n const jwtError = new Error(\"Invalid token\");\n\n // Mock jwt.verify to call the callback with an error\n (jwt.verify as jest.Mock).mockImplementation(\n (token, secret, callback) => {\n callback(jwtError, null);\n }\n );\n\n // Execute and Verify\n await expect(authService.verifyJwtToken(token)).rejects.toEqual(jwtError);\n expect(jwt.verify).toHaveBeenCalledWith(\n token,\n expect.any(String),\n expect.any(Function)\n );\n });\n\n it(\"should use custom secret when provided\", async () => {\n // Setup\n const token = \"valid-token\";\n const customSecret = \"custom-secret-key\";\n const decodedPayload = { id: \"user-123\", iat: 1617123456 };\n\n // Mock jwt.verify to call the callback with decoded payload\n (jwt.verify as jest.Mock).mockImplementation(\n (token, secret, callback) => {\n callback(null, decodedPayload);\n }\n );\n\n // Execute\n await authService.verifyJwtToken(token, customSecret);\n\n // Verify\n expect(jwt.verify).toHaveBeenCalledWith(\n token,\n customSecret,\n expect.any(Function)\n );\n });\n });\n\n describe(\"getAuthenticatedUser\", () => {\n it(\"should return null if authentication is disabled in config\", async () => {\n // Setup\n (getArkosConfig as jest.Mock).mockReturnValue({ authentication: null });\n\n // Execute\n const result = await authService.getAuthenticatedUser(mockReq);\n\n // Verify\n expect(result).toBeNull();\n });\n\n it(\"should throw an error if no token is found\", async () => {\n // Setup - No token in request\n mockReq = {};\n\n // Execute and Verify\n\n await expect(\n authService.getAuthenticatedUser(mockReq)\n ).rejects.toBeInstanceOf(AppError);\n });\n\n it(\"should extract token from Authorization header\", async () => {\n // Setup\n const token = \"bearer-token-123\";\n mockReq.headers.authorization = `Bearer ${token}`;\n\n const decodedToken = { id: \"user-123\", iat: 1617123456 };\n (authService.verifyJwtToken as any) = jest\n .fn()\n .mockResolvedValue(decodedToken);\n\n const mockUser = { id: \"user-123\", username: \"testuser\" };\n mockPrisma.user.findUnique.mockResolvedValue(mockUser);\n\n // Execute\n const result = await authService.getAuthenticatedUser(mockReq);\n\n // Verify\n expect(authService.verifyJwtToken).toHaveBeenCalledWith(token);\n expect(mockPrisma.user.findUnique).toHaveBeenCalledWith({\n where: { id: \"user-123\" },\n include: expect.objectContaining({\n roles: expect.any(Object),\n }),\n });\n expect(result).toEqual(mockUser);\n });\n\n it(\"should extract token from cookies\", async () => {\n // Setup\n const token = \"cookie-token-123\";\n mockReq.cookies = { arkos_access_token: token };\n\n const decodedToken = { id: \"user-123\", iat: 1617123456 };\n (authService.verifyJwtToken as any) = jest\n .fn()\n .mockResolvedValue(decodedToken);\n\n const mockUser = { id: \"user-123\", username: \"testuser\" };\n mockPrisma.user.findUnique.mockResolvedValue(mockUser);\n\n // Execute\n const result = await authService.getAuthenticatedUser(mockReq);\n\n // Verify\n expect(authService.verifyJwtToken).toHaveBeenCalledWith(token);\n expect(mockPrisma.user.findUnique).toHaveBeenCalled();\n expect(result).toEqual(mockUser);\n });\n\n it(\"should throw an error if token verification fails\", async () => {\n // Setup\n mockReq.headers.authorization = \"Bearer invalid-token\";\n (authService.verifyJwtToken as any) = jest\n .fn()\n .mockRejectedValue(new Error(\"Token invalid\"));\n\n // Execute and Verify\n await expect(\n authService.getAuthenticatedUser(mockReq)\n ).rejects.toBeInstanceOf(AppError);\n });\n\n it(\"should throw an error if decoded token has no id\", async () => {\n // Setup\n mockReq.headers.authorization = \"Bearer token-without-id\";\n (authService.verifyJwtToken as any) = jest.fn().mockResolvedValue({});\n\n // Execute and Verify\n await expect(\n authService.getAuthenticatedUser(mockReq)\n ).rejects.toBeInstanceOf(AppError);\n });\n\n it(\"should throw an error if user does not exist\", async () => {\n // Setup\n mockReq.headers.authorization = \"Bearer valid-token\";\n (authService.verifyJwtToken as any) = jest\n .fn()\n .mockResolvedValue({ id: \"non-existent-user\" });\n mockPrisma.user.findUnique.mockResolvedValue(null);\n\n // Execute and Verify\n await expect(\n authService.getAuthenticatedUser(mockReq)\n ).rejects.toBeInstanceOf(AppError);\n });\n\n it(\"should throw an error if user changed password after token was issued\", async () => {\n // Setup\n mockReq.headers.authorization = \"Bearer valid-token\";\n const decodedToken = { id: \"user-123\", iat: 1617123456 };\n (authService.verifyJwtToken as any) = jest\n .fn()\n .mockResolvedValue(decodedToken);\n\n const mockUser = {\n id: \"user-123\",\n username: \"testuser\",\n passwordChangedAt: new Date(Date.now()),\n };\n mockPrisma.user.findUnique.mockResolvedValue(mockUser);\n\n // Mock the userChangedPasswordAfter method to return true\n (authService.userChangedPasswordAfter as any) = jest\n .fn()\n .mockReturnValue(true);\n\n // Execute and Verify\n await expect(\n authService.getAuthenticatedUser(mockReq)\n ).rejects.toBeInstanceOf(AppError);\n });\n\n it(\"should not throw password changed error if path includes logout\", async () => {\n // Setup\n mockReq.headers.authorization = \"Bearer valid-token\";\n mockReq.path = \"/auth/logout\";\n\n const decodedToken = { id: \"user-123\", iat: 1617123456 };\n (authService.verifyJwtToken as any) = jest\n .fn()\n .mockResolvedValue(decodedToken);\n\n const mockUser = {\n id: \"user-123\",\n username: \"testuser\",\n passwordChangedAt: new Date(Date.now()),\n };\n mockPrisma.user.findUnique.mockResolvedValue(mockUser);\n\n // Mock the userChangedPasswordAfter method to return true\n (authService.userChangedPasswordAfter as any) = jest\n .fn()\n .mockReturnValue(true);\n\n // Execute\n const result = await authService.getAuthenticatedUser(mockReq);\n\n // Verify\n expect(result).toEqual(mockUser);\n });\n });\n\n describe(\"authenticate\", () => {\n it(\"should call next() if authentication is disabled\", async () => {\n // Setup\n (getArkosConfig as jest.Mock).mockReturnValue({ authentication: null });\n\n // Execute\n await authService.authenticate(mockReq, mockRes, mockNext);\n\n // Verify\n expect(mockNext).toHaveBeenCalled();\n expect(mockReq.user).toBeNull();\n });\n\n it(\"should set user on request and call next()\", async () => {\n // Setup\n const mockUser = { id: \"user-123\", username: \"testuser\" };\n (authService.getAuthenticatedUser as any) = jest\n .fn()\n .mockResolvedValue(mockUser);\n\n // Execute\n await authService.authenticate(mockReq, mockRes, mockNext);\n\n // Verify\n expect(authService.getAuthenticatedUser).toHaveBeenCalledWith(mockReq);\n expect(mockReq.user).toEqual(mockUser);\n expect(mockNext).toHaveBeenCalled();\n });\n });\n\n describe(\"handleActionAccessControl\", () => {\n it(\"should allow access for superusers and call next()\", async () => {\n // Setup\n mockReq.user = {\n id: \"admin-123\",\n username: \"admin\",\n isSuperUser: true,\n };\n\n const accessControlMiddleware = authService.handleActionAccessControl(\n {},\n \"create\",\n \"User\"\n );\n\n // Execute\n await accessControlMiddleware(mockReq, mockRes, mockNext);\n\n // Verify\n expect(mockNext).toHaveBeenCalled();\n });\n\n it(\"should check dynamic permissions when authentication mode is dynamic\", async () => {\n // Setup\n mockReq.user = {\n id: \"user-123\",\n username: \"testuser\",\n isSuperUser: false,\n roles: [{ roleId: 1 }, { roleId: 2 }],\n };\n\n mockConfig.authentication.mode = \"dynamic\";\n\n mockPrisma.authPermission.count.mockResolvedValue(1); // User has permission\n\n const accessControlMiddleware = authService.handleActionAccessControl(\n {},\n \"create\",\n \"Users\"\n );\n\n // Execute\n await accessControlMiddleware(mockReq, mockRes, mockNext);\n\n // Verify\n expect(mockPrisma.authPermission.count).toHaveBeenCalledWith({\n where: {\n resource: \"user\",\n action: \"create\",\n roleId: { in: [1, 2] },\n },\n });\n expect(mockNext).toHaveBeenCalled();\n });\n\n it(\"should deny access if no dynamic permissions found\", async () => {\n // Setup\n mockReq.user = {\n id: \"user-123\",\n username: \"testuser\",\n isSuperUser: false,\n roles: [{ roleId: 1 }],\n };\n\n mockConfig.authentication.mode = \"dynamic\";\n\n mockPrisma.authPermission.count.mockResolvedValue(0); // No permissions\n\n const accessControlMiddleware = authService.handleActionAccessControl(\n {},\n \"create\",\n \"Users\"\n );\n\n // Create mock AppError constructor\n (AppError as unknown as jest.Mock).mockImplementation((message, code) => {\n return { message, statusCode: code };\n });\n\n // Execute\n await accessControlMiddleware(mockReq, mockRes, mockNext);\n\n // Verify\n expect(mockNext).toHaveBeenCalledWith(\n expect.objectContaining({\n message: \"You do not have permission to perfom this action\",\n statusCode: 403,\n })\n );\n });\n\n it(\"should check static permissions when authentication mode is static\", async () => {\n // Setup\n mockReq.user = {\n id: \"user-123\",\n username: \"testuser\",\n role: \"editor\",\n roles: [],\n isSuperUser: false,\n };\n\n mockConfig.authentication.mode = \"static\";\n\n const authConfigs = {\n accessControl: {\n create: [\"admin\", \"editor\"],\n },\n };\n\n const accessControlMiddleware = authService.handleActionAccessControl(\n authConfigs,\n \"create\",\n \"Post\"\n );\n\n // Execute\n await accessControlMiddleware(mockReq, mockRes, mockNext);\n\n // Verify\n expect(mockNext).toHaveBeenCalled();\n });\n\n it(\"should deny access if role is not in static accessControl list\", async () => {\n // Setup\n mockReq.user = {\n id: \"user-123\",\n username: \"testuser\",\n role: \"viewer\",\n roles: [],\n isSuperUser: false,\n };\n\n mockConfig.authentication.mode = \"static\";\n\n const authConfigs = {\n accessControl: {\n create: [\"admin\", \"editor\"],\n },\n };\n\n const accessControlMiddleware = authService.handleActionAccessControl(\n authConfigs,\n \"create\",\n \"Post\"\n );\n\n // Create mock AppError constructor\n (AppError as unknown as jest.Mock).mockImplementation((message, code) => {\n return { message, statusCode: code };\n });\n\n // Execute\n await accessControlMiddleware(mockReq, mockRes, mockNext);\n\n // Verify\n expect(mockNext).toHaveBeenCalledWith(\n expect.objectContaining({\n message: \"You do not have permission to perfom this action\",\n statusCode: 403,\n })\n );\n });\n\n it(\"should handle array-based accessControl configuration\", async () => {\n // Setup\n mockReq.user = {\n id: \"user-123\",\n username: \"testuser\",\n role: \"admin\",\n roles: [],\n isSuperUser: false,\n };\n\n mockConfig.authentication.mode = \"static\";\n\n const authConfigs = {\n accessControl: [\"admin\", \"editor\"],\n };\n\n const accessControlMiddleware = authService.handleActionAccessControl(\n authConfigs,\n \"create\",\n \"Post\"\n );\n\n // Execute\n await accessControlMiddleware(mockReq, mockRes, mockNext);\n\n // Verify\n expect(mockNext).toHaveBeenCalled();\n });\n\n it(\"should check multiple roles when user has roles array\", async () => {\n // Setup\n mockReq.user = {\n id: \"user-123\",\n username: \"testuser\",\n role: \"viewer\",\n roles: [\"editor\", \"contributor\"],\n isSuperUser: false,\n };\n\n mockConfig.authentication.mode = \"static\";\n\n const authConfigs = {\n accessControl: {\n create: [\"admin\", \"editor\"],\n },\n };\n\n const accessControlMiddleware = authService.handleActionAccessControl(\n authConfigs,\n \"create\",\n \"Post\"\n );\n\n // Execute\n await accessControlMiddleware(mockReq, mockRes, mockNext);\n\n // Verify\n expect(mockNext).toHaveBeenCalled();\n });\n });\n\n describe(\"handleAuthenticationControl\", () => {\n it(\"should return callNext if authentication control for action is false\", () => {\n // Setup\n const authConfigs = {\n authenticationControl: {\n view: false,\n },\n };\n\n // Execute\n const middleware = authService.handleAuthenticationControl(\n authConfigs,\n \"view\",\n \"User\"\n );\n\n // Verify\n expect(middleware.name).toBe(\"callNext\");\n });\n\n it(\"should return authenticate middleware if authentication control for action is true\", () => {\n // Setup\n const authConfigs = {\n authenticationControl: {\n create: true,\n },\n };\n\n // Execute\n const middleware = authService.handleAuthenticationControl(\n authConfigs,\n \"create\",\n \"User\"\n );\n\n // Verify\n expect(middleware).toBe(authService.authenticate);\n });\n\n it(\"should return authenticate middleware if authenticationControl is not specified\", () => {\n // Setup\n const authConfigs = {};\n\n // Execute\n const middleware = authService.handleAuthenticationControl(\n authConfigs,\n \"update\",\n \"User\"\n );\n\n // Verify\n expect(middleware).toBe(authService.authenticate);\n });\n\n it(\"should return authenticate middleware if authConfigs is undefined\", () => {\n // Execute\n const middleware = authService.handleAuthenticationControl(\n undefined,\n \"delete\",\n \"User\"\n );\n\n // Verify\n expect(middleware).toBe(authService.authenticate);\n });\n });\n});\n"]}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
const server_1 = require("../../../../../server");
|
|
13
|
-
const auth_helpers_1 = require("../auth.helpers");
|
|
14
|
-
jest.mock("../../../../../server", () => ({
|
|
15
|
-
getArkosConfig: jest.fn(),
|
|
16
|
-
close: jest.fn(),
|
|
17
|
-
}));
|
|
18
|
-
jest.mock("fs", () => ({
|
|
19
|
-
default: Object.assign(Object.assign({}, jest.requireActual("fs")), { readdirSync: jest.fn(() => ["test.prisma"]), statSync: jest.fn(() => ({
|
|
20
|
-
isFile: jest.fn(),
|
|
21
|
-
})), existsSync: jest.fn(() => false), mkdirSync: jest.fn(), unlink: jest.fn(), access: jest.fn() }),
|
|
22
|
-
}));
|
|
23
|
-
describe("determineUsernameField", () => {
|
|
24
|
-
it("should use query parameter usernameField when provided", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
25
|
-
const testReq = {
|
|
26
|
-
query: { usernameField: "email" },
|
|
27
|
-
};
|
|
28
|
-
expect((0, auth_helpers_1.determineUsernameField)(testReq)).toBe("email");
|
|
29
|
-
}));
|
|
30
|
-
it("should use configuration value when query parameter is not provided", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
31
|
-
const testReq = { query: {} };
|
|
32
|
-
server_1.getArkosConfig.mockReturnValueOnce({
|
|
33
|
-
authentication: {
|
|
34
|
-
usernameField: "phoneNumber",
|
|
35
|
-
},
|
|
36
|
-
});
|
|
37
|
-
expect((0, auth_helpers_1.determineUsernameField)(testReq)).toBe("phoneNumber");
|
|
38
|
-
}));
|
|
39
|
-
it('should default to "username" when neither query nor config specify a field', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
40
|
-
expect((0, auth_helpers_1.determineUsernameField)({ query: {} })).toBe("username");
|
|
41
|
-
}));
|
|
42
|
-
});
|
|
43
|
-
//# sourceMappingURL=auth.helpers.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auth.helpers.test.js","sourceRoot":"","sources":["../../../../../../../src/modules/auth/utils/helpers/__tests__/auth.helpers.test.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,kDAAuD;AACvD,kDAAyD;AAEzD,IAAI,CAAC,IAAI,CAAC,uBAAuB,EAAE,GAAG,EAAE,CAAC,CAAC;IACxC,cAAc,EAAE,IAAI,CAAC,EAAE,EAAE;IACzB,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE;CACjB,CAAC,CAAC,CAAC;AAEJ,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IACrB,OAAO,kCACF,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAC3B,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,EAC3C,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;YACvB,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE;SAClB,CAAC,CAAC,EACH,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,EAChC,SAAS,EAAE,IAAI,CAAC,EAAE,EAAE,EACpB,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,EACjB,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,GAClB;CACF,CAAC,CAAC,CAAC;AAEJ,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,wDAAwD,EAAE,GAAS,EAAE;QACtE,MAAM,OAAO,GAAG;YACd,KAAK,EAAE,EAAE,aAAa,EAAE,OAAO,EAAE;SAClC,CAAC;QAEF,MAAM,CAAC,IAAA,qCAAsB,EAAC,OAAc,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/D,CAAC,CAAA,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,GAAS,EAAE;QACnF,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QAE7B,uBAAsB,CAAC,mBAAmB,CAAC;YAC1C,cAAc,EAAE;gBACd,aAAa,EAAE,aAAa;aAC7B;SACF,CAAC,CAAC;QAEH,MAAM,CAAC,IAAA,qCAAsB,EAAC,OAAc,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACrE,CAAC,CAAA,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,GAAS,EAAE;QAC1F,MAAM,CAAC,IAAA,qCAAsB,EAAC,EAAE,KAAK,EAAE,EAAE,EAAS,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACxE,CAAC,CAAA,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { getArkosConfig } from \"../../../../../server\";\nimport { determineUsernameField } from \"../auth.helpers\";\n\njest.mock(\"../../../../../server\", () => ({\n getArkosConfig: jest.fn(),\n close: jest.fn(),\n}));\n\njest.mock(\"fs\", () => ({\n default: {\n ...jest.requireActual(\"fs\"),\n readdirSync: jest.fn(() => [\"test.prisma\"]),\n statSync: jest.fn(() => ({\n isFile: jest.fn(),\n })),\n existsSync: jest.fn(() => false),\n mkdirSync: jest.fn(),\n unlink: jest.fn(),\n access: jest.fn(),\n },\n}));\n\ndescribe(\"determineUsernameField\", () => {\n it(\"should use query parameter usernameField when provided\", async () => {\n const testReq = {\n query: { usernameField: \"email\" },\n };\n\n expect(determineUsernameField(testReq as any)).toBe(\"email\");\n });\n\n it(\"should use configuration value when query parameter is not provided\", async () => {\n const testReq = { query: {} };\n\n (getArkosConfig as any).mockReturnValueOnce({\n authentication: {\n usernameField: \"phoneNumber\",\n },\n });\n\n expect(determineUsernameField(testReq as any)).toBe(\"phoneNumber\");\n });\n\n it('should default to \"username\" when neither query nor config specify a field', async () => {\n expect(determineUsernameField({ query: {} } as any)).toBe(\"username\");\n });\n});\n"]}
|