@soapjs/soap-auth 0.3.3 → 0.4.4

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 (98) hide show
  1. package/.claude/settings.local.json +20 -0
  2. package/build/errors.d.ts +1 -1
  3. package/build/errors.js +2 -2
  4. package/build/index.d.ts +1 -0
  5. package/build/index.js +1 -0
  6. package/build/services/auth-throttle.service.d.ts +2 -2
  7. package/build/services/auth-throttle.service.js +2 -2
  8. package/build/services/index.d.ts +1 -0
  9. package/build/services/index.js +1 -0
  10. package/build/services/password.service.d.ts +7 -5
  11. package/build/services/password.service.js +76 -18
  12. package/build/services/totp.service.d.ts +16 -0
  13. package/build/services/totp.service.js +96 -0
  14. package/build/session/session-handler.d.ts +1 -0
  15. package/build/session/session-handler.js +39 -6
  16. package/build/soap-auth.d.ts +13 -6
  17. package/build/soap-auth.js +132 -5
  18. package/build/strategies/api-key/api-key.strategy.d.ts +4 -4
  19. package/build/strategies/api-key/api-key.strategy.js +3 -2
  20. package/build/strategies/base-auth.strategy.d.ts +5 -4
  21. package/build/strategies/basic/basic.strategy.d.ts +2 -1
  22. package/build/strategies/basic/basic.strategy.js +1 -0
  23. package/build/strategies/credential-auth.strategy.d.ts +7 -7
  24. package/build/strategies/credential-auth.strategy.js +9 -14
  25. package/build/strategies/index.d.ts +1 -0
  26. package/build/strategies/index.js +1 -0
  27. package/build/strategies/jwt/jwt.strategy.d.ts +3 -1
  28. package/build/strategies/jwt/jwt.strategy.js +41 -9
  29. package/build/strategies/jwt/jwt.tools.js +16 -14
  30. package/build/strategies/local/local.strategy.d.ts +6 -3
  31. package/build/strategies/local/local.strategy.js +83 -2
  32. package/build/strategies/oauth2/hybrid.oauth2.strategy.d.ts +3 -3
  33. package/build/strategies/oauth2/hybrid.oauth2.strategy.js +1 -6
  34. package/build/strategies/oauth2/oauth2.errors.d.ts +1 -0
  35. package/build/strategies/oauth2/oauth2.errors.js +4 -0
  36. package/build/strategies/oauth2/oauth2.strategy.d.ts +6 -4
  37. package/build/strategies/oauth2/oauth2.strategy.js +114 -46
  38. package/build/strategies/oauth2/oauth2.tools.js +2 -2
  39. package/build/strategies/oauth2/oauth2.types.d.ts +2 -2
  40. package/build/strategies/oauth2/providers/facebook.strategy.d.ts +11 -0
  41. package/build/strategies/oauth2/providers/facebook.strategy.js +58 -0
  42. package/build/strategies/oauth2/providers/github.strategy.d.ts +11 -0
  43. package/build/strategies/oauth2/providers/github.strategy.js +56 -0
  44. package/build/strategies/oauth2/providers/google.strategy.d.ts +11 -0
  45. package/build/strategies/oauth2/providers/google.strategy.js +52 -0
  46. package/build/strategies/oauth2/providers/http-oauth2.strategy.d.ts +16 -0
  47. package/build/strategies/oauth2/providers/http-oauth2.strategy.js +49 -0
  48. package/build/strategies/oauth2/providers/index.d.ts +5 -0
  49. package/build/strategies/oauth2/providers/index.js +21 -0
  50. package/build/strategies/oauth2/providers/provider.types.d.ts +7 -0
  51. package/build/strategies/oauth2/providers/provider.types.js +2 -0
  52. package/build/strategies/token-auth.strategy.d.ts +4 -4
  53. package/build/strategies/token-auth.strategy.js +2 -3
  54. package/build/tools/tools.js +1 -2
  55. package/build/types.d.ts +31 -32
  56. package/build/utils/validation.d.ts +23 -0
  57. package/build/utils/validation.js +139 -0
  58. package/package.json +8 -7
  59. package/build/__tests__/soap-auth.test.d.ts +0 -1
  60. package/build/__tests__/soap-auth.test.js +0 -42
  61. package/build/services/__tests__/account-lock.service.test.d.ts +0 -1
  62. package/build/services/__tests__/account-lock.service.test.js +0 -55
  63. package/build/services/__tests__/auth-throttle.service.test.d.ts +0 -1
  64. package/build/services/__tests__/auth-throttle.service.test.js +0 -48
  65. package/build/services/__tests__/jwks.service.test.d.ts +0 -1
  66. package/build/services/__tests__/jwks.service.test.js +0 -39
  67. package/build/services/__tests__/mfa.service.test.d.ts +0 -1
  68. package/build/services/__tests__/mfa.service.test.js +0 -66
  69. package/build/services/__tests__/password.service.test.d.ts +0 -1
  70. package/build/services/__tests__/password.service.test.js +0 -66
  71. package/build/services/__tests__/pkce.service.test.d.ts +0 -1
  72. package/build/services/__tests__/pkce.service.test.js +0 -77
  73. package/build/services/__tests__/rate-limit.service.test.d.ts +0 -1
  74. package/build/services/__tests__/rate-limit.service.test.js +0 -37
  75. package/build/services/__tests__/role.service.test.d.ts +0 -1
  76. package/build/services/__tests__/role.service.test.js +0 -31
  77. package/build/session/__tests__/file.session-store.test.d.ts +0 -1
  78. package/build/session/__tests__/file.session-store.test.js +0 -117
  79. package/build/session/__tests__/memory.session-store.test.d.ts +0 -1
  80. package/build/session/__tests__/memory.session-store.test.js +0 -77
  81. package/build/session/__tests__/session-handler.test.d.ts +0 -1
  82. package/build/session/__tests__/session-handler.test.js +0 -337
  83. package/build/strategies/__tests__/base-auth.strategy.test.d.ts +0 -14
  84. package/build/strategies/__tests__/base-auth.strategy.test.js +0 -137
  85. package/build/strategies/__tests__/credential-auth.strategy.test.d.ts +0 -14
  86. package/build/strategies/__tests__/credential-auth.strategy.test.js +0 -265
  87. package/build/strategies/__tests__/token-auth.strategy.test.d.ts +0 -28
  88. package/build/strategies/__tests__/token-auth.strategy.test.js +0 -298
  89. package/build/strategies/api-key/__tests__/api-key.strategy.test.d.ts +0 -1
  90. package/build/strategies/api-key/__tests__/api-key.strategy.test.js +0 -103
  91. package/build/strategies/basic/__tests__/basic.strategy.test.d.ts +0 -1
  92. package/build/strategies/basic/__tests__/basic.strategy.test.js +0 -104
  93. package/build/strategies/jwt/__tests__/jwt.strategy.test.d.ts +0 -1
  94. package/build/strategies/jwt/__tests__/jwt.strategy.test.js +0 -156
  95. package/build/strategies/jwt/__tests__/jwt.tools.test.d.ts +0 -1
  96. package/build/strategies/jwt/__tests__/jwt.tools.test.js +0 -98
  97. package/build/strategies/local/__tests__/local.strategy.test.d.ts +0 -1
  98. package/build/strategies/local/__tests__/local.strategy.test.js +0 -115
