@alanszp/express 12.0.2 → 12.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/package.json +6 -9
  2. package/.gitignore +0 -3
  3. package/.npmignore +0 -3
  4. package/node_modules/@jest/expect-utils/LICENSE +0 -21
  5. package/node_modules/@jest/expect-utils/README.md +0 -5
  6. package/node_modules/@jest/expect-utils/build/index.d.ts +0 -93
  7. package/node_modules/@jest/expect-utils/build/index.js +0 -37
  8. package/node_modules/@jest/expect-utils/build/jasmineUtils.js +0 -282
  9. package/node_modules/@jest/expect-utils/build/types.js +0 -1
  10. package/node_modules/@jest/expect-utils/build/utils.js +0 -457
  11. package/node_modules/@jest/expect-utils/package.json +0 -33
  12. package/node_modules/@jest/types/LICENSE +0 -21
  13. package/node_modules/@jest/types/README.md +0 -30
  14. package/node_modules/@jest/types/build/Circus.js +0 -1
  15. package/node_modules/@jest/types/build/Config.js +0 -1
  16. package/node_modules/@jest/types/build/Global.js +0 -1
  17. package/node_modules/@jest/types/build/TestResult.js +0 -1
  18. package/node_modules/@jest/types/build/Transform.js +0 -1
  19. package/node_modules/@jest/types/build/index.d.ts +0 -1166
  20. package/node_modules/@jest/types/build/index.js +0 -1
  21. package/node_modules/@jest/types/package.json +0 -38
  22. package/node_modules/@types/jest/LICENSE +0 -21
  23. package/node_modules/@types/jest/README.md +0 -17
  24. package/node_modules/@types/jest/index.d.ts +0 -1608
  25. package/node_modules/@types/jest/package.json +0 -159
  26. package/node_modules/@types/node/LICENSE +0 -21
  27. package/node_modules/@types/node/README.md +0 -15
  28. package/node_modules/@types/node/assert/strict.d.ts +0 -8
  29. package/node_modules/@types/node/assert.d.ts +0 -996
  30. package/node_modules/@types/node/async_hooks.d.ts +0 -539
  31. package/node_modules/@types/node/buffer.d.ts +0 -2362
  32. package/node_modules/@types/node/child_process.d.ts +0 -1540
  33. package/node_modules/@types/node/cluster.d.ts +0 -432
  34. package/node_modules/@types/node/console.d.ts +0 -415
  35. package/node_modules/@types/node/constants.d.ts +0 -19
  36. package/node_modules/@types/node/crypto.d.ts +0 -4487
  37. package/node_modules/@types/node/dgram.d.ts +0 -596
  38. package/node_modules/@types/node/diagnostics_channel.d.ts +0 -545
  39. package/node_modules/@types/node/dns/promises.d.ts +0 -425
  40. package/node_modules/@types/node/dns.d.ts +0 -809
  41. package/node_modules/@types/node/dom-events.d.ts +0 -122
  42. package/node_modules/@types/node/domain.d.ts +0 -170
  43. package/node_modules/@types/node/events.d.ts +0 -879
  44. package/node_modules/@types/node/fs/promises.d.ts +0 -1239
  45. package/node_modules/@types/node/fs.d.ts +0 -4311
  46. package/node_modules/@types/node/globals.d.ts +0 -411
  47. package/node_modules/@types/node/globals.global.d.ts +0 -1
  48. package/node_modules/@types/node/http.d.ts +0 -1887
  49. package/node_modules/@types/node/http2.d.ts +0 -2382
  50. package/node_modules/@types/node/https.d.ts +0 -550
  51. package/node_modules/@types/node/index.d.ts +0 -88
  52. package/node_modules/@types/node/inspector.d.ts +0 -2747
  53. package/node_modules/@types/node/module.d.ts +0 -315
  54. package/node_modules/@types/node/net.d.ts +0 -949
  55. package/node_modules/@types/node/os.d.ts +0 -478
  56. package/node_modules/@types/node/package.json +0 -229
  57. package/node_modules/@types/node/path.d.ts +0 -191
  58. package/node_modules/@types/node/perf_hooks.d.ts +0 -645
  59. package/node_modules/@types/node/process.d.ts +0 -1561
  60. package/node_modules/@types/node/punycode.d.ts +0 -117
  61. package/node_modules/@types/node/querystring.d.ts +0 -141
  62. package/node_modules/@types/node/readline/promises.d.ts +0 -150
  63. package/node_modules/@types/node/readline.d.ts +0 -539
  64. package/node_modules/@types/node/repl.d.ts +0 -430
  65. package/node_modules/@types/node/stream/consumers.d.ts +0 -12
  66. package/node_modules/@types/node/stream/promises.d.ts +0 -83
  67. package/node_modules/@types/node/stream/web.d.ts +0 -366
  68. package/node_modules/@types/node/stream.d.ts +0 -1701
  69. package/node_modules/@types/node/string_decoder.d.ts +0 -67
  70. package/node_modules/@types/node/test.d.ts +0 -1465
  71. package/node_modules/@types/node/timers/promises.d.ts +0 -93
  72. package/node_modules/@types/node/timers.d.ts +0 -240
  73. package/node_modules/@types/node/tls.d.ts +0 -1210
  74. package/node_modules/@types/node/trace_events.d.ts +0 -182
  75. package/node_modules/@types/node/ts4.8/assert/strict.d.ts +0 -8
  76. package/node_modules/@types/node/ts4.8/assert.d.ts +0 -996
  77. package/node_modules/@types/node/ts4.8/async_hooks.d.ts +0 -539
  78. package/node_modules/@types/node/ts4.8/buffer.d.ts +0 -2362
  79. package/node_modules/@types/node/ts4.8/child_process.d.ts +0 -1540
  80. package/node_modules/@types/node/ts4.8/cluster.d.ts +0 -432
  81. package/node_modules/@types/node/ts4.8/console.d.ts +0 -415
  82. package/node_modules/@types/node/ts4.8/constants.d.ts +0 -19
  83. package/node_modules/@types/node/ts4.8/crypto.d.ts +0 -4487
  84. package/node_modules/@types/node/ts4.8/dgram.d.ts +0 -596
  85. package/node_modules/@types/node/ts4.8/diagnostics_channel.d.ts +0 -545
  86. package/node_modules/@types/node/ts4.8/dns/promises.d.ts +0 -425
  87. package/node_modules/@types/node/ts4.8/dns.d.ts +0 -809
  88. package/node_modules/@types/node/ts4.8/dom-events.d.ts +0 -122
  89. package/node_modules/@types/node/ts4.8/domain.d.ts +0 -170
  90. package/node_modules/@types/node/ts4.8/events.d.ts +0 -879
  91. package/node_modules/@types/node/ts4.8/fs/promises.d.ts +0 -1239
  92. package/node_modules/@types/node/ts4.8/fs.d.ts +0 -4311
  93. package/node_modules/@types/node/ts4.8/globals.d.ts +0 -411
  94. package/node_modules/@types/node/ts4.8/globals.global.d.ts +0 -1
  95. package/node_modules/@types/node/ts4.8/http.d.ts +0 -1887
  96. package/node_modules/@types/node/ts4.8/http2.d.ts +0 -2382
  97. package/node_modules/@types/node/ts4.8/https.d.ts +0 -550
  98. package/node_modules/@types/node/ts4.8/index.d.ts +0 -88
  99. package/node_modules/@types/node/ts4.8/inspector.d.ts +0 -2747
  100. package/node_modules/@types/node/ts4.8/module.d.ts +0 -315
  101. package/node_modules/@types/node/ts4.8/net.d.ts +0 -949
  102. package/node_modules/@types/node/ts4.8/os.d.ts +0 -478
  103. package/node_modules/@types/node/ts4.8/path.d.ts +0 -191
  104. package/node_modules/@types/node/ts4.8/perf_hooks.d.ts +0 -645
  105. package/node_modules/@types/node/ts4.8/process.d.ts +0 -1561
  106. package/node_modules/@types/node/ts4.8/punycode.d.ts +0 -117
  107. package/node_modules/@types/node/ts4.8/querystring.d.ts +0 -141
  108. package/node_modules/@types/node/ts4.8/readline/promises.d.ts +0 -150
  109. package/node_modules/@types/node/ts4.8/readline.d.ts +0 -539
  110. package/node_modules/@types/node/ts4.8/repl.d.ts +0 -430
  111. package/node_modules/@types/node/ts4.8/stream/consumers.d.ts +0 -12
  112. package/node_modules/@types/node/ts4.8/stream/promises.d.ts +0 -83
  113. package/node_modules/@types/node/ts4.8/stream/web.d.ts +0 -366
  114. package/node_modules/@types/node/ts4.8/stream.d.ts +0 -1701
  115. package/node_modules/@types/node/ts4.8/string_decoder.d.ts +0 -67
  116. package/node_modules/@types/node/ts4.8/test.d.ts +0 -1465
  117. package/node_modules/@types/node/ts4.8/timers/promises.d.ts +0 -93
  118. package/node_modules/@types/node/ts4.8/timers.d.ts +0 -240
  119. package/node_modules/@types/node/ts4.8/tls.d.ts +0 -1210
  120. package/node_modules/@types/node/ts4.8/trace_events.d.ts +0 -182
  121. package/node_modules/@types/node/ts4.8/tty.d.ts +0 -208
  122. package/node_modules/@types/node/ts4.8/url.d.ts +0 -927
  123. package/node_modules/@types/node/ts4.8/util.d.ts +0 -2183
  124. package/node_modules/@types/node/ts4.8/v8.d.ts +0 -764
  125. package/node_modules/@types/node/ts4.8/vm.d.ts +0 -903
  126. package/node_modules/@types/node/ts4.8/wasi.d.ts +0 -179
  127. package/node_modules/@types/node/ts4.8/worker_threads.d.ts +0 -691
  128. package/node_modules/@types/node/ts4.8/zlib.d.ts +0 -517
  129. package/node_modules/@types/node/tty.d.ts +0 -208
  130. package/node_modules/@types/node/url.d.ts +0 -927
  131. package/node_modules/@types/node/util.d.ts +0 -2183
  132. package/node_modules/@types/node/v8.d.ts +0 -764
  133. package/node_modules/@types/node/vm.d.ts +0 -903
  134. package/node_modules/@types/node/wasi.d.ts +0 -179
  135. package/node_modules/@types/node/worker_threads.d.ts +0 -691
  136. package/node_modules/@types/node/zlib.d.ts +0 -517
  137. package/src/helpers/getIp.ts +0 -5
  138. package/src/helpers/getRequestLogger.ts +0 -6
  139. package/src/helpers/now.ts +0 -3
  140. package/src/helpers/renderErrorJson.ts +0 -29
  141. package/src/index.ts +0 -10
  142. package/src/middlewares/accessLogger.ts +0 -34
  143. package/src/middlewares/auditLog.ts +0 -52
  144. package/src/middlewares/authedForOrg.ts +0 -50
  145. package/src/middlewares/authenticateUser.test.ts +0 -403
  146. package/src/middlewares/authenticateUser.ts +0 -171
  147. package/src/middlewares/createContext.test.ts +0 -85
  148. package/src/middlewares/createContext.ts +0 -49
  149. package/src/middlewares/hasRoles.ts +0 -24
  150. package/src/middlewares/jsonBodyParser.ts +0 -22
  151. package/src/middlewares/returnInternalServerError.ts +0 -15
  152. package/src/middlewares/returnNotFound.ts +0 -11
  153. package/src/test/mocks/authOptionsMocks.ts +0 -35
  154. package/src/test/mocks/expressMocks.ts +0 -33
  155. package/src/test/mocks/jwtUserMocks.ts +0 -19
  156. package/src/test/setup.test.ts +0 -15
  157. package/src/test/setup.ts +0 -3
  158. package/src/types/AuthMethod.ts +0 -27
  159. package/src/types/GenericRequest.ts +0 -3
  160. package/src/types/custom.d.ts +0 -20
