mvc-common-toolkit 1.43.10 → 1.44.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 (210) hide show
  1. package/dist/src/constants.d.ts +59 -0
  2. package/dist/src/constants.js +69 -0
  3. package/dist/src/constants.js.map +1 -0
  4. package/dist/src/gateways/alibaba-cloud-gateway.d.ts +30 -0
  5. package/dist/src/gateways/alibaba-cloud-gateway.js +120 -0
  6. package/dist/src/gateways/alibaba-cloud-gateway.js.map +1 -0
  7. package/dist/src/gateways/http-audit-gateway.d.ts +20 -0
  8. package/dist/src/gateways/http-audit-gateway.js +76 -0
  9. package/dist/src/gateways/http-audit-gateway.js.map +1 -0
  10. package/dist/src/gateways/index.d.ts +5 -0
  11. package/dist/src/gateways/index.js +22 -0
  12. package/dist/src/gateways/index.js.map +1 -0
  13. package/dist/src/gateways/internal-auth-gateway.d.ts +8 -0
  14. package/dist/src/gateways/internal-auth-gateway.js +40 -0
  15. package/dist/src/gateways/internal-auth-gateway.js.map +1 -0
  16. package/dist/src/gateways/stdout-audit-gateway.d.ts +7 -0
  17. package/dist/src/gateways/stdout-audit-gateway.js +25 -0
  18. package/dist/src/gateways/stdout-audit-gateway.js.map +1 -0
  19. package/dist/src/gateways/webhook-audit-gateway.d.ts +14 -0
  20. package/dist/src/gateways/webhook-audit-gateway.js +27 -0
  21. package/dist/src/gateways/webhook-audit-gateway.js.map +1 -0
  22. package/dist/src/interfaces.d.ts +218 -0
  23. package/dist/src/interfaces.js +3 -0
  24. package/dist/src/interfaces.js.map +1 -0
  25. package/dist/src/models/audit-log.d.ts +77 -0
  26. package/dist/src/models/audit-log.js +92 -0
  27. package/dist/src/models/audit-log.js.map +1 -0
  28. package/dist/src/models/index.d.ts +1 -0
  29. package/dist/src/models/index.js +18 -0
  30. package/dist/src/models/index.js.map +1 -0
  31. package/dist/src/pkg/array-helper.d.ts +1 -0
  32. package/dist/src/pkg/array-helper.js +12 -0
  33. package/dist/src/pkg/array-helper.js.map +1 -0
  34. package/dist/src/pkg/bcrypt-helper.d.ts +2 -0
  35. package/dist/src/pkg/bcrypt-helper.js +36 -0
  36. package/dist/src/pkg/bcrypt-helper.js.map +1 -0
  37. package/dist/src/pkg/crypto-helper.d.ts +2 -0
  38. package/dist/src/pkg/crypto-helper.js +16 -0
  39. package/dist/src/pkg/crypto-helper.js.map +1 -0
  40. package/dist/src/pkg/encryption-helper.d.ts +18 -0
  41. package/dist/src/pkg/encryption-helper.js +89 -0
  42. package/dist/src/pkg/encryption-helper.js.map +1 -0
  43. package/dist/src/pkg/encryption-helper.spec.d.ts +1 -0
  44. package/dist/src/pkg/encryption-helper.spec.js +238 -0
  45. package/dist/src/pkg/encryption-helper.spec.js.map +1 -0
  46. package/dist/src/pkg/filter-helper.d.ts +2 -0
  47. package/dist/src/pkg/filter-helper.js +102 -0
  48. package/dist/src/pkg/filter-helper.js.map +1 -0
  49. package/dist/src/pkg/filter-helper.spec.d.ts +1 -0
  50. package/dist/src/pkg/filter-helper.spec.js +94 -0
  51. package/dist/src/pkg/filter-helper.spec.js.map +1 -0
  52. package/dist/src/pkg/geoip-helper.d.ts +2 -0
  53. package/dist/src/pkg/geoip-helper.js +32 -0
  54. package/dist/src/pkg/geoip-helper.js.map +1 -0
  55. package/dist/src/pkg/hash-helper.d.ts +1 -0
  56. package/dist/src/pkg/hash-helper.js +37 -0
  57. package/dist/src/pkg/hash-helper.js.map +1 -0
  58. package/dist/src/pkg/http-request-utils.d.ts +4 -0
  59. package/dist/src/pkg/http-request-utils.js +55 -0
  60. package/dist/src/pkg/http-request-utils.js.map +1 -0
  61. package/dist/src/pkg/index.d.ts +19 -0
  62. package/dist/src/pkg/index.js +46 -0
  63. package/dist/src/pkg/index.js.map +1 -0
  64. package/dist/src/pkg/key-helper.d.ts +2 -0
  65. package/dist/src/pkg/key-helper.js +20 -0
  66. package/dist/src/pkg/key-helper.js.map +1 -0
  67. package/dist/src/pkg/logger.d.ts +9 -0
  68. package/dist/src/pkg/logger.js +23 -0
  69. package/dist/src/pkg/logger.js.map +1 -0
  70. package/dist/src/pkg/object-helper.d.ts +2 -0
  71. package/dist/src/pkg/object-helper.js +37 -0
  72. package/dist/src/pkg/object-helper.js.map +1 -0
  73. package/dist/src/pkg/paginated-cache-registry.d.ts +8 -0
  74. package/dist/src/pkg/paginated-cache-registry.js +23 -0
  75. package/dist/src/pkg/paginated-cache-registry.js.map +1 -0
  76. package/dist/src/pkg/query-helper.d.ts +3 -0
  77. package/dist/src/pkg/query-helper.js +60 -0
  78. package/dist/src/pkg/query-helper.js.map +1 -0
  79. package/dist/src/pkg/referral-tree-utils.d.ts +33 -0
  80. package/dist/src/pkg/referral-tree-utils.js +71 -0
  81. package/dist/src/pkg/referral-tree-utils.js.map +1 -0
  82. package/dist/src/pkg/scripts/index.d.ts +1 -0
  83. package/dist/src/pkg/scripts/index.js +28 -0
  84. package/dist/src/pkg/scripts/index.js.map +1 -0
  85. package/dist/src/pkg/scripts/lua.d.ts +10 -0
  86. package/dist/src/pkg/scripts/lua.js +109 -0
  87. package/dist/src/pkg/scripts/lua.js.map +1 -0
  88. package/dist/src/pkg/sort-helper.d.ts +3 -0
  89. package/dist/src/pkg/sort-helper.js +18 -0
  90. package/dist/src/pkg/sort-helper.js.map +1 -0
  91. package/dist/src/pkg/string-utils.d.ts +10 -0
  92. package/dist/src/pkg/string-utils.js +79 -0
  93. package/dist/src/pkg/string-utils.js.map +1 -0
  94. package/dist/src/pkg/task-helper.d.ts +2 -0
  95. package/dist/src/pkg/task-helper.js +30 -0
  96. package/dist/src/pkg/task-helper.js.map +1 -0
  97. package/dist/src/pkg/trading-pair-helper.d.ts +9 -0
  98. package/dist/src/pkg/trading-pair-helper.js +44 -0
  99. package/dist/src/pkg/trading-pair-helper.js.map +1 -0
  100. package/dist/src/pkg/trading-pair-helper.spec.d.ts +1 -0
  101. package/dist/src/pkg/trading-pair-helper.spec.js +132 -0
  102. package/dist/src/pkg/trading-pair-helper.spec.js.map +1 -0
  103. package/dist/src/pkg/workflow/delayed-task-registry.d.ts +10 -0
  104. package/dist/src/pkg/workflow/delayed-task-registry.js +67 -0
  105. package/dist/src/pkg/workflow/delayed-task-registry.js.map +1 -0
  106. package/dist/src/pkg/workflow/delayed-task.d.ts +18 -0
  107. package/dist/src/pkg/workflow/delayed-task.js +95 -0
  108. package/dist/src/pkg/workflow/delayed-task.js.map +1 -0
  109. package/dist/src/pkg/workflow/index.d.ts +5 -0
  110. package/dist/src/pkg/workflow/index.js +22 -0
  111. package/dist/src/pkg/workflow/index.js.map +1 -0
  112. package/dist/src/pkg/workflow/processing-milestone.d.ts +18 -0
  113. package/dist/src/pkg/workflow/processing-milestone.js +39 -0
  114. package/dist/src/pkg/workflow/processing-milestone.js.map +1 -0
  115. package/dist/src/pkg/workflow/retry-task.d.ts +24 -0
  116. package/dist/src/pkg/workflow/retry-task.js +89 -0
  117. package/dist/src/pkg/workflow/retry-task.js.map +1 -0
  118. package/dist/src/pkg/workflow/retry-task.spec.d.ts +1 -0
  119. package/dist/src/pkg/workflow/retry-task.spec.js +145 -0
  120. package/dist/src/pkg/workflow/retry-task.spec.js.map +1 -0
  121. package/dist/src/pkg/workflow/sync-taskqueue.d.ts +32 -0
  122. package/dist/src/pkg/workflow/sync-taskqueue.js +108 -0
  123. package/dist/src/pkg/workflow/sync-taskqueue.js.map +1 -0
  124. package/dist/src/pkg/worksheet.utils.d.ts +27 -0
  125. package/dist/src/pkg/worksheet.utils.js +116 -0
  126. package/dist/src/pkg/worksheet.utils.js.map +1 -0
  127. package/dist/src/services/audit-service.d.ts +7 -0
  128. package/dist/src/services/audit-service.js +32 -0
  129. package/dist/src/services/audit-service.js.map +1 -0
  130. package/dist/src/services/excel.service.d.ts +25 -0
  131. package/dist/src/services/excel.service.js +95 -0
  132. package/dist/src/services/excel.service.js.map +1 -0
  133. package/dist/src/services/http-service.d.ts +7 -0
  134. package/dist/src/services/http-service.js +67 -0
  135. package/dist/src/services/http-service.js.map +1 -0
  136. package/dist/src/services/index.d.ts +8 -0
  137. package/dist/src/services/index.js +25 -0
  138. package/dist/src/services/index.js.map +1 -0
  139. package/dist/src/services/kafka-service.d.ts +15 -0
  140. package/dist/src/services/kafka-service.js +68 -0
  141. package/dist/src/services/kafka-service.js.map +1 -0
  142. package/dist/src/services/mailer-service.d.ts +15 -0
  143. package/dist/src/services/mailer-service.js +44 -0
  144. package/dist/src/services/mailer-service.js.map +1 -0
  145. package/dist/src/services/paginated-cache.d.ts +16 -0
  146. package/dist/src/services/paginated-cache.js +115 -0
  147. package/dist/src/services/paginated-cache.js.map +1 -0
  148. package/dist/src/services/paginated-cache.spec.d.ts +1 -0
  149. package/dist/src/services/paginated-cache.spec.js +284 -0
  150. package/dist/src/services/paginated-cache.spec.js.map +1 -0
  151. package/dist/src/services/redis-service.d.ts +33 -0
  152. package/dist/src/services/redis-service.js +230 -0
  153. package/dist/src/services/redis-service.js.map +1 -0
  154. package/dist/src/services/security-service.d.ts +11 -0
  155. package/dist/src/services/security-service.js +68 -0
  156. package/dist/src/services/security-service.js.map +1 -0
  157. package/dist/tsconfig.tsbuildinfo +1 -1
  158. package/package.json +1 -1
  159. package/src/constants.ts +66 -0
  160. package/src/gateways/alibaba-cloud-gateway.ts +127 -0
  161. package/src/gateways/http-audit-gateway.ts +104 -0
  162. package/src/gateways/index.ts +5 -0
  163. package/src/gateways/internal-auth-gateway.ts +42 -0
  164. package/src/gateways/stdout-audit-gateway.ts +23 -0
  165. package/src/gateways/webhook-audit-gateway.ts +33 -0
  166. package/src/interfaces.ts +304 -0
  167. package/src/models/audit-log.ts +126 -0
  168. package/src/models/index.ts +1 -0
  169. package/src/pkg/array-helper.ts +7 -0
  170. package/src/pkg/bcrypt-helper.ts +9 -0
  171. package/src/pkg/crypto-helper.ts +18 -0
  172. package/src/pkg/encryption-helper.spec.ts +423 -0
  173. package/src/pkg/encryption-helper.ts +155 -0
  174. package/src/pkg/filter-helper.spec.ts +105 -0
  175. package/src/pkg/filter-helper.ts +139 -0
  176. package/src/pkg/geoip-helper.ts +5 -0
  177. package/src/pkg/hash-helper.ts +12 -0
  178. package/src/pkg/http-request-utils.ts +75 -0
  179. package/src/pkg/index.ts +19 -0
  180. package/src/pkg/key-helper.ts +20 -0
  181. package/src/pkg/logger.ts +23 -0
  182. package/src/pkg/object-helper.ts +42 -0
  183. package/src/pkg/paginated-cache-registry.ts +25 -0
  184. package/src/pkg/query-helper.ts +79 -0
  185. package/src/pkg/referral-tree-utils.ts +165 -0
  186. package/src/pkg/scripts/index.ts +1 -0
  187. package/src/pkg/scripts/lua.ts +112 -0
  188. package/src/pkg/sort-helper.ts +19 -0
  189. package/src/pkg/string-utils.ts +104 -0
  190. package/src/pkg/task-helper.ts +25 -0
  191. package/src/pkg/trading-pair-helper.spec.ts +146 -0
  192. package/src/pkg/trading-pair-helper.ts +78 -0
  193. package/src/pkg/workflow/delayed-task-registry.ts +54 -0
  194. package/src/pkg/workflow/delayed-task.ts +106 -0
  195. package/src/pkg/workflow/index.ts +5 -0
  196. package/src/pkg/workflow/processing-milestone.ts +54 -0
  197. package/src/pkg/workflow/retry-task.spec.ts +194 -0
  198. package/src/pkg/workflow/retry-task.ts +119 -0
  199. package/src/pkg/workflow/sync-taskqueue.ts +118 -0
  200. package/src/pkg/worksheet.utils.ts +178 -0
  201. package/src/services/audit-service.ts +22 -0
  202. package/src/services/excel.service.ts +103 -0
  203. package/src/services/http-service.ts +71 -0
  204. package/src/services/index.ts +8 -0
  205. package/src/services/kafka-service.ts +81 -0
  206. package/src/services/mailer-service.ts +43 -0
  207. package/src/services/paginated-cache.spec.ts +519 -0
  208. package/src/services/paginated-cache.ts +122 -0
  209. package/src/services/redis-service.ts +238 -0
  210. package/src/services/security-service.ts +80 -0
