@soapjs/soap-auth 0.3.2 → 0.4.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 (77) hide show
  1. package/.claude/settings.local.json +20 -0
  2. package/build/__tests__/soap-auth.test.js +94 -0
  3. package/build/errors.d.ts +1 -1
  4. package/build/errors.js +2 -2
  5. package/build/index.d.ts +1 -0
  6. package/build/index.js +1 -0
  7. package/build/services/__tests__/password.service.test.js +25 -18
  8. package/build/services/__tests__/totp.service.test.d.ts +1 -0
  9. package/build/services/__tests__/totp.service.test.js +120 -0
  10. package/build/services/auth-throttle.service.d.ts +2 -2
  11. package/build/services/auth-throttle.service.js +2 -2
  12. package/build/services/index.d.ts +1 -0
  13. package/build/services/index.js +1 -0
  14. package/build/services/password.service.d.ts +7 -5
  15. package/build/services/password.service.js +76 -18
  16. package/build/services/totp.service.d.ts +16 -0
  17. package/build/services/totp.service.js +96 -0
  18. package/build/session/__tests__/session-handler.test.js +22 -14
  19. package/build/session/session-handler.d.ts +1 -0
  20. package/build/session/session-handler.js +39 -6
  21. package/build/soap-auth.d.ts +13 -6
  22. package/build/soap-auth.js +132 -5
  23. package/build/strategies/__tests__/base-auth.strategy.test.d.ts +3 -2
  24. package/build/strategies/__tests__/base-auth.strategy.test.js +1 -0
  25. package/build/strategies/__tests__/credential-auth.strategy.test.d.ts +1 -0
  26. package/build/strategies/__tests__/credential-auth.strategy.test.js +18 -17
  27. package/build/strategies/__tests__/token-auth.strategy.test.d.ts +1 -0
  28. package/build/strategies/__tests__/token-auth.strategy.test.js +1 -0
  29. package/build/strategies/api-key/api-key.strategy.d.ts +4 -4
  30. package/build/strategies/api-key/api-key.strategy.js +3 -2
  31. package/build/strategies/base-auth.strategy.d.ts +5 -4
  32. package/build/strategies/basic/basic.strategy.d.ts +2 -1
  33. package/build/strategies/basic/basic.strategy.js +1 -0
  34. package/build/strategies/credential-auth.strategy.d.ts +7 -7
  35. package/build/strategies/credential-auth.strategy.js +9 -14
  36. package/build/strategies/index.d.ts +1 -0
  37. package/build/strategies/index.js +1 -0
  38. package/build/strategies/jwt/__tests__/jwt.strategy.test.js +2 -2
  39. package/build/strategies/jwt/jwt.strategy.d.ts +3 -1
  40. package/build/strategies/jwt/jwt.strategy.js +35 -6
  41. package/build/strategies/jwt/jwt.tools.js +8 -8
  42. package/build/strategies/local/__tests__/local.strategy.test.js +8 -2
  43. package/build/strategies/local/local.strategy.d.ts +4 -1
  44. package/build/strategies/local/local.strategy.js +81 -0
  45. package/build/strategies/oauth2/__tests__/oauth2.strategy.test.d.ts +1 -0
  46. package/build/strategies/oauth2/__tests__/oauth2.strategy.test.js +239 -0
  47. package/build/strategies/oauth2/hybrid.oauth2.strategy.d.ts +3 -3
  48. package/build/strategies/oauth2/hybrid.oauth2.strategy.js +1 -6
  49. package/build/strategies/oauth2/oauth2.errors.d.ts +1 -0
  50. package/build/strategies/oauth2/oauth2.errors.js +4 -0
  51. package/build/strategies/oauth2/oauth2.strategy.d.ts +6 -4
  52. package/build/strategies/oauth2/oauth2.strategy.js +114 -46
  53. package/build/strategies/oauth2/oauth2.tools.js +2 -2
  54. package/build/strategies/oauth2/oauth2.types.d.ts +2 -2
  55. package/build/strategies/oauth2/providers/__tests__/social-providers.test.d.ts +1 -0
  56. package/build/strategies/oauth2/providers/__tests__/social-providers.test.js +201 -0
  57. package/build/strategies/oauth2/providers/facebook.strategy.d.ts +11 -0
  58. package/build/strategies/oauth2/providers/facebook.strategy.js +58 -0
  59. package/build/strategies/oauth2/providers/github.strategy.d.ts +11 -0
  60. package/build/strategies/oauth2/providers/github.strategy.js +56 -0
  61. package/build/strategies/oauth2/providers/google.strategy.d.ts +11 -0
  62. package/build/strategies/oauth2/providers/google.strategy.js +52 -0
  63. package/build/strategies/oauth2/providers/http-oauth2.strategy.d.ts +16 -0
  64. package/build/strategies/oauth2/providers/http-oauth2.strategy.js +49 -0
  65. package/build/strategies/oauth2/providers/index.d.ts +5 -0
  66. package/build/strategies/oauth2/providers/index.js +21 -0
  67. package/build/strategies/oauth2/providers/provider.types.d.ts +7 -0
  68. package/build/strategies/oauth2/providers/provider.types.js +2 -0
  69. package/build/strategies/token-auth.strategy.d.ts +4 -4
  70. package/build/strategies/token-auth.strategy.js +2 -3
  71. package/build/tools/tools.js +1 -2
  72. package/build/types.d.ts +31 -32
  73. package/build/utils/__tests__/validation.test.d.ts +1 -0
  74. package/build/utils/__tests__/validation.test.js +181 -0
  75. package/build/utils/validation.d.ts +23 -0
  76. package/build/utils/validation.js +139 -0
  77. package/package.json +8 -7
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TotpService = void 0;
4
+ const crypto_1 = require("crypto");
5
+ const BASE32_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
6
+ function base32Encode(buf) {
7
+ let bits = 0;
8
+ let value = 0;
9
+ let output = "";
10
+ for (const byte of buf) {
11
+ value = (value << 8) | byte;
12
+ bits += 8;
13
+ while (bits >= 5) {
14
+ output += BASE32_CHARS[(value >>> (bits - 5)) & 31];
15
+ bits -= 5;
16
+ }
17
+ }
18
+ if (bits > 0) {
19
+ output += BASE32_CHARS[(value << (5 - bits)) & 31];
20
+ }
21
+ return output;
22
+ }
23
+ function base32Decode(str) {
24
+ const s = str.replace(/=+$/, "").toUpperCase();
25
+ const bytes = [];
26
+ let bits = 0;
27
+ let value = 0;
28
+ for (const ch of s) {
29
+ const idx = BASE32_CHARS.indexOf(ch);
30
+ if (idx === -1)
31
+ throw new Error(`Invalid base32 character: ${ch}`);
32
+ value = (value << 5) | idx;
33
+ bits += 5;
34
+ if (bits >= 8) {
35
+ bytes.push((value >>> (bits - 8)) & 255);
36
+ bits -= 8;
37
+ }
38
+ }
39
+ return Buffer.from(bytes);
40
+ }
41
+ function hotp(key, counter, digits) {
42
+ const buf = Buffer.alloc(8);
43
+ buf.writeBigUInt64BE(counter);
44
+ const hmac = (0, crypto_1.createHmac)("sha1", key).update(buf).digest();
45
+ const offset = hmac[hmac.length - 1] & 0x0f;
46
+ const code = ((hmac[offset] & 0x7f) << 24) |
47
+ ((hmac[offset + 1] & 0xff) << 16) |
48
+ ((hmac[offset + 2] & 0xff) << 8) |
49
+ (hmac[offset + 3] & 0xff);
50
+ return String(code % 10 ** digits).padStart(digits, "0");
51
+ }
52
+ class TotpService {
53
+ step;
54
+ digits;
55
+ window;
56
+ constructor(options = {}) {
57
+ this.step = options.step ?? 30;
58
+ this.digits = options.digits ?? 6;
59
+ this.window = options.window ?? 1;
60
+ }
61
+ generateSecret(byteLength = 20) {
62
+ return base32Encode((0, crypto_1.randomBytes)(byteLength));
63
+ }
64
+ generateOTP(secret, timestamp = Date.now()) {
65
+ const key = base32Decode(secret);
66
+ const counter = BigInt(Math.floor(timestamp / 1000 / this.step));
67
+ return hotp(key, counter, this.digits);
68
+ }
69
+ verifyOTP(secret, code, timestamp = Date.now()) {
70
+ if (!/^\d+$/.test(code) || code.length !== this.digits)
71
+ return false;
72
+ const key = base32Decode(secret);
73
+ const counter = BigInt(Math.floor(timestamp / 1000 / this.step));
74
+ for (let delta = -this.window; delta <= this.window; delta++) {
75
+ const expected = hotp(key, counter + BigInt(delta), this.digits);
76
+ if (expected === code)
77
+ return true;
78
+ }
79
+ return false;
80
+ }
81
+ generateQRUri(secret, issuer, account) {
82
+ const params = new URLSearchParams({
83
+ secret,
84
+ issuer,
85
+ algorithm: "SHA1",
86
+ digits: String(this.digits),
87
+ period: String(this.step),
88
+ });
89
+ const label = `${encodeURIComponent(issuer)}:${encodeURIComponent(account)}`;
90
+ return `otpauth://totp/${label}?${params.toString()}`;
91
+ }
92
+ generateBackupCodes(count = 8) {
93
+ return Array.from({ length: count }, () => (0, crypto_1.randomBytes)(6).toString("hex").toUpperCase());
94
+ }
95
+ }
96
+ exports.TotpService = TotpService;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const session_handler_1 = require("../session-handler");
4
4
  const session_errors_1 = require("../session.errors");