@@ -1,103 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const api_key_strategy_1 = require("../api-key.strategy");
4
- const errors_1 = require("../../../errors");
5
- const api_key_errors_1 = require("../api-key.errors");
6
- describe("ApiKeyStrategy", () => {
7
- let strategy;
8
- let mockConfig;
9
- let mockLogger;
10
- beforeEach(() => {
11
- mockLogger = {
12
- error: jest.fn(),
13
- warn: jest.fn(),
14
- info: jest.fn(),
15
- };
16
- mockConfig = {
17
- extractApiKey: jest.fn(),
18
- retrieveUserByApiKey: jest.fn(),
19
- lock: {
20
- isAccountLocked: jest.fn(),
21
- logFailedAttempt: jest.fn(),
22
- },
23
- isApiKeyExpired: jest.fn(),
24
- rateLimit: {
25
- checkRateLimit: jest.fn(),
26
- incrementRequestCount: jest.fn(),
27
- },
28
- role: { authorizeByRoles: jest.fn(), roles: [] },
29
- revokeApiKey: jest.fn(),
30
- trackApiKeyUsage: jest.fn(),
31
- keyType: "long-term",
32
- };
33
- strategy = new api_key_strategy_1.ApiKeyStrategy(mockConfig, mockLogger);
34
- });
35
- it("should authenticate a user with a valid API key", async () => {
36
- mockConfig.extractApiKey.mockReturnValue("valid-api-key");
37
- mockConfig.retrieveUserByApiKey.mockResolvedValue({
38
- id: 1,
39
- name: "John Doe",
40
- });
41
- const result = await strategy.authenticate({});
42
- expect(result).toEqual({ user: { id: 1, name: "John Doe" } });
43
- expect(mockConfig.trackApiKeyUsage).toHaveBeenCalledWith("valid-api-key");
44
- expect(mockConfig.rateLimit.incrementRequestCount).toHaveBeenCalledWith("valid-api-key");
45
- });
46
- it("should throw MissingApiKeyError if no API key is provided", async () => {
47
- mockConfig.extractApiKey.mockReturnValue(null);
48
- await expect(strategy.authenticate({})).rejects.toThrow(api_key_errors_1.MissingApiKeyError);
49
- expect(mockConfig.lock.logFailedAttempt).toHaveBeenCalled();
50
- });
51
- it("should throw InvalidApiKeyError if the API key is invalid", async () => {
52
- mockConfig.extractApiKey.mockReturnValue("invalid-api-key");
53
- mockConfig.retrieveUserByApiKey.mockResolvedValue(null);
54
- await expect(strategy.authenticate({})).rejects.toThrow(api_key_errors_1.InvalidApiKeyError);
55
- expect(mockConfig.lock.logFailedAttempt).toHaveBeenCalledWith("invalid-api-key", {});
56
- });
57
- it("should throw AccountLockedError if account is locked", async () => {
58
- mockConfig.extractApiKey.mockReturnValue("valid-api-key");
59
- mockConfig.lock.isAccountLocked.mockResolvedValue(true);
60
- await expect(strategy.authenticate({})).rejects.toThrow(errors_1.AccountLockedError);
61
- });
62
- it("should throw ExpiredApiKeyError if API key is expired", async () => {
63
- mockConfig.extractApiKey.mockReturnValue("valid-api-key");
64
- mockConfig.isApiKeyExpired.mockResolvedValue(true);
65
- await expect(strategy.authenticate({})).rejects.toThrow(api_key_errors_1.ExpiredApiKeyError);
66
- });
67
- it("should throw RateLimitExceededError if API key exceeds rate limit", async () => {
68
- mockConfig.extractApiKey.mockReturnValue("valid-api-key");
69
- mockConfig.rateLimit.checkRateLimit.mockResolvedValue(true);
70
- await expect(strategy.authenticate({})).rejects.toThrow(errors_1.RateLimitExceededError);
71
- });
72
- it("should throw UnauthorizedRoleError if user has no access", async () => {
73
- mockConfig.extractApiKey.mockReturnValue("valid-api-key");
74
- mockConfig.retrieveUserByApiKey.mockResolvedValue({ id: 1, role: "guest" });
75
- mockConfig.role.authorizeByRoles.mockResolvedValue(false);
76
- strategy.role.roles = ["admin", "user"];
77
- await expect(strategy.authenticate({})).rejects.toThrow(errors_1.UnauthorizedRoleError);
78
- });
79
- it("should revoke one-time API keys after authentication", async () => {
80
- mockConfig.keyType = "one-time";
81
- mockConfig.extractApiKey.mockReturnValue("one-time-key");
82
- mockConfig.retrieveUserByApiKey.mockResolvedValue({ id: 1 });
83
- await strategy.authenticate({});
84
- expect(mockConfig.revokeApiKey).toHaveBeenCalledWith("one-time-key");
85
- });
86
- it("should retry retrieving user on failure", async () => {
87
- mockConfig.retrieveUserMaxRetries = 1;
88
- mockConfig.extractApiKey.mockReturnValue("valid-api-key");
89
- mockConfig.retrieveUserByApiKey
90
- .mockRejectedValueOnce(new Error("Temporary failure"))
91
- .mockResolvedValueOnce({ id: 1, name: "John Doe" });
92
- const result = await strategy.authenticate({});
93
- expect(result).toEqual({ user: { id: 1, name: "John Doe" } });
94
- expect(mockConfig.retrieveUserByApiKey).toHaveBeenCalledTimes(2);
95
- });
96
- it("should log failed authentication attempts", async () => {
97
- mockConfig.extractApiKey.mockReturnValue("invalid-api-key");
98
- mockConfig.retrieveUserByApiKey.mockResolvedValue(null);
99
- const ctx = {};
100
- await expect(strategy.authenticate(ctx)).rejects.toThrow(api_key_errors_1.InvalidApiKeyError);
101
- expect(mockConfig.lock.logFailedAttempt).toHaveBeenCalledWith("invalid-api-key", ctx);
102
- });
103
- });
@@ -1,104 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const basic_strategy_1 = require("../basic.strategy");
4
- const errors_1 = require("../../../errors");
5
- describe("BasicStrategy", () => {
6
- let strategy;
7
- let mockConfig;
8
- let mockSession;
9
- let mockJwt;
10
- beforeEach(() => {
11
- mockConfig = {
12
- credentials: {
13
- extractCredentials: jest.fn(),
14
- verifyCredentials: jest.fn(),
15
- },
16
- user: {
17
- fetchUser: jest.fn(),
18
- },
19
- routes: {
20
- login: {},
21
- logout: {},
22
- },
23
- };
24
- mockSession = {
25
- issueSession: jest.fn(),
26
- };
27
- mockJwt = {
28
- issueTokens: jest.fn(),
29
- };
30
- strategy = new basic_strategy_1.BasicStrategy(mockConfig, mockSession, mockJwt);
31
- });
32
- describe("extractCredentials", () => {
33
- it("should extract credentials from Authorization header", () => {
34
- mockConfig.credentials.extractCredentials = null;
35
- const username = "testuser";
36
- const password = "securepassword";
37
- const encoded = Buffer.from(`${username}:${password}`).toString("base64");
38
- const context = { headers: { authorization: `Basic ${encoded}` } };
39
- const credentials = strategy.extractCredentials(context);
40
- expect(credentials).toEqual({ identifier: username, password });
41
- });
42
- it("should throw MissingCredentialsError if Authorization header is missing", () => {
43
- const context = { headers: {} };
44
- expect(() => strategy.extractCredentials(context)).toThrow(errors_1.MissingCredentialsError);
45
- });
46
- it("should throw InvalidCredentialsError if Authorization header is malformed", () => {
47
- const context = { headers: { authorization: "Bearer token" } };
48
- mockConfig.credentials.extractCredentials = null;
49
- expect(() => strategy.extractCredentials(context)).toThrow(errors_1.InvalidCredentialsError);
50
- });
51
- it("should throw InvalidCredentialsError if Authorization header is not base64-encoded properly", () => {
52
- const context = { headers: { authorization: "Basic not_base64_data" } };
53
- mockConfig.credentials.extractCredentials = null;
54
- expect(() => strategy.extractCredentials(context)).toThrow(errors_1.InvalidCredentialsError);
55
- });
56
- it("should throw InvalidCredentialsError if decoded credentials are invalid", () => {
57
- const encoded = Buffer.from(`username`).toString("base64");
58
- const context = { headers: { authorization: `Basic ${encoded}` } };
59
- mockConfig.credentials.extractCredentials = null;
60
- expect(() => strategy.extractCredentials(context)).toThrow(errors_1.InvalidCredentialsError);
61
- });
62
- });
63
- describe("verifyCredentials", () => {
64
- it("should verify valid credentials", async () => {
65
- mockConfig.credentials.verifyCredentials.mockResolvedValue(true);
66
- const result = await strategy.verifyCredentials("testuser", "password");
67
- expect(result).toBe(true);
68
- expect(mockConfig.credentials.verifyCredentials).toHaveBeenCalledWith("testuser", "password");
69
- });
70
- it("should return false if credentials are invalid", async () => {
71
- mockConfig.credentials.verifyCredentials.mockResolvedValue(false);
72
- const result = await strategy.verifyCredentials("testuser", "wrongpass");
73
- expect(result).toBe(false);
74
- expect(mockConfig.credentials.verifyCredentials).toHaveBeenCalledWith("testuser", "wrongpass");
75
- });
76
- });
77
- describe("fetchUser", () => {
78
- it("should retrieve user data when credentials are valid", async () => {
79
- const mockUser = { id: 1, username: "testuser" };
80
- mockConfig.user.fetchUser.mockResolvedValue(mockUser);
81
- const user = await strategy.fetchUser({
82
- identifier: "testuser",
83
- password: "securepassword",
84
- });
85
- expect(user).toEqual(mockUser);
86
- expect(mockConfig.user.fetchUser).toHaveBeenCalledWith({
87
- identifier: "testuser",
88
- password: "securepassword",
89
- });
90
- });
91
- it("should return null if user is not found", async () => {
92
- mockConfig.user.fetchUser.mockResolvedValue(null);
93
- const user = await strategy.fetchUser({
94
- identifier: "unknownuser",
95
- password: "securepassword",
96
- });
97
- expect(user).toBeNull();
98
- expect(mockConfig.user.fetchUser).toHaveBeenCalledWith({
99
- identifier: "unknownuser",
100
- password: "securepassword",
101
- });
102
- });
103
- });
104
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,156 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const jsonwebtoken_1 = require("jsonwebtoken");
4
- const jwt_strategy_1 = require("../jwt.strategy");
5
- const errors_1 = require("../../../errors");
6
- describe("JWTStrategy", () => {
7
- let strategy;
8
- let mockLogger;
9
- let mockConfig;
10
- let mockUser;
11
- let mockContext;
12
- beforeEach(() => {
13
- mockLogger = { error: jest.fn(), warn: jest.fn(), info: jest.fn() };
14
- mockUser = { id: "123", email: "test@example.com" };
15
- mockContext = {
16
- req: {
17
- headers: { authorization: "Bearer mock-access-token" },
18
- cookies: { refreshToken: "mock-refresh-token" },
19
- },
20
- res: { setHeader: jest.fn(), cookie: jest.fn(), clearCookie: jest.fn() },
21
- };
22
- mockConfig = {
23
- accessToken: {
24
- issuer: { secretKey: "access-secret", options: { expiresIn: "1h" } },
25
- verifier: { options: {} },
26
- persistence: { store: jest.fn() },
27
- extract: jest.fn(),
28
- embed: jest.fn(),
29
- },
30
- refreshToken: {
31
- issuer: { secretKey: "refresh-secret", options: { expiresIn: "7d" } },
32
- verifier: { options: {} },
33
- persistence: { store: jest.fn(), remove: jest.fn() },
34
- extract: jest.fn(),
35
- embed: jest.fn(),
36
- },
37
- user: { fetchUser: jest.fn().mockResolvedValue(mockUser) },
38
- routes: {},
39
- };
40
- strategy = new jwt_strategy_1.JwtStrategy(mockConfig, mockLogger);
41
- });
42
- it("should authenticate user with valid access token", async () => {
43
- const mockAccessToken = "mock-access-token";
44
- jest
45
- .spyOn(mockConfig.accessToken, "extract")
46
- .mockReturnValue(mockAccessToken);
47
- jest.spyOn(strategy, "verifyAccessToken").mockResolvedValue(mockUser);
48
- const result = await strategy.authenticate(mockContext);
49
- expect(result.user).toEqual(mockUser);
50
- expect(result.tokens.accessToken).toEqual("mock-access-token");
51
- });
52
- it("should refresh tokens when access token is invalid", async () => {
53
- const mockAccessToken = "mock-access-token";
54
- const mockRefreshToken = "mock-refresh-token";
55
- jest
56
- .spyOn(mockConfig.accessToken, "extract")
57
- .mockReturnValue(mockAccessToken);
58
- jest
59
- .spyOn(mockConfig.refreshToken, "extract")
60
- .mockReturnValue(mockRefreshToken);
61
- jest
62
- .spyOn(strategy, "verifyAccessToken")
63
- .mockRejectedValue(new jsonwebtoken_1.TokenExpiredError("Access", new Date()));
64
- jest.spyOn(strategy, "verifyRefreshToken").mockResolvedValue(mockUser);
65
- jest
66
- .spyOn(strategy, "generateAccessToken")
67
- .mockResolvedValue("new-access-token");
68
- jest
69
- .spyOn(strategy, "generateRefreshToken")
70
- .mockResolvedValue("new-refresh-token");
71
- jest.spyOn(strategy, "storeAccessToken").mockResolvedValue(null);
72
- jest.spyOn(strategy, "storeRefreshToken").mockResolvedValue(null);
73
- const result = await strategy.authenticate(mockContext);
74
- expect(result.user).toEqual(mockUser);
75
- expect(result.tokens.accessToken).toEqual("new-access-token");
76
- expect(result.tokens.refreshToken).toEqual("new-refresh-token");
77
- });
78
- it("should throw MissingTokenError when no tokens are provided", async () => {
79
- jest.spyOn(mockConfig.accessToken, "extract").mockReturnValue(undefined);
80
- jest.spyOn(mockConfig.refreshToken, "extract").mockReturnValue(undefined);
81
- await expect(strategy.authenticate(mockContext)).rejects.toThrow(errors_1.MissingTokenError);
82
- });
83
- it("should throw InvalidTokenError if user does not exist", async () => {
84
- const mockAccessToken = "mock-access-token";
85
- const mockRefreshToken = null;
86
- jest
87
- .spyOn(mockConfig.accessToken, "extract")
88
- .mockReturnValue(mockAccessToken);
89
- jest
90
- .spyOn(mockConfig.refreshToken, "extract")
91
- .mockReturnValue(mockRefreshToken);
92
- jest.spyOn(strategy, "verifyAccessToken").mockResolvedValue(mockUser);
93
- mockConfig.user.fetchUser = jest.fn().mockResolvedValue(null);
94
- await expect(strategy.authenticate(mockContext)).rejects.toThrow(errors_1.InvalidTokenError);
95
- });
96
- it("should throw InvalidTokenError when refresh token is invalid", async () => {
97
- const mockAccessToken = "mock-access-token";
98
- const mockRefreshToken = "mock-refresh-token";
99
- jest
100
- .spyOn(mockConfig.accessToken, "extract")
101
- .mockReturnValue(mockAccessToken);
102
- jest
103
- .spyOn(mockConfig.refreshToken, "extract")
104
- .mockReturnValue(mockRefreshToken);
105
- jest
106
- .spyOn(strategy, "verifyAccessToken")
107
- .mockRejectedValue(new errors_1.InvalidTokenError("Access"));
108
- jest
109
- .spyOn(strategy, "verifyRefreshToken")
110
- .mockRejectedValue(new errors_1.InvalidTokenError("Refresh"));
111
- await expect(strategy.authenticate(mockContext)).rejects.toThrow(errors_1.InvalidTokenError);
112
- });
113
- it("should generate and store access and refresh tokens", async () => {
114
- jest
115
- .spyOn(strategy, "generateAccessToken")
116
- .mockResolvedValue("new-access-token");
117
- jest
118
- .spyOn(strategy, "generateRefreshToken")
119
- .mockResolvedValue("new-refresh-token");
120
- jest.spyOn(strategy, "storeAccessToken").mockResolvedValue(null);
121
- jest.spyOn(strategy, "storeRefreshToken").mockResolvedValue(null);
122
- const tokens = await strategy.issueTokens(mockUser, mockContext);
123
- expect(tokens).toHaveProperty("accessToken", "new-access-token");
124
- expect(tokens).toHaveProperty("refreshToken", "new-refresh-token");
125
- expect(strategy.storeAccessToken).toHaveBeenCalledWith("new-access-token");
126
- expect(strategy.storeRefreshToken).toHaveBeenCalledWith("new-refresh-token");
127
- });
128
- it("should invalidate refresh token", async () => {
129
- jest
130
- .spyOn(strategy, "extractRefreshToken")
131
- .mockResolvedValue("mock-refresh-token");
132
- jest.spyOn(strategy, "invalidateRefreshToken").mockResolvedValue(null);
133
- await strategy.invalidateRefreshToken(mockContext);
134
- expect(strategy.invalidateRefreshToken).toHaveBeenCalledWith(mockContext);
135
- });
136
- it("should extract access token from context", async () => {
137
- const mockAccessToken = "mock-access-token";
138
- jest
139
- .spyOn(mockConfig.accessToken, "extract")
140
- .mockReturnValue(mockAccessToken);
141
- const token = await strategy.extractAccessToken(mockContext);
142
- expect(token).toBe("mock-access-token");
143
- });
144
- it("should extract refresh token from context", async () => {
145
- const mockRefreshToken = "mock-refresh-token";
146
- jest
147
- .spyOn(mockConfig.refreshToken, "extract")
148
- .mockReturnValueOnce(mockRefreshToken);
149
- const token = await strategy.extractRefreshToken(mockContext);
150
- expect(token).toBe("mock-refresh-token");
151
- });
152
- it("should throw UndefinedTokenSecretError if access secret key is missing", async () => {
153
- mockConfig.accessToken.issuer.secretKey = undefined;
154
- expect(() => new jwt_strategy_1.JwtStrategy(mockConfig, mockLogger)).toThrow(errors_1.UndefinedTokenSecretError);
155
- });
156
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,98 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const globals_1 = require("@jest/globals");
4
- const jwt_tools_1 = require("../jwt.tools");
5
- const errors_1 = require("../../../errors");
6
- (0, globals_1.describe)("JwtTools", () => {
7
- const secretKey = "test-secret";
8
- const payload = { id: "user123", email: "test@example.com" };
9
- const config = {
10
- accessToken: {
11
- issuer: { secretKey, options: { expiresIn: "1h" } },
12
- verifier: { options: {} },
13
- },
14
- refreshToken: {
15
- issuer: { secretKey, options: { expiresIn: "7d" } },
16
- verifier: { options: {} },
17
- },
18
- routes: {},
19
- };
20
- (0, globals_1.it)("should generate an access token", () => {
21
- const token = jwt_tools_1.JwtTools.generateAccessToken(payload, config.accessToken);
22
- (0, globals_1.expect)(typeof token).toBe("string");
23
- });
24
- (0, globals_1.it)("should throw error when generating access token without secret key", () => {
25
- const invalidConfig = {
26
- ...config,
27
- accessToken: { issuer: { secretKey: "" } },
28
- };
29
- (0, globals_1.expect)(() => jwt_tools_1.JwtTools.generateAccessToken(payload, invalidConfig.accessToken)).toThrow(errors_1.UndefinedTokenSecretError);
30
- });
31
- (0, globals_1.it)("should generate a refresh token", () => {
32
- const token = jwt_tools_1.JwtTools.generateRefreshToken(payload, config.refreshToken);
33
- (0, globals_1.expect)(typeof token).toBe("string");
34
- });
35
- (0, globals_1.it)("should throw error when generating refresh token without secret key", () => {
36
- const invalidConfig = {
37
- ...config,
38
- refreshToken: { issuer: { secretKey: "" } },
39
- };
40
- (0, globals_1.expect)(() => jwt_tools_1.JwtTools.generateRefreshToken(payload, invalidConfig.refreshToken)).toThrow(errors_1.UndefinedTokenSecretError);
41
- });
42
- (0, globals_1.it)("should verify a valid access token", () => {
43
- const token = jwt_tools_1.JwtTools.generateAccessToken(payload, config.accessToken);
44
- const decoded = jwt_tools_1.JwtTools.verifyAccessToken(token, config.accessToken);
45
- (0, globals_1.expect)(decoded.id).toBe(payload.id);
46
- });
47
- (0, globals_1.it)("should throw error for undefined access token", () => {
48
- (0, globals_1.expect)(() => jwt_tools_1.JwtTools.verifyAccessToken("", config.accessToken)).toThrow(errors_1.UndefinedTokenError);
49
- });
50
- (0, globals_1.it)("should throw error for invalid access token", () => {
51
- (0, globals_1.expect)(() => jwt_tools_1.JwtTools.verifyAccessToken("invalid-token", config.accessToken)).toThrow(errors_1.InvalidTokenError);
52
- });
53
- (0, globals_1.it)("should verify a valid refresh token", () => {
54
- const token = jwt_tools_1.JwtTools.generateRefreshToken(payload, config.refreshToken);
55
- const decoded = jwt_tools_1.JwtTools.verifyRefreshToken(token, config.refreshToken);
56
- (0, globals_1.expect)(decoded.id).toBe(payload.id);
57
- });
58
- (0, globals_1.it)("should throw error for undefined refresh token", () => {
59
- (0, globals_1.expect)(() => jwt_tools_1.JwtTools.verifyRefreshToken("", config.refreshToken)).toThrow(errors_1.UndefinedTokenError);
60
- });
61
- (0, globals_1.it)("should throw error for invalid refresh token", () => {
62
- (0, globals_1.expect)(() => jwt_tools_1.JwtTools.verifyRefreshToken("invalid-token", config.refreshToken)).toThrow(errors_1.InvalidTokenError);
63
- });
64
- (0, globals_1.it)("should set the access token in the response header", () => {
65
- const token = jwt_tools_1.JwtTools.generateAccessToken(payload, config.accessToken);
66
- const context = { res: { setHeader: globals_1.jest.fn() } };
67
- jwt_tools_1.JwtTools.setAccessTokenHeader(token, context);
68
- (0, globals_1.expect)(context.res.setHeader).toHaveBeenCalledWith("Authorization", `Bearer ${token}`);
69
- });
70
- (0, globals_1.it)("should set the refresh token in cookies", () => {
71
- const token = jwt_tools_1.JwtTools.generateRefreshToken(payload, config.refreshToken);
72
- const context = { res: { cookie: globals_1.jest.fn() } };
73
- jwt_tools_1.JwtTools.setRefreshTokenCookie(token, context);
74
- (0, globals_1.expect)(context.res.cookie).toHaveBeenCalledWith("refreshToken", token, globals_1.expect.any(Object));
75
- });
76
- (0, globals_1.it)("should clear tokens from headers and cookies", () => {
77
- const context = {
78
- res: { clearCookie: globals_1.jest.fn(), setHeader: globals_1.jest.fn() },
79
- };
80
- jwt_tools_1.JwtTools.clearTokens(context);
81
- (0, globals_1.expect)(context.res.clearCookie).toHaveBeenCalledWith("refreshToken");
82
- (0, globals_1.expect)(context.res.setHeader).toHaveBeenCalledWith("Authorization", "");
83
- });
84
- (0, globals_1.it)("should retrieve an access token from request headers", () => {
85
- const token = jwt_tools_1.JwtTools.generateAccessToken(payload, config.accessToken);
86
- const context = {
87
- req: { headers: { authorization: `Bearer ${token}` } },
88
- };
89
- const extractedToken = jwt_tools_1.JwtTools.getAccessToken(context);
90
- (0, globals_1.expect)(extractedToken).toBe(token);
91
- });
92
- (0, globals_1.it)("should retrieve a refresh token from request cookies", () => {
93
- const token = jwt_tools_1.JwtTools.generateRefreshToken(payload, config.refreshToken);
94
- const context = { req: { cookies: { refreshToken: token } } };
95
- const extractedToken = jwt_tools_1.JwtTools.getRefreshToken(context);
96
- (0, globals_1.expect)(extractedToken).toBe(token);
97
- });
98
- });
@@ -1,115 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const local_strategy_1 = require("../local.strategy");
4
- const errors_1 = require("../../../errors");
5
- describe("LocalStrategy", () => {
6
- let strategy;
7
- let mockConfig;
8
- let mockSession;
9
- let mockJwt;
10
- beforeEach(() => {
11
- mockConfig = {
12
- credentials: {
13
- extractCredentials: jest.fn(),
14
- verifyCredentials: jest.fn(),
15
- },
16
- user: {
17
- fetchUser: jest.fn(),
18
- },
19
- routes: {
20
- login: {},
21
- logout: {},
22
- },
23
- };
24
- mockSession = {
25
- issueSession: jest.fn(),
26
- };
27
- mockJwt = {
28
- issueTokens: jest.fn(),
29
- };
30
- strategy = new local_strategy_1.LocalStrategy(mockConfig, mockSession, mockJwt);
31
- });
32
- describe("extractCredentials", () => {
33
- it("should extract credentials from context", async () => {
34
- const mockContext = { body: { username: "test", password: "pass123" } };
35
- mockConfig.credentials.extractCredentials.mockResolvedValue({
36
- identifier: "test",
37
- password: "pass123",
38
- });
39
- const credentials = await strategy.extractCredentials(mockContext);
40
- expect(credentials).toEqual({ identifier: "test", password: "pass123" });
41
- expect(mockConfig.credentials.extractCredentials).toHaveBeenCalledWith(mockContext);
42
- });
43
- it("should throw MissingCredentialsError if no credentials are provided", async () => {
44
- mockConfig.credentials.extractCredentials.mockRejectedValue(new errors_1.MissingCredentialsError());
45
- await expect(strategy.extractCredentials({})).rejects.toThrow(errors_1.MissingCredentialsError);
46
- });
47
- });
48
- describe("verifyCredentials", () => {
49
- it("should verify credentials successfully", async () => {
50
- mockConfig.credentials.verifyCredentials.mockResolvedValue(true);
51
- const result = await strategy.verifyCredentials("test", "pass123");
52
- expect(result).toBe(true);
53
- expect(mockConfig.credentials.verifyCredentials).toHaveBeenCalledWith("test", "pass123");
54
- });
55
- it("should return false if credentials are invalid", async () => {
56
- mockConfig.credentials.verifyCredentials.mockResolvedValue(false);
57
- const result = await strategy.verifyCredentials("test", "wrongpass");
58
- expect(result).toBe(false);
59
- expect(mockConfig.credentials.verifyCredentials).toHaveBeenCalledWith("test", "wrongpass");
60
- });
61
- });
62
- describe("fetchUser", () => {
63
- it("should fetch user data", async () => {
64
- const mockUser = { id: 1, username: "test" };
65
- mockConfig.user.fetchUser.mockResolvedValue(mockUser);
66
- const user = await strategy.fetchUser({
67
- identifier: "test",
68
- password: "pass123",
69
- });
70
- expect(user).toEqual(mockUser);
71
- expect(mockConfig.user.fetchUser).toHaveBeenCalledWith("test");
72
- });
73
- it("should return null if user is not found", async () => {
74
- mockConfig.user.fetchUser.mockResolvedValue(null);
75
- const user = await strategy.fetchUser({
76
- identifier: "unknown",
77
- password: "pass123",
78
- });
79
- expect(user).toBeNull();
80
- expect(mockConfig.user.fetchUser).toHaveBeenCalledWith("unknown");
81
- });
82
- });
83
- describe("login", () => {
84
- const mockContext = { body: { username: "test", password: "pass123" } };
85
- const mockUser = { id: 1, username: "test" };
86
- const mockTokens = { accessToken: "access", refreshToken: "refresh" };
87
- const mockSessionData = { sessionId: "session123", data: mockUser };
88
- beforeEach(() => {
89
- mockConfig.credentials.extractCredentials.mockResolvedValue({
90
- identifier: "test",
91
- password: "pass123",
92
- });
93
- mockConfig.credentials.verifyCredentials.mockResolvedValue(true);
94
- mockConfig.user.fetchUser.mockResolvedValue(mockUser);
95
- mockJwt.issueTokens.mockResolvedValue(mockTokens);
96
- mockSession.issueSession.mockResolvedValue(mockSessionData);
97
- });
98
- it("should login and return user with tokens and session", async () => {
99
- const result = await strategy.login(mockContext);
100
- expect(result.user).toEqual(mockUser);
101
- expect(result.tokens).toEqual(mockTokens);
102
- expect(result.session).toEqual(mockSessionData);
103
- expect(mockJwt.issueTokens).toHaveBeenCalledWith(mockUser, mockContext);
104
- expect(mockSession.issueSession).toHaveBeenCalledWith(mockUser, mockContext);
105
- });
106
- it("should throw InvalidCredentialsError if credentials are incorrect", async () => {
107
- mockConfig.credentials.verifyCredentials.mockResolvedValue(false);
108
- await expect(strategy.login(mockContext)).rejects.toThrow(errors_1.InvalidCredentialsError);
109
- });
110
- it("should throw UserNotFoundError if user is not found", async () => {
111
- mockConfig.user.fetchUser.mockResolvedValue(null);
112
- await expect(strategy.login(mockContext)).rejects.toThrow(errors_1.UserNotFoundError);
113
- });
114
- });
115
- });