@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
@@ -0,0 +1,20 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npm run *)",
5
+ "Bash(npx tsc *)",
6
+ "Bash(npm audit *)",
7
+ "Bash(npm uninstall *)",
8
+ "Bash(npm install *)",
9
+ "Bash(echo \"=== SOAP-EXPRESS src ===\" && find /Users/rad/git/soapjs/soap-express/src -type f -name \"*.ts\" | grep -v __tests__ | grep -v \".test.\" | sort && echo \"\" && echo \"=== SOAP-EXPRESS package.json ===\" && cat /Users/rad/git/soapjs/soap-express/package.json)",
10
+ "Bash(echo \"=== SOAP src \\(http + common\\) ===\" && find /Users/rad/git/soapjs/soap/src -type f -name \"*.ts\" | grep -v __tests__ | grep -v \".test.\" | grep -E \"\\(http|common|config\\)\" | sort)",
11
+ "Bash(cat /Users/rad/git/soapjs/soap/package.json | grep '\"version\"' | head -1)",
12
+ "Bash(grep -rln \"AuthStrategy\\\\|\\\\.configure\\(\\\\|\\\\.middleware\\(\\\\|serializeUser\\\\|AuthConfig\\\\b\" src --include=\"*.test.ts\")",
13
+ "Bash(grep -rln \"AuthStrategy\\\\|AuthConfig\" src/**/__tests__)",
14
+ "Bash(npm pack *)",
15
+ "Read(//Users/rad/git/soapjs/**)",
16
+ "Bash(npm view *)",
17
+ "Bash(grep -v \"^$\")"
18
+ ]
19
+ }
20
+ }
package/build/errors.d.ts CHANGED
@@ -20,7 +20,7 @@ export declare class UserNotFoundError extends Error {
20
20
  constructor();
21
21
  }
22
22
  export declare class InvalidCredentialsError extends Error {
23
- constructor();
23
+ constructor(message?: string);
24
24
  }