5
+ const validation_1 = require("../../utils/validation");
5
6
  describe("SessionHandler", () => {
6
7
  let mockStore;
7
8
  let mockLogger;
@@ -21,6 +22,7 @@ describe("SessionHandler", () => {
21
22
  warn: jest.fn(),
22
23
  };
23
24
  config = {
25
+ secret: "test-secret-key",
24
26
  store: mockStore,
25
27
  sessionKey: "CUSTOMSESSION",
26
28
  sessionHeader: "x-custom-session",
@@ -29,7 +31,7 @@ describe("SessionHandler", () => {
29
31
  maxAge: 3600,
30
32
  },
31
33
  generateSessionId: jest.fn(),
32
- getSessionId: undefined,
34
+ getSessionId: jest.fn(),
33
35
  embedSessionId: undefined,
34
36
  createSessionData: undefined,
35
37
  };
@@ -39,10 +41,10 @@ describe("SessionHandler", () => {
39
41
  it("should throw if store is not provided", () => {
40
42
  expect(() => {
41
43
  new session_handler_1.SessionHandler({});
42
- }).toThrowError("Session store is required.");
44
+ }).toThrowError("config.secret is required");
43
45
  });
44
46
  it("should set default sessionKey and headerKey if not provided", () => {
45
- const newHandler = new session_handler_1.SessionHandler({ store: mockStore });
47
+ const newHandler = new session_handler_1.SessionHandler({ secret: "test-secret", store: mockStore });
46
48
  expect(newHandler.sessionKey).toBe("SESSIONID");
47
49
  expect(newHandler.headerKey).toBe("x-session-id");
48
50
  });
@@ -94,7 +96,7 @@ describe("SessionHandler", () => {
94
96
  throw new Error("Test error");
95
97
  });
96
98
  const handler = new session_handler_1.SessionHandler(config, mockLogger);
97
- handler.setSessionId({}, "boom");
99
+ expect(() => handler.setSessionId({}, "boom")).toThrow("Test error");
98
100
  expect(mockLogger.error).toHaveBeenCalledWith("Error setting session ID:", expect.any(Error));
99
101
  });
100
102
  });