@@ -0,0 +1,126 @@
1
+ import { LOG_LEVEL } from "../constants";
2
+
3
+ export type LogObject = ErrorLog | InfoLog | DebugLog;
4
+
5
+ export interface LogObjectData {
6
+ logId: string;
7
+ userId?: string;
8
+ level: LOG_LEVEL;
9
+ action: string;
10
+ message?: any;
11
+ payload?: any;
12
+ metadata?: any;
13
+ }
14
+
15
+ export abstract class BaseLog {
16
+ public logId: string;
17
+ public userId: string;
18
+ public level: LOG_LEVEL;
19
+ public action: string;
20
+ public message?: any;
21
+ public payload?: any;
22
+ public metadata?: any;
23
+
24
+ constructor(data: Omit<LogObjectData, "level">) {
25
+ this.logId = data.logId;
26
+ this.userId = data.userId;
27
+ this.action = data.action;
28
+ this.message = data.message;
29
+ this.metadata = data.metadata;
30
+ this.payload = data.payload;
31
+ }
32
+
33
+ public abstract toJSON(): Record<string, any>;
34
+ }
35
+
36
+ export class ErrorLog extends BaseLog {
37
+ constructor(data: Omit<LogObjectData, "level">) {
38
+ super(data);
39
+
40
+ this.level = LOG_LEVEL.ERROR;
41
+ }
42
+
43
+ public toJSON() {
44
+ return {
45
+ logId: this.logId,
46
+ userId: this.userId,
47
+ level: this.level,
48
+ action: this.action,
49
+ message: this.message,
50
+ metadata: this.metadata,
51
+ payload: this.payload,
52
+ };
53
+ }
54
+ }
55
+
56
+ export class FatalLog extends BaseLog {
57
+ constructor(data: Omit<LogObjectData, "level">) {
58
+ super(data);
59
+
60
+ this.level = LOG_LEVEL.FATAL;
61
+ }
62
+
63
+ public toJSON() {
64
+ return {
65
+ logId: this.logId,
66
+ userId: this.userId,
67
+ level: this.level,
68
+ action: this.action,
69
+ message: this.message,
70
+ metadata: this.metadata,
71
+ payload: this.payload,
72
+ };
73
+ }
74
+ }
75
+
76
+ export class InfoLog extends BaseLog {
77
+ constructor(data: Omit<LogObjectData, "level">) {
78
+ super(data);
79
+
80
+ this.level = LOG_LEVEL.INFO;
81
+ }
82
+
83
+ public toJSON() {
84
+ return {
85
+ logId: this.logId,
86
+ userId: this.userId,
87
+ level: this.level,
88
+ action: this.action,
89
+ message: this.message,
90
+ metadata: this.metadata,
91
+ payload: this.payload,
92
+ };
93
+ }
94
+ }
95
+
96
+ export class DebugLog extends BaseLog {
97
+ parentLogId?: string;
98
+ parentLogType?: LOG_LEVEL;
99
+
100
+ constructor(
101
+ data: Omit<LogObjectData, "level"> & {
102
+ parentLogId?: string;
103
+ parentLogType?: LOG_LEVEL;
104
+ }
105
+ ) {
106
+ super(data);
107
+
108
+ this.level = LOG_LEVEL.DEBUG;
109
+ this.parentLogId = data.parentLogId;
110
+ this.parentLogType = data.parentLogType;
111
+ }
112
+
113
+ public toJSON() {
114
+ return {
115
+ logId: this.logId,
116
+ userId: this.userId,
117
+ level: this.level,
118
+ action: this.action,
119
+ message: this.message,
120
+ metadata: this.metadata,
121
+ payload: this.payload,
122
+ parentLogId: this.parentLogId,
123
+ parentLogType: this.parentLogType,
124
+ };
125
+ }
126
+ }
@@ -0,0 +1 @@
1
+ export * from "./audit-log";
@@ -0,0 +1,7 @@
1
+ export function shuffle<T>(array: T[]): T[] {
2
+ for (let i = array.length - 1; i > 0; i--) {
3
+ const j = Math.floor(Math.random() * (i + 1));
4
+ [array[i], array[j]] = [array[j], array[i]];
5
+ }
6
+ return array;
7
+ }
@@ -0,0 +1,9 @@
1
+ import * as bcrypt from "bcrypt";
2
+
3
+ export function hash(data: string, salt?: string | number): Promise<string> {
4
+ return bcrypt.hash(data, salt || 12);
5
+ }
6
+
7
+ export function compare(raw: string, hashed: string): Promise<boolean> {
8
+ return bcrypt.compare(raw, hashed);
9
+ }
@@ -0,0 +1,18 @@
1
+ import { createHash } from "crypto";
2
+
3
+ export const sha512Encrypt = (data: string, privateKey: string) => {
4
+ const sha512Hasher = createHash("sha512");
5
+ const finalData = `${data}_${privateKey}`;
6
+
7
+ return sha512Hasher.update(finalData).digest("hex");
8
+ };
9
+
10
+ export const sha512Verify = (
11
+ hashedToVerify: string,
12
+ data: string,
13
+ privateKey: string
14
+ ): boolean => {
15
+ const hashed = sha512Encrypt(data, privateKey);
16
+
17
+ return hashedToVerify === hashed;
18
+ };
@@ -0,0 +1,423 @@
1
+ import { expect } from "chai";
2
+ import {
3
+ encrypt,
4
+ decrypt,
5
+ encryptWithTwoFactors,
6
+ decryptWithTwoFactors,
7
+ } from "./encryption-helper";
8
+
9
+ describe("encryption helper", () => {
10
+ describe("single factor encryption", () => {
11
+ it("should encrypt and decrypt text correctly", () => {
12
+ const plaintext = "Hello, World!";
13
+ const password = "my-secret-password";
14
+
15
+ const encrypted = encrypt(plaintext, password);
16
+ const decrypted = decrypt(encrypted, password);
17
+
18
+ expect(decrypted).to.equal(plaintext);
19
+ });
20
+
21
+ it("should handle empty string", () => {
22
+ const plaintext = "";
23
+ const password = "my-secret-password";
24
+
25
+ const encrypted = encrypt(plaintext, password);
26
+ const decrypted = decrypt(encrypted, password);
27
+
28
+ expect(decrypted).to.equal(plaintext);
29
+ });
30
+
31
+ it("should handle special characters and unicode", () => {
32
+ const plaintext = "Hello 世界! 🚀 测试";
33
+ const password = "my-secret-password";
34
+
35
+ const encrypted = encrypt(plaintext, password);
36
+ const decrypted = decrypt(encrypted, password);
37
+
38
+ expect(decrypted).to.equal(plaintext);
39
+ });
40
+
41
+ it("should handle long text", () => {
42
+ const plaintext = "A".repeat(1000);
43
+ const password = "my-secret-password";
44
+
45
+ const encrypted = encrypt(plaintext, password);
46
+ const decrypted = decrypt(encrypted, password);
47
+
48
+ expect(decrypted).to.equal(plaintext);
49
+ });
50
+
51
+ it("should produce different ciphertext for same plaintext with different passwords", () => {
52
+ const plaintext = "Hello, World!";
53
+ const password1 = "password1";
54
+ const password2 = "password2";
55
+
56
+ const encrypted1 = encrypt(plaintext, password1);
57
+ const encrypted2 = encrypt(plaintext, password2);
58
+
59
+ expect(encrypted1.ciphertext).to.not.equal(encrypted2.ciphertext);
60
+ });
61
+
62
+ it("should produce different ciphertext for same plaintext and password (due to random salt/iv)", () => {
63
+ const plaintext = "Hello, World!";
64
+ const password = "my-secret-password";
65
+
66
+ const encrypted1 = encrypt(plaintext, password);
67
+ const encrypted2 = encrypt(plaintext, password);
68
+
69
+ expect(encrypted1.ciphertext).to.not.equal(encrypted2.ciphertext);
70
+ expect(encrypted1.iv).to.not.equal(encrypted2.iv);
71
+ expect(encrypted1.salt).to.not.equal(encrypted2.salt);
72
+ });
73
+
74
+ it("should fail decryption with wrong password", () => {
75
+ const plaintext = "Hello, World!";
76
+ const correctPassword = "correct-password";
77
+ const wrongPassword = "wrong-password";
78
+
79
+ const encrypted = encrypt(plaintext, correctPassword);
80
+
81
+ expect(() => decrypt(encrypted, wrongPassword)).to.throw();
82
+ });
83
+
84
+ it("should fail decryption with corrupted payload", () => {
85
+ const plaintext = "Hello, World!";
86
+ const password = "my-secret-password";
87
+
88
+ const encrypted = encrypt(plaintext, password);
89
+ const corruptedPayload = {
90
+ ...encrypted,
91
+ ciphertext: "corrupted-ciphertext",
92
+ };
93
+
94
+ expect(() => decrypt(corruptedPayload, password)).to.throw();
95
+ });
96
+
97
+ it("should fail decryption with corrupted auth tag", () => {
98
+ const plaintext = "Hello, World!";
99
+ const password = "my-secret-password";
100
+
101
+ const encrypted = encrypt(plaintext, password);
102
+ const corruptedPayload = {
103
+ ...encrypted,
104
+ tag: "corrupted-tag",
105
+ };
106
+
107
+ expect(() => decrypt(corruptedPayload, password)).to.throw();
108
+ });
109
+
110
+ it("should have correct payload structure", () => {
111
+ const plaintext = "Hello, World!";
112
+ const password = "my-secret-password";
113
+
114
+ const encrypted = encrypt(plaintext, password);
115
+
116
+ expect(encrypted).to.have.property("iv");
117
+ expect(encrypted).to.have.property("salt");
118
+ expect(encrypted).to.have.property("ciphertext");
119
+ expect(encrypted).to.have.property("tag");
120
+
121
+ expect(encrypted.iv).to.be.a("string");
122
+ expect(encrypted.salt).to.be.a("string");
123
+ expect(encrypted.ciphertext).to.be.a("string");
124
+ expect(encrypted.tag).to.be.a("string");
125
+
126
+ // Check that hex strings are valid
127
+ expect(encrypted.iv).to.match(/^[0-9a-f]+$/);
128
+ expect(encrypted.salt).to.match(/^[0-9a-f]+$/);
129
+ expect(encrypted.ciphertext).to.match(/^[0-9a-f]+$/);
130
+ expect(encrypted.tag).to.match(/^[0-9a-f]+$/);
131
+ });
132
+ });
133
+
134
+ describe("two factor encryption", () => {
135
+ it("should encrypt and decrypt text correctly with two factors", () => {
136
+ const plaintext = "Hello, World!";
137
+ const userPassword = "user-password";
138
+ const serverSecret = "server-secret";
139
+
140
+ const encrypted = encryptWithTwoFactors(
141
+ plaintext,
142
+ userPassword,
143
+ serverSecret
144
+ );
145
+ const decrypted = decryptWithTwoFactors(
146
+ encrypted,
147
+ userPassword,
148
+ serverSecret
149
+ );
150
+
151
+ expect(decrypted).to.equal(plaintext);
152
+ });
153
+
154
+ it("should handle empty string with two factors", () => {
155
+ const plaintext = "";
156
+ const userPassword = "user-password";
157
+ const serverSecret = "server-secret";
158
+
159
+ const encrypted = encryptWithTwoFactors(
160
+ plaintext,
161
+ userPassword,
162
+ serverSecret
163
+ );
164
+ const decrypted = decryptWithTwoFactors(
165
+ encrypted,
166
+ userPassword,
167
+ serverSecret
168
+ );
169
+
170
+ expect(decrypted).to.equal(plaintext);
171
+ });
172
+
173
+ it("should handle special characters and unicode with two factors", () => {
174
+ const plaintext = "Hello 世界! 🚀 测试";
175
+ const userPassword = "user-password";
176
+ const serverSecret = "server-secret";
177
+
178
+ const encrypted = encryptWithTwoFactors(
179
+ plaintext,
180
+ userPassword,
181
+ serverSecret
182
+ );
183
+ const decrypted = decryptWithTwoFactors(
184
+ encrypted,
185
+ userPassword,
186
+ serverSecret
187
+ );
188
+
189
+ expect(decrypted).to.equal(plaintext);
190
+ });
191
+
192
+ it("should handle long text with two factors", () => {
193
+ const plaintext = "A".repeat(1000);
194
+ const userPassword = "user-password";
195
+ const serverSecret = "server-secret";
196
+
197
+ const encrypted = encryptWithTwoFactors(
198
+ plaintext,
199
+ userPassword,
200
+ serverSecret
201
+ );
202
+ const decrypted = decryptWithTwoFactors(
203
+ encrypted,
204
+ userPassword,
205
+ serverSecret
206
+ );
207
+
208
+ expect(decrypted).to.equal(plaintext);
209
+ });
210
+
211
+ it("should produce different ciphertext for same plaintext with different factors", () => {
212
+ const plaintext = "Hello, World!";
213
+ const userPassword1 = "user1";
214
+ const userPassword2 = "user2";
215
+ const serverSecret = "server-secret";
216
+
217
+ const encrypted1 = encryptWithTwoFactors(
218
+ plaintext,
219
+ userPassword1,
220
+ serverSecret
221
+ );
222
+ const encrypted2 = encryptWithTwoFactors(
223
+ plaintext,
224
+ userPassword2,
225
+ serverSecret
226
+ );
227
+
228
+ expect(encrypted1.ciphertext).to.not.equal(encrypted2.ciphertext);
229
+ });
230
+
231
+ it("should produce different ciphertext for same plaintext and factors (due to random salt/iv)", () => {
232
+ const plaintext = "Hello, World!";
233
+ const userPassword = "user-password";
234
+ const serverSecret = "server-secret";
235
+
236
+ const encrypted1 = encryptWithTwoFactors(
237
+ plaintext,
238
+ userPassword,
239
+ serverSecret
240
+ );
241
+ const encrypted2 = encryptWithTwoFactors(
242
+ plaintext,
243
+ userPassword,
244
+ serverSecret
245
+ );
246
+
247
+ expect(encrypted1.ciphertext).to.not.equal(encrypted2.ciphertext);
248
+ expect(encrypted1.iv).to.not.equal(encrypted2.iv);
249
+ expect(encrypted1.saltUser).to.not.equal(encrypted2.saltUser);
250
+ expect(encrypted1.saltServer).to.not.equal(encrypted2.saltServer);
251
+ });
252
+
253
+ it("should fail decryption with wrong user password", () => {
254
+ const plaintext = "Hello, World!";
255
+ const correctUserPassword = "correct-user-password";
256
+ const wrongUserPassword = "wrong-user-password";
257
+ const serverSecret = "server-secret";
258
+
259
+ const encrypted = encryptWithTwoFactors(
260
+ plaintext,
261
+ correctUserPassword,
262
+ serverSecret
263
+ );
264
+
265
+ expect(() =>
266
+ decryptWithTwoFactors(encrypted, wrongUserPassword, serverSecret)
267
+ ).to.throw();
268
+ });
269
+
270
+ it("should fail decryption with wrong server secret", () => {
271
+ const plaintext = "Hello, World!";
272
+ const userPassword = "user-password";
273
+ const correctServerSecret = "correct-server-secret";
274
+ const wrongServerSecret = "wrong-server-secret";
275
+
276
+ const encrypted = encryptWithTwoFactors(
277
+ plaintext,
278
+ userPassword,
279
+ correctServerSecret
280
+ );
281
+
282
+ expect(() =>
283
+ decryptWithTwoFactors(encrypted, userPassword, wrongServerSecret)
284
+ ).to.throw();
285
+ });
286
+
287
+ it("should fail decryption with corrupted payload", () => {
288
+ const plaintext = "Hello, World!";
289
+ const userPassword = "user-password";
290
+ const serverSecret = "server-secret";
291
+
292
+ const encrypted = encryptWithTwoFactors(
293
+ plaintext,
294
+ userPassword,
295
+ serverSecret
296
+ );
297
+ const corruptedPayload = {
298
+ ...encrypted,
299
+ ciphertext: "corrupted-ciphertext",
300
+ };
301
+
302
+ expect(() =>
303
+ decryptWithTwoFactors(corruptedPayload, userPassword, serverSecret)
304
+ ).to.throw();
305
+ });
306
+
307
+ it("should fail decryption with corrupted auth tag", () => {
308
+ const plaintext = "Hello, World!";
309
+ const userPassword = "user-password";
310
+ const serverSecret = "server-secret";
311
+
312
+ const encrypted = encryptWithTwoFactors(
313
+ plaintext,
314
+ userPassword,
315
+ serverSecret
316
+ );
317
+ const corruptedPayload = {
318
+ ...encrypted,
319
+ tag: "corrupted-tag",
320
+ };
321
+
322
+ expect(() =>
323
+ decryptWithTwoFactors(corruptedPayload, userPassword, serverSecret)
324
+ ).to.throw();
325
+ });
326
+
327
+ it("should have correct payload structure for two factors", () => {
328
+ const plaintext = "Hello, World!";
329
+ const userPassword = "user-password";
330
+ const serverSecret = "server-secret";
331
+
332
+ const encrypted = encryptWithTwoFactors(
333
+ plaintext,
334
+ userPassword,
335
+ serverSecret
336
+ );
337
+
338
+ expect(encrypted).to.have.property("iv");
339
+ expect(encrypted).to.have.property("saltUser");
340
+ expect(encrypted).to.have.property("saltServer");
341
+ expect(encrypted).to.have.property("ciphertext");
342
+ expect(encrypted).to.have.property("tag");
343
+
344
+ expect(encrypted.iv).to.be.a("string");
345
+ expect(encrypted.saltUser).to.be.a("string");
346
+ expect(encrypted.saltServer).to.be.a("string");
347
+ expect(encrypted.ciphertext).to.be.a("string");
348
+ expect(encrypted.tag).to.be.a("string");
349
+
350
+ // Check that hex strings are valid
351
+ expect(encrypted.iv).to.match(/^[0-9a-f]+$/);
352
+ expect(encrypted.saltUser).to.match(/^[0-9a-f]+$/);
353
+ expect(encrypted.saltServer).to.match(/^[0-9a-f]+$/);
354
+ expect(encrypted.ciphertext).to.match(/^[0-9a-f]+$/);
355
+ expect(encrypted.tag).to.match(/^[0-9a-f]+$/);
356
+ });
357
+
358
+ it("should be secure against known plaintext attacks", () => {
359
+ const plaintext = "Hello, World!";
360
+ const userPassword = "user-password";
361
+ const serverSecret = "server-secret";
362
+
363
+ const encrypted1 = encryptWithTwoFactors(
364
+ plaintext,
365
+ userPassword,
366
+ serverSecret
367
+ );
368
+ const encrypted2 = encryptWithTwoFactors(
369
+ plaintext,
370
+ userPassword,
371
+ serverSecret
372
+ );
373
+
374
+ // Even with same plaintext and factors, ciphertext should be different
375
+ expect(encrypted1.ciphertext).to.not.equal(encrypted2.ciphertext);
376
+ expect(encrypted1.iv).to.not.equal(encrypted2.iv);
377
+ });
378
+ });
379
+
380
+ describe("edge cases and error handling", () => {
381
+ it("should handle very long passwords", () => {
382
+ const plaintext = "Hello, World!";
383
+ const longPassword = "A".repeat(1000);
384
+
385
+ const encrypted = encrypt(plaintext, longPassword);
386
+ const decrypted = decrypt(encrypted, longPassword);
387
+
388
+ expect(decrypted).to.equal(plaintext);
389
+ });
390
+
391
+ it("should handle very short passwords", () => {
392
+ const plaintext = "Hello, World!";
393
+ const shortPassword = "a";
394
+
395
+ const encrypted = encrypt(plaintext, shortPassword);
396
+ const decrypted = decrypt(encrypted, shortPassword);
397
+
398
+ expect(decrypted).to.equal(plaintext);
399
+ });
400
+
401
+ it("should handle passwords with special characters", () => {
402
+ const plaintext = "Hello, World!";
403
+ const specialPassword = "!@#$%^&*()_+-=[]{}|;':\",./<>?";
404
+
405
+ const encrypted = encrypt(plaintext, specialPassword);
406
+ const decrypted = decrypt(encrypted, specialPassword);
407
+
408
+ expect(decrypted).to.equal(plaintext);
409
+ });
410
+
411
+ it("should handle binary data as string", () => {
412
+ const plaintext = Buffer.from([0x00, 0x01, 0x02, 0x03, 0x04]).toString(
413
+ "utf8"
414
+ );
415
+ const password = "my-secret-password";
416
+
417
+ const encrypted = encrypt(plaintext, password);
418
+ const decrypted = decrypt(encrypted, password);
419
+
420
+ expect(decrypted).to.equal(plaintext);
421
+ });
422
+ });
423
+ });