25
25
  export declare class MissingTokenError extends Error {
26
26
  readonly tokenType: "Access" | "Refresh";
package/build/errors.js CHANGED
@@ -50,8 +50,8 @@ class UserNotFoundError extends Error {
50
50
  }
51
51
  exports.UserNotFoundError = UserNotFoundError;
52
52
  class InvalidCredentialsError extends Error {
53
- constructor() {
54
- super("Invalid credentials: Authentication failed.");
53
+ constructor(message) {
54
+ super(`Invalid credentials: ${message || 'Authentication failed.'}`);
55
55
  this.name = "InvalidCredentialsError";
56
56
  }
57
57
  }
package/build/index.d.ts CHANGED
@@ -5,3 +5,4 @@ export * from "./tools";
5
5
  export * from "./errors";
6
6
  export * from "./types";
7
7
  export * from "./soap-auth";
8
+ export * from "./utils/validation";
package/build/index.js CHANGED
@@ -21,3 +21,4 @@ __exportStar(require("./tools"), exports);
21
21
  __exportStar(require("./errors"), exports);
22
22
  __exportStar(require("./types"), exports);
23
23
  __exportStar(require("./soap-auth"), exports);
24
+ __exportStar(require("./utils/validation"), exports);
@@ -2,8 +2,8 @@ import * as Soap from "@soapjs/soap";
2
2
  import { AuthThrottleConfig } from "../types";
3
3
  export declare class AuthThrottleService {
4
4
  private config;
5
- private logger;
6
- constructor(config: AuthThrottleConfig, logger: Soap.Logger);
5
+ private logger?;
6
+ constructor(config: AuthThrottleConfig, logger?: Soap.Logger);
7
7
  checkFailedAttempts(identifier: string): Promise<void>;
8
8
  incrementFailedAttempts(account: any): Promise<void>;
9
9
  resetFailedAttempts(account: any): Promise<void>;
@@ -17,11 +17,11 @@ class AuthThrottleService {
17
17
  (await this.config.getFailedAttempts?.(identifier)) || 0;
18
18
  }
19
19
  catch (e) {
20
- this.logger.error("Check failed attempts:", e);
20
+ this.logger?.error("Check failed attempts:", e);
21
21
  }
22
22
  if (Number.isInteger(failedAttempts) &&
23
23
  failedAttempts >= this.config.maxFailedAttempts) {
24
- this.logger.warn(`User ${identifier} is temporarily locked out.`);
24
+ this.logger?.warn(`User ${identifier} is temporarily locked out.`);
25
25
  throw new errors_1.AccountLockedError();
26
26
  }
27
27
  }
@@ -6,3 +6,4 @@ export * from "./password.service";
6
6
  export * from "./pkce.service";
7
7
  export * from "./rate-limit.service";
8
8
  export * from "./role.service";
9
+ export * from "./totp.service";
@@ -22,3 +22,4 @@ __exportStar(require("./password.service"), exports);
22
22
  __exportStar(require("./pkce.service"), exports);
23
23
  __exportStar(require("./rate-limit.service"), exports);
24
24
  __exportStar(require("./role.service"), exports);
25
+ __exportStar(require("./totp.service"), exports);
@@ -1,14 +1,16 @@
1
1
  import * as Soap from "@soapjs/soap";
2
- import { PasswordPolicyConfig } from "../types";
2
+ import { NewPasswordOptions, PasswordInfo, PasswordPolicyConfig } from "../types";
3
3
  export declare class PasswordService {
4
4
  private config;
5
5
  private logger;
6
6
  constructor(config: PasswordPolicyConfig, logger: Soap.Logger);
7
- validatePassword(password: string): Promise<boolean>;
8
- getLastPasswordChange(identifier: string): Promise<Date>;
7
+ private validateConfig;
8
+ validatePassword(password: string, previousPassword?: string): Promise<void>;
9
+ getPasswordPasswordInfo(identifier: string): Promise<PasswordInfo>;
9
10
  generateResetToken(identifier: string): Promise<string>;
10
11
  sendResetEmail(identifier: string, token: string): Promise<void>;
11
- validateResetToken(token: string): Promise<boolean>;
12
- updatePassword(identifier: string, newPassword: string): Promise<void>;
12
+ validateResetToken(token: string): Promise<void>;
13
+ updatePassword(identifier: string, newPassword: string, passwordOptions?: NewPasswordOptions): Promise<void>;
13
14
  isPasswordChangeRequired(identifier: string): Promise<boolean>;
15
+ generatePassword(identifier: string, options: NewPasswordOptions): Promise<string>;
14
16
  }
@@ -22,57 +22,115 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
25
28
  Object.defineProperty(exports, "__esModule", { value: true });
26
29
  exports.PasswordService = void 0;
27
30
  const Soap = __importStar(require("@soapjs/soap"));
31
+ const bcrypt_1 = __importDefault(require("bcrypt"));
32
+ const crypto_1 = __importDefault(require("crypto"));
33
+ const validation_1 = require("../utils/validation");
34
+ const errors_1 = require("../errors");
28
35
  class PasswordService {
29
36
  config;
30
37
  logger;
31
38
  constructor(config, logger) {
32
39
  this.config = config;
33
40
  this.logger = logger;
41
+ this.validateConfig(config);
34
42
  }
35
- async validatePassword(password) {
36
- return this.config.validatePassword?.(password);
43
+ validateConfig(config) {
44
+ try {
45
+ validation_1.ValidationUtils.required(config, "config");
46
+ validation_1.ValidationUtils.object(config, "config");
47
+ }
48
+ catch (error) {
49
+ if (error instanceof validation_1.ValidationError) {
50
+ throw error;
51
+ }
52
+ throw new validation_1.ValidationError(`Invalid PasswordService configuration: ${error.message}`);
53
+ }
37
54
  }
38
- async getLastPasswordChange(identifier) {
39
- return this.config.getLastPasswordChange?.(identifier);
55
+ async validatePassword(password, previousPassword) {
56
+ validation_1.ValidationUtils.nonEmptyString(password, "password");
57
+ if (previousPassword !== undefined) {
58
+ validation_1.ValidationUtils.nonEmptyString(previousPassword, "previousPassword");
59
+ }
60
+ return this.config.validatePassword?.(password, previousPassword);
61
+ }
62
+ async getPasswordPasswordInfo(identifier) {
63
+ validation_1.ValidationUtils.nonEmptyString(identifier, "identifier");
64
+ return this.config.getPasswordPasswordInfo?.(identifier);
40
65
  }
41
66
  async generateResetToken(identifier) {
67
+ validation_1.ValidationUtils.nonEmptyString(identifier, "identifier");
42
68
  if (!this.config?.generateResetToken) {
43
69
  throw new Soap.NotImplementedError("generateResetToken");
44
70
  }
45
71
  return this.config.generateResetToken?.(identifier);
46
72
  }
47
73
  async sendResetEmail(identifier, token) {
48
- if (!this.config?.sendResetEmail) {
74
+ validation_1.ValidationUtils.nonEmptyString(identifier, "identifier");
75
+ validation_1.ValidationUtils.nonEmptyString(token, "token");
76
+ if (!this.config?.sendPasswordResetEmail) {
49
77
  throw new Soap.NotImplementedError("sendResetEmail");
50
78
  }
51
- return this.config.sendResetEmail?.(identifier, token);
79
+ return this.config.sendPasswordResetEmail?.(identifier, token);
52
80
  }
53
81
  async validateResetToken(token) {
54
- if (!this.config?.validateResetToken) {
82
+ validation_1.ValidationUtils.nonEmptyString(token, "token");
83
+ if (!this.config?.validatePasswordResetToken) {
55
84
  throw new Soap.NotImplementedError("validateResetToken");
56
85
  }
57
- return this.config.validateResetToken?.(token);
86
+ const isValid = await this.config.validatePasswordResetToken(token);
87
+ if (isValid === false) {
88
+ throw new errors_1.ExpiredResetTokenError();
89
+ }
58
90
  }
59
- async updatePassword(identifier, newPassword) {
91
+ async updatePassword(identifier, newPassword, passwordOptions) {
92
+ validation_1.ValidationUtils.nonEmptyString(identifier, "identifier");
93
+ validation_1.ValidationUtils.nonEmptyString(newPassword, "newPassword");
94
+ if (passwordOptions) {
95
+ validation_1.ValidationUtils.object(passwordOptions, "passwordOptions");
96
+ if (passwordOptions.type) {
97
+ validation_1.ValidationUtils.oneOf(passwordOptions.type, "passwordOptions.type", ["default", "one-time", "temporary"]);
98
+ }
99
+ }
60
100
  if (!this.config?.updatePassword) {
61
101
  throw new Soap.NotImplementedError("updatePassword");
62
102
  }
63
- return this.config.updatePassword?.(identifier, newPassword);
103
+ return this.config.updatePassword?.(identifier, newPassword, passwordOptions);
64
104
  }
65
105
  async isPasswordChangeRequired(identifier) {
66
- if (this.config.passwordExpirationDays) {
67
- if (!this.config.getLastPasswordChange) {
68
- throw new Soap.NotImplementedError("getLastPasswordChange");
69
- }
70
- const lastChanged = await this.config.getLastPasswordChange(identifier);
71
- return (lastChanged &&
72
- Date.now() - Number(lastChanged) >
73
- this.config.passwordExpirationDays * 86400000);
106
+ validation_1.ValidationUtils.nonEmptyString(identifier, "identifier");
107
+ const passwordInfo = await this.config.getPasswordPasswordInfo?.(identifier);
108
+ if (passwordInfo &&
109
+ (passwordInfo.type === "one-time" ||
110
+ (passwordInfo.type === "temporary" &&
111
+ Number.isInteger(passwordInfo.expiresIn) &&
112
+ Date.now() - passwordInfo.lastChangeDate.getTime() >
113
+ passwordInfo.expiresIn))) {
114
+ return true;
74
115
  }
75
116
  return false;
76
117
  }
118
+ async generatePassword(identifier, options) {
119
+ validation_1.ValidationUtils.nonEmptyString(identifier, "identifier");
120
+ validation_1.ValidationUtils.required(options, "options");
121
+ validation_1.ValidationUtils.object(options, "options");
122
+ validation_1.ValidationUtils.oneOf(options.type, "options.type", ["default", "one-time", "temporary"]);
123
+ let plaintext;
124
+ if (this.config.generatePassword) {
125
+ plaintext = await this.config.generatePassword(identifier, options);
126
+ }
127
+ else {
128
+ plaintext = crypto_1.default.randomBytes(12).toString("base64url");
129
+ }
130
+ const salt = await bcrypt_1.default.genSalt(10);
131
+ const hashedPassword = await bcrypt_1.default.hash(plaintext, salt);
132
+ await this.updatePassword(identifier, hashedPassword, options);
133
+ return plaintext;
134
+ }
77
135
  }
78
136
  exports.PasswordService = PasswordService;
@@ -0,0 +1,16 @@
1
+ export interface TotpOptions {
2
+ step?: number;
3
+ digits?: number;
4
+ window?: number;
5
+ }
6
+ export declare class TotpService {
7
+ private readonly step;
8
+ private readonly digits;
9
+ private readonly window;
10
+ constructor(options?: TotpOptions);
11
+ generateSecret(byteLength?: number): string;
12
+ generateOTP(secret: string, timestamp?: number): string;
13
+ verifyOTP(secret: string, code: string, timestamp?: number): boolean;
14
+ generateQRUri(secret: string, issuer: string, account: string): string;
15
+ generateBackupCodes(count?: number): string[];
16
+ }
@@ -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;
@@ -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 extends AuthStrategy>(name: string, type: AuthCategories): T;
12
- getHttpStrategy<T extends AuthStrategy>(name: string): T;
13
- getSocketStrategy<T extends AuthStrategy>(name: string): T;
14
- getEventStrategy<T extends AuthStrategy>(name: string): T;
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
  }