@@ -107,23 +109,31 @@ describe("SessionHandler", () => {
107
109
  expect(config.getSessionId).toHaveBeenCalled();
108
110
  });
109
111
  it("should return cookie session if present", () => {
112
+ config.getSessionId = undefined;
113
+ const handler = new session_handler_1.SessionHandler(config, mockLogger);
110
114
  const context = { cookies: { CUSTOMSESSION: "cookieValue" } };
111
- const sid = sessionHandler.getSessionId(context);
115
+ const sid = handler.getSessionId(context);
112
116
  expect(sid).toBe("cookieValue");
113
117
  });
114
118
  it("should return header session if present", () => {
119
+ config.getSessionId = undefined;
120
+ const handler = new session_handler_1.SessionHandler(config, mockLogger);
115
121
  const context = { headers: { "x-custom-session": "headerValue" } };
116
- const sid = sessionHandler.getSessionId(context);
122
+ const sid = handler.getSessionId(context);
117
123
  expect(sid).toBe("headerValue");
118
124
  });
119
125
  it("should return sessionId if set directly on context", () => {
126
+ config.getSessionId = undefined;
127
+ const handler = new session_handler_1.SessionHandler(config, mockLogger);
120
128
  const context = { sessionId: "directValue" };
121
- const sid = sessionHandler.getSessionId(context);
129
+ const sid = handler.getSessionId(context);
122
130
  expect(sid).toBe("directValue");
123
131
  });