@@ -1,50 +0,0 @@
1
- import { NextFunction, Response } from "express";
2
- import { getRequestLogger } from "../helpers/getRequestLogger";
3
- import { GenericRequest } from "../types/GenericRequest";
4
- import { render401Error, render404Error } from "../helpers/renderErrorJson";
5
-
6
- function response401(res: Response): void {
7
- res.status(401).json(render401Error(["jwt"]));
8
- }
9
-
10
- export function authForOrg(
11
- req: GenericRequest,
12
- res: Response,
13
- next: NextFunction
14
- ): void {
15
- const { orgReference } = req.params;
16
- const logger = getRequestLogger(req).child({ org: orgReference });
17
- try {
18
- if (!orgReference) {
19
- logger.error("middleware.authForOrg.error.noOrgReferenceInPath");
20
- return response401(res);
21
- }
22
-
23
- if (!req.context?.jwtUser?.organizationReference) {
24
- logger.info("middleware.authForOrg.error.noOrgInJwt", {
25
- jwtUser: req.context?.jwtUser || null,
26
- });
27
- return response401(res);
28
- }
29
-
30
- const jwtOrg = req.context.jwtUser.organizationReference;
31
- if (jwtOrg !== orgReference) {
32
- if (jwtOrg === "lara") {
33
- req.context.jwtUser.organizationReference = orgReference;
34
- return next();
35
- }
36
-
37
- logger.info("middleware.authForOrg.error.nonMatch", {
38
- jwtOrg,
39
- });
40
- return response401(res);
41
- }
42
-
43
- return next();
44
- } catch (error: unknown) {
45
- logger.info("middleware.authForOrg.error.noOrganization", {
46
- error,
47
- });
48
- res.status(404).json(render404Error());
49
- }
50
- }
@@ -1,403 +0,0 @@
1
- import { AuthMethods, createAuthContext } from "./authenticateUser";
2
- import { verifyJWT } from "@alanszp/jwt";
3
- import {
4
- mockNext,
5
- mockRequest,
6
- mockResponse,
7
- } from "../test/mocks/expressMocks";
8
- import { laraJwtUserMock, userJwtUserMock } from "../test/mocks/jwtUserMocks";
9
- import {
10
- apiKeyAuthOptions,
11
- bothMethodsAuthOptions,
12
- jwtAuthOptions,
13
- verifyOptions,
14
- } from "../test/mocks/authOptionsMocks";
15
-
16
- jest.mock("@alanszp/jwt");
17
-
18
- describe("AuthenticateUser", () => {
19
- describe("authentication with only JWT", () => {
20
- describe("when jwt verifies correctly", () => {
21
- it("should authenticate correctly and call next", async () => {
22
- (verifyJWT as jest.Mock).mockResolvedValueOnce(userJwtUserMock);
23
-
24
- const req = mockRequest("Bearer token");
25
- const res = mockResponse();
26
- const next = mockNext();
27
-
28
- await createAuthContext(jwtAuthOptions)([AuthMethods.JWT])(
29
- req,
30
- res,
31
- next
32
- );
33
-
34
- expect(verifyJWT).toBeCalledWith("publicKey", "token", verifyOptions);
35
- expect(res.status).toHaveBeenCalledTimes(0);
36
- expect(res.json).toHaveBeenCalledTimes(0);
37
- expect(req.context.jwtUser).toMatchObject(userJwtUserMock);
38
- expect(req.context.authenticated).toStrictEqual(["jwt"]);
39
- expect(next).toBeCalledWith();
40
- });
41
- });
42
-
43
- describe("when jwt verifies incorrectly", () => {
44
- it("should not authenticate, should not call next, and it should return 401", async () => {
45
- (verifyJWT as jest.Mock).mockResolvedValueOnce(undefined);
46
-
47
- const req = mockRequest("Bearer token");
48
- const res = mockResponse();
49
- const next = mockNext();
50
-
51
- await createAuthContext(jwtAuthOptions)([AuthMethods.JWT])(
52
- req,
53
- res,
54
- next
55
- );
56
-
57
- expect(verifyJWT).toBeCalledWith("publicKey", "token", verifyOptions);
58
- expect(res.status).toHaveBeenCalledWith(401);
59
- expect(res.json).toHaveBeenCalledTimes(1);
60
- expect(req.context.jwtUser).toBe(undefined);
61
- expect(req.context.authenticated).toEqual([]);
62
- expect(next).toHaveBeenCalledTimes(0);
63
- });
64
- });
65
-
66
- describe("when jwt doesn't exist", () => {
67
- it("should not verify JWT, should not authenticate, should not call next, and it should return 401", async () => {
68
- const req = mockRequest("aa");
69
- const res = mockResponse();
70
- const next = mockNext();
71
-
72
- await createAuthContext(jwtAuthOptions)([AuthMethods.JWT])(
73
- req,
74
- res,
75
- next
76
- );
77
-
78
- expect(verifyJWT).toHaveBeenCalledTimes(0);
79
- expect(res.status).toHaveBeenCalledWith(401);
80
- expect(res.json).toHaveBeenCalledTimes(1);
81
- expect(req.context.jwtUser).toBe(undefined);
82
- expect(req.context.authenticated).toEqual([]);
83
- expect(next).toHaveBeenCalledTimes(0);
84
- });
85
- });
86
- });
87
-
88
- describe("authentication with only API KEY", () => {
89
- describe("when api key verifies correctly", () => {
90
- it("should authenticate correctly and call next", async () => {
91
- const req = mockRequest("token");
92
- const res = mockResponse();
93
- const next = mockNext();
94
-
95
- await createAuthContext(apiKeyAuthOptions)([AuthMethods.API_KEY])(
96
- req,
97
- res,
98
- next
99
- );
100
-
101
- expect(verifyJWT).toHaveBeenCalledTimes(0);
102
- expect(res.status).toHaveBeenCalledTimes(0);
103
- expect(res.json).toHaveBeenCalledTimes(0);
104
- expect(req.context.jwtUser).toMatchObject(laraJwtUserMock);
105
- expect(req.context.authenticated).toStrictEqual(["api_key"]);
106
- expect(next).toBeCalledWith();
107
- });
108
- });
109
-
110
- describe("when api key verifies incorrectly", () => {
111
- it("should not authenticate, should not call next, and it should return 401", async () => {
112
- const req = mockRequest("invalidToken");
113
- const res = mockResponse();
114
- const next = mockNext();
115
-
116
- await createAuthContext(apiKeyAuthOptions)([AuthMethods.API_KEY])(
117
- req,
118
- res,
119
- next
120
- );
121
-
122
- expect(verifyJWT).toHaveBeenCalledTimes(0);
123
- expect(res.status).toHaveBeenCalledWith(401);
124
- expect(res.json).toHaveBeenCalledTimes(1);
125
- expect(req.context.jwtUser).toBe(undefined);
126
- expect(req.context.authenticated).toEqual([]);
127
- expect(next).toHaveBeenCalledTimes(0);
128
- });
129
- });
130
-
131
- describe("when api key doesn't exist", () => {
132
- it("should not verify api key, should not authenticate, should not call next, and it should return 401", async () => {
133
- const req = mockRequest(undefined as any);
134
- const res = mockResponse();
135
- const next = mockNext();
136
-
137
- await createAuthContext(apiKeyAuthOptions)([AuthMethods.API_KEY])(
138
- req,
139
- res,
140
- next
141
- );
142
-
143
- expect(verifyJWT).toHaveBeenCalledTimes(0);
144
- expect(res.status).toHaveBeenCalledWith(401);
145
- expect(res.json).toHaveBeenCalledTimes(1);
146
- expect(req.context.jwtUser).toBe(undefined);
147
- expect(req.context.authenticated).toEqual([]);
148
- expect(next).toHaveBeenCalledTimes(0);
149
- });
150
- });
151
- });
152
-
153
- describe("authentication with JWT and API KEY", () => {
154
- describe("using both methods", () => {
155
- describe("when api key verifies correctly", () => {
156
- it("should authenticate correctly and call next", async () => {
157
- const req = mockRequest("token");
158
- const res = mockResponse();
159
- const next = mockNext();
160
-
161
- await createAuthContext(bothMethodsAuthOptions)([
162
- AuthMethods.API_KEY,
163
- AuthMethods.JWT,
164
- ])(req, res, next);
165
-
166
- expect(verifyJWT).toHaveBeenCalledTimes(0);
167
- expect(res.status).toHaveBeenCalledTimes(0);
168
- expect(res.json).toHaveBeenCalledTimes(0);
169
- expect(req.context.jwtUser).toMatchObject(laraJwtUserMock);
170
- expect(req.context.authenticated).toStrictEqual(["api_key"]);
171
- expect(next).toHaveBeenCalledWith();
172
- });
173
- });
174
-
175
- describe("when api key verifies incorrectly", () => {
176
- it("should not authenticate, should not call next, and it should return 401", async () => {
177
- const req = mockRequest("invalidToken");
178
- const res = mockResponse();
179
- const next = mockNext();
180
-
181
- await createAuthContext(bothMethodsAuthOptions)([
182
- AuthMethods.API_KEY,
183
- AuthMethods.JWT,
184
- ])(req, res, next);
185
-
186
- expect(verifyJWT).toHaveBeenCalledTimes(0);
187
- expect(res.status).toHaveBeenCalledWith(401);
188
- expect(res.json).toHaveBeenCalledTimes(1);
189
- expect(req.context.jwtUser).toBe(undefined);
190
- expect(req.context.authenticated).toEqual([]);
191
- expect(next).toHaveBeenCalledTimes(0);
192
- });
193
- });
194
-
195
- describe("when jwt verifies correctly", () => {
196
- it("should authenticate correctly and call next", async () => {
197
- (verifyJWT as jest.Mock).mockResolvedValueOnce(userJwtUserMock);
198
-
199
- const req = mockRequest("Bearer token");
200
- const res = mockResponse();
201
- const next = mockNext();
202
-
203
- await createAuthContext(bothMethodsAuthOptions)([
204
- AuthMethods.API_KEY,
205
- AuthMethods.JWT,
206
- ])(req, res, next);
207
-
208
- expect(verifyJWT).toBeCalledWith("publicKey", "token", {
209
- issuer: "issuer",
210
- audience: "audience",
211
- });
212
- expect(res.status).toHaveBeenCalledTimes(0);
213
- expect(res.json).toHaveBeenCalledTimes(0);
214
-
215
- expect(req.context.jwtUser).toMatchObject(userJwtUserMock);
216
-
217
- expect(req.context.authenticated).toStrictEqual(["jwt"]);
218
-
219
- expect(next).toHaveBeenCalledWith();
220
- });
221
- });
222
-
223
- describe("when jwt verifies incorrectly", () => {
224
- it("should not authenticate, should not call next, and it should return 401", async () => {
225
- (verifyJWT as jest.Mock).mockResolvedValueOnce(undefined);
226
-
227
- const req = mockRequest("Bearer token");
228
- const res = mockResponse();
229
- const next = mockNext();
230
-
231
- await createAuthContext(bothMethodsAuthOptions)([
232
- AuthMethods.API_KEY,
233
- AuthMethods.JWT,
234
- ])(req, res, next);
235
-
236
- expect(verifyJWT).toBeCalledWith("publicKey", "token", {
237
- issuer: "issuer",
238
- audience: "audience",
239
- });
240
- expect(res.status).toHaveBeenCalledWith(401);
241
- expect(res.json).toHaveBeenCalledTimes(1);
242
- expect(req.context.jwtUser).toBe(undefined);
243
- expect(req.context.authenticated).toEqual([]);
244
- expect(next).toHaveBeenCalledTimes(0);
245
- });
246
- });
247
-
248
- describe("when jwt doesnt exist", () => {
249
- it("should not authenticate, should not call next, and it should return 401", async () => {
250
- const req = mockRequest(undefined as any);
251
- const res = mockResponse();
252
- const next = mockNext();
253
-
254
- await createAuthContext(bothMethodsAuthOptions)([
255
- AuthMethods.API_KEY,
256
- AuthMethods.JWT,
257
- ])(req, res, next);
258
-
259
- expect(verifyJWT).toHaveBeenCalledTimes(0);
260
- expect(res.status).toHaveBeenCalledWith(401);
261
- expect(res.json).toHaveBeenCalledTimes(1);
262
- expect(req.context.jwtUser).toBe(undefined);
263
- expect(req.context.authenticated).toEqual([]);
264
- expect(next).toHaveBeenCalledTimes(0);
265
- });
266
- });
267
- });
268
-
269
- describe("using jwt method", () => {
270
- describe("when jwt verifies correctly", () => {
271
- it("should authenticate correctly and call next", async () => {
272
- (verifyJWT as jest.Mock).mockResolvedValueOnce(userJwtUserMock);
273
-
274
- const req = mockRequest("Bearer token");
275
- const res = mockResponse();
276
- const next = mockNext();
277
-
278
- await createAuthContext(bothMethodsAuthOptions)([AuthMethods.JWT])(
279
- req,
280
- res,
281
- next
282
- );
283
-
284
- expect(verifyJWT).toBeCalledWith("publicKey", "token", {
285
- issuer: "issuer",
286
- audience: "audience",
287
- });
288
- expect(res.status).toHaveBeenCalledTimes(0);
289
- expect(res.json).toHaveBeenCalledTimes(0);
290
- expect(req.context.jwtUser).toMatchObject(userJwtUserMock);
291
- expect(req.context.authenticated).toStrictEqual(["jwt"]);
292
- expect(next).toHaveBeenCalledWith();
293
- });
294
- });
295
-
296
- describe("when jwt verifies incorrectly", () => {
297
- it("should not authenticate, should not call next, and it should return 401", async () => {
298
- (verifyJWT as jest.Mock).mockResolvedValueOnce(undefined);
299
-
300
- const req = mockRequest("Bearer invalidToken");
301
- const res = mockResponse();
302
- const next = mockNext();
303
-
304
- await createAuthContext(bothMethodsAuthOptions)([AuthMethods.JWT])(
305
- req,
306
- res,
307
- next
308
- );
309
-
310
- expect(verifyJWT).toBeCalledWith("publicKey", "invalidToken", {
311
- issuer: "issuer",
312
- audience: "audience",
313
- });
314
- expect(res.status).toHaveBeenCalledWith(401);
315
- expect(res.json).toHaveBeenCalledTimes(1);
316
- expect(req.context.jwtUser).toBe(undefined);
317
- expect(req.context.authenticated).toEqual([]);
318
- expect(next).toHaveBeenCalledTimes(0);
319
- });
320
- });
321
-
322
- describe("when api key verifies correctly", () => {
323
- it("should authenticate correctly and call next", async () => {
324
- const req = mockRequest("token");
325
- const res = mockResponse();
326
- const next = mockNext();
327
-
328
- await createAuthContext(bothMethodsAuthOptions)([
329
- AuthMethods.API_KEY,
330
- ])(req, res, next);
331
-
332
- expect(verifyJWT).toHaveBeenCalledTimes(0);
333
- expect(res.status).toHaveBeenCalledTimes(0);
334
- expect(res.json).toHaveBeenCalledTimes(0);
335
-
336
- expect(req.context.jwtUser).toMatchObject(laraJwtUserMock);
337
- expect(req.context.authenticated).toStrictEqual(["api_key"]);
338
- expect(next).toHaveBeenCalledWith();
339
- });
340
- });
341
-
342
- describe("when api key verifies incorrectly", () => {
343
- it("should not authenticate, should not call next, and it should return 401", async () => {
344
- const req = mockRequest("invalidToken");
345
- const res = mockResponse();
346
- const next = mockNext();
347
-
348
- await createAuthContext(bothMethodsAuthOptions)([
349
- AuthMethods.API_KEY,
350
- AuthMethods.JWT,
351
- ])(req, res, next);
352
-
353
- expect(verifyJWT).toHaveBeenCalledTimes(0);
354
- expect(res.status).toHaveBeenCalledWith(401);
355
- expect(res.json).toHaveBeenCalledTimes(1);
356
- expect(req.context.jwtUser).toBe(undefined);
357
- expect(req.context.authenticated).toEqual([]);
358
- expect(next).toHaveBeenCalledTimes(0);
359
- });
360
- });
361
-
362
- describe("when jwt doesnt exist", () => {
363
- it("should not authenticate, should not call next, and it should return 401", async () => {
364
- const req = mockRequest("aaa");
365
- const res = mockResponse();
366
- const next = mockNext();
367
-
368
- await createAuthContext(bothMethodsAuthOptions)([AuthMethods.JWT])(
369
- req,
370
- res,
371
- next
372
- );
373
-
374
- expect(verifyJWT).toHaveBeenCalledTimes(0);
375
- expect(res.status).toHaveBeenCalledWith(401);
376
- expect(res.json).toHaveBeenCalledTimes(1);
377
- expect(req.context.jwtUser).toBe(undefined);
378
- expect(req.context.authenticated).toEqual([]);
379
- expect(next).toHaveBeenCalledTimes(0);
380
- });
381
- });
382
-
383
- describe("when api key doesnt exist", () => {
384
- it("should not authenticate, should not call next, and it should return 401", async () => {
385
- const req = mockRequest(undefined as any);
386
- const res = mockResponse();
387
- const next = mockNext();
388
-
389
- await createAuthContext(bothMethodsAuthOptions)([
390
- AuthMethods.API_KEY,
391
- ])(req, res, next);
392
-
393
- expect(verifyJWT).toHaveBeenCalledTimes(0);
394
- expect(res.status).toHaveBeenCalledWith(401);
395
- expect(res.json).toHaveBeenCalledTimes(1);
396
- expect(req.context.jwtUser).toBe(undefined);
397
- expect(req.context.authenticated).toEqual([]);
398
- expect(next).toHaveBeenCalledTimes(0);
399
- });
400
- });
401
- });
402
- });
403
- });
@@ -1,171 +0,0 @@
1
- import { JWTUser, verifyJWT, VerifyOptions } from "@alanszp/jwt";
2
- import { NextFunction, Response } from "express";
3
- import { getRequestLogger } from "../helpers/getRequestLogger";
4
- import { GenericRequest } from "../types/GenericRequest";
5
- import { ILogger } from "@alanszp/logger";
6
- import { compact, isEmpty, omit } from "lodash";
7
- import { render401Error } from "../helpers/renderErrorJson";
8
-
9
- function parseAuthorizationHeader(
10
- authorization: string | undefined
11
- ): string | undefined {
12
- if (!authorization) return undefined;
13
- const [bearer, jwt, ...other] = authorization.split(" ");
14
-
15
- if (bearer !== "Bearer" || other.length > 0) return undefined;
16
-
17
- return jwt;
18
- }
19
-
20
- export enum AuthMethods {
21
- JWT = "JWT",
22
- API_KEY = "API_KEY",
23
- }
24
-
25
- export interface JWTVerifyOptions extends Partial<VerifyOptions> {
26
- publicKey: string;
27
- }
28
-
29
- export interface JWTOptions {
30
- jwtVerifyOptions: JWTVerifyOptions;
31
- types: [AuthMethods.JWT];
32
- }
33
-
34
- export interface ApiKeyOptions {
35
- validApiKeys: string[];
36
- types: [AuthMethods.API_KEY];
37
- }
38
-
39
- export interface BothMethodsOptions {
40
- jwtVerifyOptions: JWTVerifyOptions;
41
- validApiKeys: string[];
42
- types:
43
- | [AuthMethods.JWT, AuthMethods.API_KEY]
44
- | [AuthMethods.API_KEY, AuthMethods.JWT];
45
- }
46
-
47
- export type AuthOptions = JWTOptions | ApiKeyOptions | BothMethodsOptions;
48
-
49
- const middlewareGetterByAuthType: Record<
50
- AuthMethods,
51
- (
52
- tokenOrJwt: string | null | undefined,
53
- options: AuthOptions,
54
- logger: ILogger
55
- ) => Promise<JWTUser | null | undefined>
56
- > = {
57
- [AuthMethods.JWT]: async (
58
- jwt: string | null | undefined,
59
- options: Exclude<AuthOptions, ApiKeyOptions>,
60
- logger: ILogger
61
- ) => {
62
- try {
63
- if (!jwt) return undefined;
64
- const jwtUser = await verifyJWT(
65
- options.jwtVerifyOptions.publicKey,
66
- jwt,
67
- omit(options.jwtVerifyOptions, "publicKey")
68
- );
69
- logger.debug("auth.authWithJwt.authed", {
70
- user: jwtUser.id,
71
- org: jwtUser.organizationReference,
72
- });
73
- return jwtUser;
74
- } catch (error: unknown) {
75
- logger.info("auth.authWithJwt.invalidJwt", { jwt, error });
76
- return null;
77
- }
78
- },
79
- [AuthMethods.API_KEY]: async (
80
- token: string | null | undefined,
81
- options: Exclude<AuthOptions, JWTOptions>,
82
- logger: ILogger
83
- ): Promise<JWTUser | null | undefined> => {
84
- try {
85
- if (!token) return undefined;
86
- if (options.validApiKeys.includes(token)) {
87
- logger.debug("auth.authWithApiKey.authed", {
88
- user: "0",
89
- org: "lara",
90
- });
91
- return Promise.resolve(
92
- new JWTUser({
93
- id: "0",
94
- employeeReference: "0",
95
- organizationReference: "lara",
96
- roles: [],
97
- segmentReference: null,
98
- // This will be changed in the near future to grab all permissions.
99
- permissions: "MA==", // 0 in base64
100
- })
101
- );
102
- } else {
103
- return null;
104
- }
105
- } catch (error: unknown) {
106
- logger.info("auth.authWithApiKey.invalidApiKey", { token, error });
107
- return null;
108
- }
109
- },
110
- };
111
-
112
- export function createAuthContext<Options extends AuthOptions>(
113
- options: Options
114
- ) {
115
- return function getMiddlewareForMethods(
116
- authMethods: Options["types"][number][]
117
- ) {
118
- return async function authWithGivenMethods(
119
- req: GenericRequest,
120
- res: Response,
121
- next: NextFunction
122
- ): Promise<void> {
123
- const logger = getRequestLogger(req);
124
- const cookies = (req.cookies as Record<string, string | undefined>) || {};
125
- const jwt =
126
- cookies.jwt || parseAuthorizationHeader(req.headers.authorization);
127
-
128
- try {
129
- const authAttempts = await Promise.all(
130
- authMethods.map((method) =>
131
- middlewareGetterByAuthType[method](
132
- method === AuthMethods.JWT ? jwt : req.headers.authorization,
133
- options,
134
- logger
135
- )
136
- )
137
- );
138
-
139
- const successfulAuthAttempts = compact(authAttempts);
140
-
141
- if (isEmpty(successfulAuthAttempts)) {
142
- res
143
- .status(401)
144
- .json(
145
- render401Error([
146
- authAttempts.includes(null)
147
- ? `Token invalid for methods ${authMethods}`
148
- : `Token not set for methods ${authMethods}`,
149
- ])
150
- );
151
- return;
152
- }
153
-
154
- const jwtUser: JWTUser = successfulAuthAttempts[0];
155
- req.context.jwtUser = jwtUser;
156
- req.context.authenticated.push(
157
- jwtUser.employeeReference !== "0" ? "jwt" : "api_key"
158
- );
159
- next();
160
- } catch (error: unknown) {
161
- logger.info("auth.authenticateUser.error", {
162
- jwt,
163
- token: req.headers.authorization,
164
- methods: AuthMethods,
165
- error,
166
- });
167
- res.status(401).json(render401Error(authMethods));
168
- }
169
- };
170
- };
171
- }
@@ -1,85 +0,0 @@
1
- import { createContext } from "./createContext";
2
- import { SharedContext } from "@alanszp/shared-context";
3
- import { createMockLogger } from "@alanszp/logger";
4
- import { createAuditLogger } from "@alanszp/audit";
5
- import {
6
- mockNext,
7
- mockRequest,
8
- mockRequestWithBody,
9
- mockResponse,
10
- } from "../test/mocks/expressMocks";
11
- import { appIdentifier } from "@alanszp/core";
12
- jest.mock("@alanszp/shared-context");
13
-
14
- const logger = createMockLogger({});
15
- const sharedContext = new SharedContext();
16
- const lifecycleId = "123";
17
- const lifecycleChain = "node:test";
18
-
19
- describe("CreateContext", () => {
20
- describe("when has lifecycle headers", () => {
21
- beforeAll(() => {
22
- (SharedContext as jest.Mock).mockClear();
23
- });
24
- it("should get lifecycle identifiers from there", () => {
25
- const middleware = createContext(
26
- sharedContext,
27
- logger,
28
- createAuditLogger(logger)
29
- );
30
-
31
- middleware(
32
- mockRequest("authToken", {
33
- "x-lifecycle-chain": lifecycleChain,
34
- "x-lifecycle-id": lifecycleId,
35
- }),
36
- mockResponse(),
37
- mockNext()
38
- );
39
-
40
- expect(sharedContext.run).toHaveBeenCalledWith(
41
- expect.anything(),
42
- expect.objectContaining({
43
- lifecycleId,
44
- lifecycleChain: `${lifecycleChain},${appIdentifier()}`,
45
- })
46
- );
47
- });
48
- });
49
-
50
- describe("when doesn't have lifecycle headers", () => {
51
- beforeAll(() => {
52
- (SharedContext as jest.Mock).mockClear();
53
- });
54
- it("should get lifecycle identifiers from body.detail", () => {
55
- const middleware = createContext(
56
- sharedContext,
57
- logger,
58
- createAuditLogger(logger)
59
- );
60
-
61
- middleware(
62
- mockRequestWithBody(
63
- "authToken",
64
- {},
65
- {
66
- detail: {
67
- lch: lifecycleChain,
68
- lid: lifecycleId,
69
- },
70
- }
71
- ),
72
- mockResponse(),
73
- mockNext()
74
- );
75
-
76
- expect(sharedContext.run).toHaveBeenCalledWith(
77
- expect.anything(),
78
- expect.objectContaining({
79
- lifecycleId,
80
- lifecycleChain: `${lifecycleChain},${appIdentifier()}`,
81
- })
82
- );
83
- });
84
- });
85
- });