@alanszp/express 12.0.2 → 13.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/dist/helpers/getRequestBaseLog.d.ts +2 -0
  2. package/dist/helpers/getRequestBaseLog.js +9 -0
  3. package/dist/helpers/getRequestBaseLog.js.map +1 -0
  4. package/dist/helpers/renderErrorJson.d.ts +1 -0
  5. package/dist/helpers/renderErrorJson.js +10 -1
  6. package/dist/helpers/renderErrorJson.js.map +1 -1
  7. package/dist/index.d.ts +3 -1
  8. package/dist/index.js +3 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/middlewares/errorRequestHandlerMiddleware.d.ts +4 -0
  11. package/dist/middlewares/errorRequestHandlerMiddleware.js +68 -0
  12. package/dist/middlewares/errorRequestHandlerMiddleware.js.map +1 -0
  13. package/dist/middlewares/hasPermissions.d.ts +20 -0
  14. package/dist/middlewares/hasPermissions.js +90 -0
  15. package/dist/middlewares/hasPermissions.js.map +1 -0
  16. package/dist/middlewares/hasRoles.js +4 -4
  17. package/dist/middlewares/hasRoles.js.map +1 -1
  18. package/package.json +9 -10
  19. package/.gitignore +0 -3
  20. package/.npmignore +0 -3
  21. package/dist/middlewares/returnInternalServerError.d.ts +0 -4
  22. package/dist/middlewares/returnInternalServerError.js +0 -10
  23. package/dist/middlewares/returnInternalServerError.js.map +0 -1
  24. package/node_modules/@jest/expect-utils/LICENSE +0 -21
  25. package/node_modules/@jest/expect-utils/README.md +0 -5
  26. package/node_modules/@jest/expect-utils/build/index.d.ts +0 -93
  27. package/node_modules/@jest/expect-utils/build/index.js +0 -37
  28. package/node_modules/@jest/expect-utils/build/jasmineUtils.js +0 -282
  29. package/node_modules/@jest/expect-utils/build/types.js +0 -1
  30. package/node_modules/@jest/expect-utils/build/utils.js +0 -457
  31. package/node_modules/@jest/expect-utils/package.json +0 -33
  32. package/node_modules/@jest/types/LICENSE +0 -21
  33. package/node_modules/@jest/types/README.md +0 -30
  34. package/node_modules/@jest/types/build/Circus.js +0 -1
  35. package/node_modules/@jest/types/build/Config.js +0 -1
  36. package/node_modules/@jest/types/build/Global.js +0 -1
  37. package/node_modules/@jest/types/build/TestResult.js +0 -1
  38. package/node_modules/@jest/types/build/Transform.js +0 -1
  39. package/node_modules/@jest/types/build/index.d.ts +0 -1166
  40. package/node_modules/@jest/types/build/index.js +0 -1
  41. package/node_modules/@jest/types/package.json +0 -38
  42. package/node_modules/@types/jest/LICENSE +0 -21
  43. package/node_modules/@types/jest/README.md +0 -17
  44. package/node_modules/@types/jest/index.d.ts +0 -1608
  45. package/node_modules/@types/jest/package.json +0 -159
  46. package/node_modules/@types/node/LICENSE +0 -21
  47. package/node_modules/@types/node/README.md +0 -15
  48. package/node_modules/@types/node/assert/strict.d.ts +0 -8
  49. package/node_modules/@types/node/assert.d.ts +0 -996
  50. package/node_modules/@types/node/async_hooks.d.ts +0 -539
  51. package/node_modules/@types/node/buffer.d.ts +0 -2362
  52. package/node_modules/@types/node/child_process.d.ts +0 -1540
  53. package/node_modules/@types/node/cluster.d.ts +0 -432
  54. package/node_modules/@types/node/console.d.ts +0 -415
  55. package/node_modules/@types/node/constants.d.ts +0 -19
  56. package/node_modules/@types/node/crypto.d.ts +0 -4487
  57. package/node_modules/@types/node/dgram.d.ts +0 -596
  58. package/node_modules/@types/node/diagnostics_channel.d.ts +0 -545
  59. package/node_modules/@types/node/dns/promises.d.ts +0 -425
  60. package/node_modules/@types/node/dns.d.ts +0 -809
  61. package/node_modules/@types/node/dom-events.d.ts +0 -122
  62. package/node_modules/@types/node/domain.d.ts +0 -170
  63. package/node_modules/@types/node/events.d.ts +0 -879
  64. package/node_modules/@types/node/fs/promises.d.ts +0 -1239
  65. package/node_modules/@types/node/fs.d.ts +0 -4311
  66. package/node_modules/@types/node/globals.d.ts +0 -411
  67. package/node_modules/@types/node/globals.global.d.ts +0 -1
  68. package/node_modules/@types/node/http.d.ts +0 -1887
  69. package/node_modules/@types/node/http2.d.ts +0 -2382
  70. package/node_modules/@types/node/https.d.ts +0 -550
  71. package/node_modules/@types/node/index.d.ts +0 -88
  72. package/node_modules/@types/node/inspector.d.ts +0 -2747
  73. package/node_modules/@types/node/module.d.ts +0 -315
  74. package/node_modules/@types/node/net.d.ts +0 -949
  75. package/node_modules/@types/node/os.d.ts +0 -478
  76. package/node_modules/@types/node/package.json +0 -229
  77. package/node_modules/@types/node/path.d.ts +0 -191
  78. package/node_modules/@types/node/perf_hooks.d.ts +0 -645
  79. package/node_modules/@types/node/process.d.ts +0 -1561
  80. package/node_modules/@types/node/punycode.d.ts +0 -117
  81. package/node_modules/@types/node/querystring.d.ts +0 -141
  82. package/node_modules/@types/node/readline/promises.d.ts +0 -150
  83. package/node_modules/@types/node/readline.d.ts +0 -539
  84. package/node_modules/@types/node/repl.d.ts +0 -430
  85. package/node_modules/@types/node/stream/consumers.d.ts +0 -12
  86. package/node_modules/@types/node/stream/promises.d.ts +0 -83
  87. package/node_modules/@types/node/stream/web.d.ts +0 -366
  88. package/node_modules/@types/node/stream.d.ts +0 -1701
  89. package/node_modules/@types/node/string_decoder.d.ts +0 -67
  90. package/node_modules/@types/node/test.d.ts +0 -1465
  91. package/node_modules/@types/node/timers/promises.d.ts +0 -93
  92. package/node_modules/@types/node/timers.d.ts +0 -240
  93. package/node_modules/@types/node/tls.d.ts +0 -1210
  94. package/node_modules/@types/node/trace_events.d.ts +0 -182
  95. package/node_modules/@types/node/ts4.8/assert/strict.d.ts +0 -8
  96. package/node_modules/@types/node/ts4.8/assert.d.ts +0 -996
  97. package/node_modules/@types/node/ts4.8/async_hooks.d.ts +0 -539
  98. package/node_modules/@types/node/ts4.8/buffer.d.ts +0 -2362
  99. package/node_modules/@types/node/ts4.8/child_process.d.ts +0 -1540
  100. package/node_modules/@types/node/ts4.8/cluster.d.ts +0 -432
  101. package/node_modules/@types/node/ts4.8/console.d.ts +0 -415
  102. package/node_modules/@types/node/ts4.8/constants.d.ts +0 -19
  103. package/node_modules/@types/node/ts4.8/crypto.d.ts +0 -4487
  104. package/node_modules/@types/node/ts4.8/dgram.d.ts +0 -596
  105. package/node_modules/@types/node/ts4.8/diagnostics_channel.d.ts +0 -545
  106. package/node_modules/@types/node/ts4.8/dns/promises.d.ts +0 -425
  107. package/node_modules/@types/node/ts4.8/dns.d.ts +0 -809
  108. package/node_modules/@types/node/ts4.8/dom-events.d.ts +0 -122
  109. package/node_modules/@types/node/ts4.8/domain.d.ts +0 -170
  110. package/node_modules/@types/node/ts4.8/events.d.ts +0 -879
  111. package/node_modules/@types/node/ts4.8/fs/promises.d.ts +0 -1239
  112. package/node_modules/@types/node/ts4.8/fs.d.ts +0 -4311
  113. package/node_modules/@types/node/ts4.8/globals.d.ts +0 -411
  114. package/node_modules/@types/node/ts4.8/globals.global.d.ts +0 -1
  115. package/node_modules/@types/node/ts4.8/http.d.ts +0 -1887
  116. package/node_modules/@types/node/ts4.8/http2.d.ts +0 -2382
  117. package/node_modules/@types/node/ts4.8/https.d.ts +0 -550
  118. package/node_modules/@types/node/ts4.8/index.d.ts +0 -88
  119. package/node_modules/@types/node/ts4.8/inspector.d.ts +0 -2747
  120. package/node_modules/@types/node/ts4.8/module.d.ts +0 -315
  121. package/node_modules/@types/node/ts4.8/net.d.ts +0 -949
  122. package/node_modules/@types/node/ts4.8/os.d.ts +0 -478
  123. package/node_modules/@types/node/ts4.8/path.d.ts +0 -191
  124. package/node_modules/@types/node/ts4.8/perf_hooks.d.ts +0 -645
  125. package/node_modules/@types/node/ts4.8/process.d.ts +0 -1561
  126. package/node_modules/@types/node/ts4.8/punycode.d.ts +0 -117
  127. package/node_modules/@types/node/ts4.8/querystring.d.ts +0 -141
  128. package/node_modules/@types/node/ts4.8/readline/promises.d.ts +0 -150
  129. package/node_modules/@types/node/ts4.8/readline.d.ts +0 -539
  130. package/node_modules/@types/node/ts4.8/repl.d.ts +0 -430
  131. package/node_modules/@types/node/ts4.8/stream/consumers.d.ts +0 -12
  132. package/node_modules/@types/node/ts4.8/stream/promises.d.ts +0 -83
  133. package/node_modules/@types/node/ts4.8/stream/web.d.ts +0 -366
  134. package/node_modules/@types/node/ts4.8/stream.d.ts +0 -1701
  135. package/node_modules/@types/node/ts4.8/string_decoder.d.ts +0 -67
  136. package/node_modules/@types/node/ts4.8/test.d.ts +0 -1465
  137. package/node_modules/@types/node/ts4.8/timers/promises.d.ts +0 -93
  138. package/node_modules/@types/node/ts4.8/timers.d.ts +0 -240
  139. package/node_modules/@types/node/ts4.8/tls.d.ts +0 -1210
  140. package/node_modules/@types/node/ts4.8/trace_events.d.ts +0 -182
  141. package/node_modules/@types/node/ts4.8/tty.d.ts +0 -208
  142. package/node_modules/@types/node/ts4.8/url.d.ts +0 -927
  143. package/node_modules/@types/node/ts4.8/util.d.ts +0 -2183
  144. package/node_modules/@types/node/ts4.8/v8.d.ts +0 -764
  145. package/node_modules/@types/node/ts4.8/vm.d.ts +0 -903
  146. package/node_modules/@types/node/ts4.8/wasi.d.ts +0 -179
  147. package/node_modules/@types/node/ts4.8/worker_threads.d.ts +0 -691
  148. package/node_modules/@types/node/ts4.8/zlib.d.ts +0 -517
  149. package/node_modules/@types/node/tty.d.ts +0 -208
  150. package/node_modules/@types/node/url.d.ts +0 -927
  151. package/node_modules/@types/node/util.d.ts +0 -2183
  152. package/node_modules/@types/node/v8.d.ts +0 -764
  153. package/node_modules/@types/node/vm.d.ts +0 -903
  154. package/node_modules/@types/node/wasi.d.ts +0 -179
  155. package/node_modules/@types/node/worker_threads.d.ts +0 -691
  156. package/node_modules/@types/node/zlib.d.ts +0 -517
  157. package/src/helpers/getIp.ts +0 -5
  158. package/src/helpers/getRequestLogger.ts +0 -6
  159. package/src/helpers/now.ts +0 -3
  160. package/src/helpers/renderErrorJson.ts +0 -29
  161. package/src/index.ts +0 -10
  162. package/src/middlewares/accessLogger.ts +0 -34
  163. package/src/middlewares/auditLog.ts +0 -52
  164. package/src/middlewares/authedForOrg.ts +0 -50
  165. package/src/middlewares/authenticateUser.test.ts +0 -403
  166. package/src/middlewares/authenticateUser.ts +0 -171
  167. package/src/middlewares/createContext.test.ts +0 -85
  168. package/src/middlewares/createContext.ts +0 -49
  169. package/src/middlewares/hasRoles.ts +0 -24
  170. package/src/middlewares/jsonBodyParser.ts +0 -22
  171. package/src/middlewares/returnInternalServerError.ts +0 -15
  172. package/src/middlewares/returnNotFound.ts +0 -11
  173. package/src/test/mocks/authOptionsMocks.ts +0 -35
  174. package/src/test/mocks/expressMocks.ts +0 -33
  175. package/src/test/mocks/jwtUserMocks.ts +0 -19
  176. package/src/test/setup.test.ts +0 -15
  177. package/src/test/setup.ts +0 -3
  178. package/src/types/AuthMethod.ts +0 -27
  179. package/src/types/GenericRequest.ts +0 -3
  180. 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
- });