124
132
  it("should return null if not found", () => {
133
+ config.getSessionId = undefined;
134
+ const handler = new session_handler_1.SessionHandler(config, mockLogger);
125
135
  const context = {};
126
- const sid = sessionHandler.getSessionId(context);
136
+ const sid = handler.getSessionId(context);
127
137
  expect(sid).toBeNull();
128
138
  });
129
139
  it("should log error and return null if something goes wrong", () => {
@@ -180,10 +190,8 @@ describe("SessionHandler", () => {
180
190
  });
181
191
  });
182
192
  describe("setSessionData", () => {
183
- it("should warn if sessionId is falsy", async () => {
184
- await sessionHandler.setSessionData("", { user: {} });
185
- expect(mockLogger.warn).toHaveBeenCalledWith("No session ID found, unable to set session.");
186
- expect(mockStore.setSession).not.toHaveBeenCalled();
193
+ it("should throw ValidationError if sessionId is falsy", async () => {
194
+ await expect(sessionHandler.setSessionData("", { user: {} })).rejects.toThrow(validation_1.ValidationError);
187
195
  });
188
196
  it("should call store.setSession with provided data", async () => {
189
197
  await sessionHandler.setSessionData("sessionXYZ", {
@@ -196,9 +204,9 @@ describe("SessionHandler", () => {
196
204
  });
197
205
  it("should log error if store.setSession fails", async () => {
198
206
  mockStore.setSession.mockRejectedValue(new Error("Store error"));
199
- await sessionHandler.setSessionData("session123", {
207
+ await expect(sessionHandler.setSessionData("session123", {
200
208
  user: { id: "xyz" },
201
- });
209
+ })).rejects.toThrow("Store error");
202
210
  expect(mockLogger.error).toHaveBeenCalledWith("Error storing session data:", expect.any(Error));
203
211
  });
204
212
  });
@@ -7,6 +7,7 @@ export declare class SessionHandler<TContext = unknown, TUser = unknown, TData =
7
7
  private sessionKey;
8
8
  private headerKey;
9
9
  constructor(config: SessionConfig, logger?: Soap.Logger);
10
+ private validateConfig;
10
11
  setSessionId(context: TContext, sessionId: string): void;
11
12
  getSessionId(context: TContext): string | null;
12
13
  generateSessionId(): string;
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SessionHandler = void 0;
4
- const uuid_1 = require("uuid");
4
+ const crypto_1 = require("crypto");
5
5
  const session_errors_1 = require("./session.errors");
6
+ const validation_1 = require("../utils/validation");
6
7
  class SessionHandler {
7
8
  config;
8
9
  logger;
@@ -12,6 +13,7 @@ class SessionHandler {
12
13
  constructor(config, logger) {
13
14
  this.config = config;
14
15
  this.logger = logger;
16
+ this.validateConfig(config);
15
17
  if (!config.store) {
16
18
  throw new Error("Session store is required.");
17
19
  }
@@ -19,8 +21,37 @@ class SessionHandler {
19
21
  this.sessionKey = config.sessionKey || "SESSIONID";
20
22
  this.headerKey = config.sessionHeader || "x-session-id";
21
23
  }
24
+ validateConfig(config) {
25
+ try {
26
+ validation_1.ValidationUtils.required(config, "config");
27
+ validation_1.ValidationUtils.required(config.secret, "config.secret");
28
+ validation_1.ValidationUtils.nonEmptyString(config.secret, "config.secret");
29
+ validation_1.ValidationUtils.required(config.store, "config.store");
30
+ validation_1.ValidationUtils.object(config.store, "config.store");
31
+ if (config.sessionKey) {
32
+ validation_1.ValidationUtils.nonEmptyString(config.sessionKey, "config.sessionKey");
33
+ }
34
+ if (config.sessionHeader) {
35
+ validation_1.ValidationUtils.nonEmptyString(config.sessionHeader, "config.sessionHeader");
36
+ }
37
+ const requiredMethods = ['getSession', 'setSession', 'destroySession', 'touchSession', 'getSessionIds'];
38
+ for (const method of requiredMethods) {
39
+ if (typeof config.store[method] !== 'function') {
40
+ throw new validation_1.ValidationError(`Session store must implement ${method} method`);
41
+ }
42
+ }
43
+ }
44
+ catch (error) {
45
+ if (error instanceof validation_1.ValidationError) {
46
+ throw error;
47
+ }
48
+ throw new validation_1.ValidationError(`Invalid SessionHandler configuration: ${error.message}`);
49
+ }
50
+ }
22
51
  setSessionId(context, sessionId) {
23
52
  try {
53
+ validation_1.ValidationUtils.required(context, "context");
54
+ validation_1.ValidationUtils.nonEmptyString(sessionId, "sessionId");
24
55
  if (this.config.embedSessionId) {
25
56
  this.config.embedSessionId(context, sessionId);
26
57
  return;
@@ -48,10 +79,12 @@ class SessionHandler {
48
79
  }
49
80
  catch (error) {
50
81
  this.config.logger?.error("Error setting session ID:", error);
82
+ throw error;
51
83
  }
52
84
  }
53
85
  getSessionId(context) {
54
86
  try {
87
+ validation_1.ValidationUtils.required(context, "context");
55
88
  if (this.config.getSessionId) {
56
89
  return this.config.getSessionId(context);
57
90
  }
@@ -74,7 +107,7 @@ class SessionHandler {
74
107
  }
75
108
  }
76
109
  generateSessionId() {
77
- return this.config.generateSessionId?.() || (0, uuid_1.v4)();
110
+ return this.config.generateSessionId?.() || (0, crypto_1.randomUUID)();
78
111
  }
79
112
  buildSessionData(data, context) {
80
113
  return this.config.createSessionData
@@ -83,6 +116,7 @@ class SessionHandler {
83
116
  }
84
117
  async getSessionData(sessionId) {
85
118
  try {
119
+ validation_1.ValidationUtils.nonEmptyString(sessionId, "sessionId");
86
120
  const data = await this.store.getSession(sessionId);
87
121
  return data;
88
122
  }
@@ -93,15 +127,14 @@ class SessionHandler {
93
127
  }
94
128
  async setSessionData(sessionId, data) {
95
129
  try {
96
- if (!sessionId) {
97
- this.config.logger?.warn("No session ID found, unable to set session.");
98
- return;
99
- }
130
+ validation_1.ValidationUtils.nonEmptyString(sessionId, "sessionId");
131
+ validation_1.ValidationUtils.required(data, "data");
100
132
  await this.store.setSession(sessionId, data);
101
133
  this.config.logger?.info(`Session set for ID: ${sessionId}`);
102
134
  }
103
135
  catch (error) {
104
136
  this.config.logger?.error("Error storing session data:", error);
137
+ throw error;
105
138
  }
106
139
  }
107
140
  async touch(sessionId, data) {
@@ -1,17 +1,24 @@
1
- import { AuthCategories, AuthStrategy, SoapAuthConfig } from "./types";
1
+ import * as Soap from "@soapjs/soap";
2
+ import { AuthCategories, SoapAuthConfig } from "./types";
2
3
  export declare class SoapAuth {
3
4
  private requiredStrategyMethods;
4
5
  private strategies;
5
6
  private logger?;
6
7
  constructor(config: SoapAuthConfig);
8
+ private validateConfig;
9
+ private validateSessionConfig;
10
+ private validateJwtConfig;
11
+ private validateHttpStrategies;
12
+ private validateSocketStrategies;
7
13
  private isAuthStrategy;
8
- addStrategy(strategyInstance: AuthStrategy | undefined, name: string, type: AuthCategories): void;
14
+ addStrategy(strategyInstance: Soap.AuthStrategy | undefined, name: string, type: AuthCategories): void;
9
15
  removeStrategy(name: string | string[], type: AuthCategories): void;
10
16
  hasStrategy(name: string, type: AuthCategories): boolean;
11
- getStrategy<T = unknown>(name: string, type: AuthCategories): T | AuthStrategy | undefined;
12
- getHttpStrategy<T = unknown>(name: string): T | AuthStrategy | undefined;
13
- getSocketStrategy<T = unknown>(name: string): T | AuthStrategy | undefined;
14
- getEventStrategy<T = unknown>(name: string): T | AuthStrategy | undefined;
17
+ getStrategy<T extends Soap.AuthStrategy>(name: string, type: AuthCategories): T;
18
+ getHttpStrategy<T extends Soap.AuthStrategy>(name: string): T;
19
+ getSocketStrategy<T extends Soap.AuthStrategy>(name: string): T;
20
+ getEventStrategy<T extends Soap.AuthStrategy>(name: string): T;
15
21
  listStrategies(type: AuthCategories): string[];
16
22
  init(sequential?: boolean): Promise<void>;
23
+ static create(config: SoapAuthConfig): Promise<SoapAuth>;
17
24
  }
@@ -1,11 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SoapAuth = void 0;
4
+ const validation_1 = require("./utils/validation");
5
+ const session_handler_1 = require("./session/session-handler");
6
+ const jwt_strategy_1 = require("./strategies/jwt/jwt.strategy");
7
+ const local_strategy_1 = require("./strategies/local/local.strategy");
8
+ const basic_strategy_1 = require("./strategies/basic/basic.strategy");
9
+ const api_key_strategy_1 = require("./strategies/api-key/api-key.strategy");
4
10
  class SoapAuth {
5
- requiredStrategyMethods = ["authenticate", "init"];
11
+ requiredStrategyMethods = ["authenticate"];
6
12
  strategies = new Map();
7
13
  logger;
8
14
  constructor(config) {
15
+ this.validateConfig(config);
9
16
  this.strategies.set("http", new Map());
10
17
  this.strategies.set("socket", new Map());
11
18
  this.strategies.set("event", new Map());
@@ -15,12 +22,83 @@ class SoapAuth {
15
22
  this.strategies.set("edge", new Map());
16
23
  this.logger = config.logger;
17
24
  }
25
+ validateConfig(config) {
26
+ try {
27
+ validation_1.ValidationUtils.required(config, "config");
28
+ if (config.logger) {
29
+ validation_1.ValidationUtils.object(config.logger, "config.logger");
30
+ }
31
+ if (config.session) {
32
+ this.validateSessionConfig(config.session);
33
+ }
34
+ if (config.jwt) {
35
+ this.validateJwtConfig(config.jwt);
36
+ }
37
+ if (config.http) {
38
+ this.validateHttpStrategies(config.http);
39
+ }
40
+ if (config.socket) {
41
+ this.validateSocketStrategies(config.socket);
42
+ }
43
+ }
44
+ catch (error) {
45
+ if (error instanceof validation_1.ValidationError) {
46
+ throw error;
47
+ }
48
+ throw new validation_1.ValidationError(`Invalid configuration: ${error.message}`);
49
+ }
50
+ }
51
+ validateSessionConfig(session) {
52
+ validation_1.ValidationUtils.required(session.secret, "session.secret");
53
+ validation_1.ValidationUtils.nonEmptyString(session.secret, "session.secret");
54
+ if (session.sessionKey) {
55
+ validation_1.ValidationUtils.nonEmptyString(session.sessionKey, "session.sessionKey");
56
+ }
57
+ if (session.sessionHeader) {
58
+ validation_1.ValidationUtils.nonEmptyString(session.sessionHeader, "session.sessionHeader");
59
+ }
60
+ }
61
+ validateJwtConfig(jwt) {
62
+ if (jwt.accessToken) {
63
+ validation_1.ValidationUtils.required(jwt.accessToken.issuer, "jwt.accessToken.issuer");
64
+ validation_1.ValidationUtils.required(jwt.accessToken.issuer.secretKey, "jwt.accessToken.issuer.secretKey");
65
+ validation_1.ValidationUtils.nonEmptyString(jwt.accessToken.issuer.secretKey, "jwt.accessToken.issuer.secretKey");
66
+ }
67
+ if (jwt.refreshToken) {
68
+ validation_1.ValidationUtils.required(jwt.refreshToken.issuer, "jwt.refreshToken.issuer");
69
+ validation_1.ValidationUtils.required(jwt.refreshToken.issuer.secretKey, "jwt.refreshToken.issuer.secretKey");
70
+ validation_1.ValidationUtils.nonEmptyString(jwt.refreshToken.issuer.secretKey, "jwt.refreshToken.issuer.secretKey");
71
+ }
72
+ }
73
+ validateHttpStrategies(http) {
74
+ validation_1.ValidationUtils.object(http, "http");
75
+ if (http.custom) {
76
+ validation_1.ValidationUtils.object(http.custom, "http.custom");
77
+ for (const [name, strategy] of Object.entries(http.custom)) {
78
+ validation_1.ValidationUtils.required(strategy, `http.custom.${name}`);
79
+ validation_1.ValidationUtils.object(strategy, `http.custom.${name}`);
80
+ }
81
+ }
82
+ }
83
+ validateSocketStrategies(socket) {
84
+ validation_1.ValidationUtils.object(socket, "socket");
85
+ if (socket.custom) {
86
+ validation_1.ValidationUtils.object(socket.custom, "socket.custom");
87
+ for (const [name, strategy] of Object.entries(socket.custom)) {
88
+ validation_1.ValidationUtils.required(strategy, `socket.custom.${name}`);
89
+ validation_1.ValidationUtils.object(strategy, `socket.custom.${name}`);
90
+ }
91
+ }
92
+ }
18
93
  isAuthStrategy(strategy) {
19
94
  return (typeof strategy === "object" &&
20
95
  strategy !== null &&
21
96
  this.requiredStrategyMethods.every((method) => typeof strategy[method] === "function"));
22
97
  }
23
98
  addStrategy(strategyInstance, name, type) {
99
+ validation_1.ValidationUtils.required(strategyInstance, "strategyInstance");
100
+ validation_1.ValidationUtils.nonEmptyString(name, "name");
101
+ validation_1.ValidationUtils.oneOf(type, "type", ["http", "socket", "event", "isa", "webhook", "grpc", "edge"]);
24
102
  if (!this.strategies.has(type)) {
25
103
  throw new Error(`Invalid strategy type "${type}".`);
26
104
  }
@@ -33,21 +111,28 @@ class SoapAuth {
33
111
  }
34
112
  }
35
113
  removeStrategy(name, type) {
114
+ validation_1.ValidationUtils.required(name, "name");
115
+ validation_1.ValidationUtils.oneOf(type, "type", ["http", "socket", "event", "isa", "webhook", "grpc", "edge"]);
36
116
  if (!this.strategies.has(type)) {
37
117
  throw new Error(`Invalid strategy type "${type}".`);
38
118
  }
39
119
  const names = Array.isArray(name) ? name : [name];
40
120
  names.forEach((n) => {
121
+ validation_1.ValidationUtils.nonEmptyString(n, "strategy name");
41
122
  this.strategies.get(type).delete(n);
42
123
  });
43
124
  }
44
125
  hasStrategy(name, type) {
126
+ validation_1.ValidationUtils.nonEmptyString(name, "name");
127
+ validation_1.ValidationUtils.oneOf(type, "type", ["http", "socket", "event", "isa", "webhook", "grpc", "edge"]);
45
128
  if (!this.strategies.has(type)) {
46
129
  throw new Error(`Invalid strategy type "${type}".`);
47
130
  }
48
131
  return this.strategies.get(type).has(name);
49
132
  }
50
133
  getStrategy(name, type) {
134
+ validation_1.ValidationUtils.nonEmptyString(name, "name");
135
+ validation_1.ValidationUtils.oneOf(type, "type", ["http", "socket", "event", "isa", "webhook", "grpc", "edge"]);
51
136
  if (!this.strategies.has(type)) {
52
137
  throw new Error(`Invalid strategy type "${type}".`);
53
138
  }
@@ -101,7 +186,7 @@ class SoapAuth {
101
186
  if (sequential) {
102
187
  for (const strategy of strategies) {
103
188
  try {
104
- await strategy.init();
189
+ await strategy.init?.();
105
190
  }
106
191
  catch (error) {
107
192
  this.logger?.error(`Failed to initialize strategy: ${error.message}`);
@@ -109,10 +194,52 @@ class SoapAuth {
109
194
  }
110
195
  }
111
196
  else {
112
- await Promise.all(strategies.map((strategy) => strategy
113
- .init()
114
- .catch((error) => this.logger?.error(`Failed to initialize strategy: ${error.message}`))));
197
+ await Promise.all(strategies.map((strategy) => Promise.resolve(strategy.init?.()).catch((error) => this.logger?.error(`Failed to initialize strategy: ${error.message}`))));
198
+ }
199
+ }
200
+ static async create(config) {
201
+ const auth = new SoapAuth(config);
202
+ const logger = config.logger;
203
+ const sessionHandler = config.session
204
+ ? new session_handler_1.SessionHandler(config.session, logger)
205
+ : undefined;
206
+ if (config.http) {
207
+ const sharedJwt = config.http.jwt
208
+ ? new jwt_strategy_1.JwtStrategy(config.http.jwt, logger)
209
+ : undefined;
210
+ if (config.http.local) {
211
+ auth.addStrategy(new local_strategy_1.LocalStrategy(config.http.local, sessionHandler, sharedJwt, logger), "local", "http");
212
+ }
213
+ if (config.http.basic) {
214
+ auth.addStrategy(new basic_strategy_1.BasicStrategy(config.http.basic, sessionHandler, sharedJwt, logger), "basic", "http");
215
+ }
216
+ if (config.http.apiKey) {
217
+ auth.addStrategy(new api_key_strategy_1.ApiKeyStrategy(config.http.apiKey, logger), "api-key", "http");
218
+ }
219
+ if (sharedJwt) {
220
+ auth.addStrategy(sharedJwt, "jwt", "http");
221
+ }
222
+ if (config.http.custom) {
223
+ for (const [name, strategy] of Object.entries(config.http.custom)) {
224
+ auth.addStrategy(strategy, name, "http");
225
+ }
226
+ }
227
+ }
228
+ if (config.socket) {
229
+ if (config.socket.jwt) {
230
+ auth.addStrategy(new jwt_strategy_1.JwtStrategy(config.socket.jwt, logger), "jwt", "socket");
231
+ }
232
+ if (config.socket.apiKey) {
233
+ auth.addStrategy(new api_key_strategy_1.ApiKeyStrategy(config.socket.apiKey, logger), "api-key", "socket");
234
+ }
235
+ if (config.socket.custom) {
236
+ for (const [name, strategy] of Object.entries(config.socket.custom)) {
237
+ auth.addStrategy(strategy, name, "socket");
238
+ }
239
+ }
115
240
  }
241
+ await auth.init();
242
+ return auth;
116
243
  }
117
244
  }
118
245
  exports.SoapAuth = SoapAuth;
@@ -1,4 +1,4 @@
1
- import { AuthResult, BaseAuthStrategyConfig } from "../../../src/types";
1
+ import { BaseAuthStrategyConfig } from "../../../src/types";
2
2
  import { SessionHandler } from "../../../src/session/session-handler";
3
3
  import * as Soap from "@soapjs/soap";
4
4
  import { BaseAuthStrategy } from "../base-auth.strategy";
@@ -9,6 +9,7 @@ export interface MockUser {
9
9
  export interface MockContext {
10
10
  }
11
11
  export declare class TestBaseAuthStrategy extends BaseAuthStrategy<MockContext, MockUser> {
12
+ readonly name = "test";
12
13
  constructor(config: BaseAuthStrategyConfig<MockContext, MockUser>, session?: SessionHandler, logger?: Soap.Logger);
13
- authenticate(context?: MockContext): Promise<AuthResult<MockUser>>;
14
+ authenticate(context?: MockContext): Promise<Soap.AuthResult<MockUser> | null>;
14
15
  }
@@ -4,6 +4,7 @@ exports.TestBaseAuthStrategy = void 0;
4
4
  const session_errors_1 = require("../../../src/session/session.errors");
5
5
  const base_auth_strategy_1 = require("../base-auth.strategy");
6
6
  class TestBaseAuthStrategy extends base_auth_strategy_1.BaseAuthStrategy {
7
+ name = "test";
7
8
  constructor(config, session, logger) {
8
9
  super(config, session, logger);
9
10
  }
@@ -4,6 +4,7 @@ import { JwtStrategy } from "../../../src/strategies/jwt/jwt.strategy";
4
4
  import * as Soap from "@soapjs/soap";
5
5
  import { CredentialAuthStrategy } from "../credential-auth.strategy";
6
6
  export declare class TestCredentialAuthStrategy extends CredentialAuthStrategy<any, any> {
7
+ readonly name = "test-credential";
7
8
  constructor(config: CredentialAuthStrategyConfig<any, any>, session?: SessionHandler, jwt?: JwtStrategy<any, any>, logger?: Soap.Logger);
8
9
  protected verifyCredentials(identifier: string, password: string): Promise<boolean>;
9
10
  protected extractCredentials(context: any): Promise<{