n8n-nodes-dominusnode 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +21 -0
  3. package/README.md +99 -0
  4. package/dist/credentials/DominusNodeApi.credentials.d.ts +7 -0
  5. package/dist/credentials/DominusNodeApi.credentials.js +42 -0
  6. package/dist/credentials/DominusNodeApi.credentials.js.map +1 -0
  7. package/dist/index.d.ts +4 -0
  8. package/dist/index.js +12 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/nodes/DominusNodeProxy/DominusNodeProxy.node.d.ts +24 -0
  11. package/dist/nodes/DominusNodeProxy/DominusNodeProxy.node.js +436 -0
  12. package/dist/nodes/DominusNodeProxy/DominusNodeProxy.node.js.map +1 -0
  13. package/dist/nodes/DominusNodeUsage/DominusNodeUsage.node.d.ts +13 -0
  14. package/dist/nodes/DominusNodeUsage/DominusNodeUsage.node.js +105 -0
  15. package/dist/nodes/DominusNodeUsage/DominusNodeUsage.node.js.map +1 -0
  16. package/dist/nodes/DominusNodeWallet/DominusNodeWallet.node.d.ts +33 -0
  17. package/dist/nodes/DominusNodeWallet/DominusNodeWallet.node.js +656 -0
  18. package/dist/nodes/DominusNodeWallet/DominusNodeWallet.node.js.map +1 -0
  19. package/dist/shared/auth.d.ts +74 -0
  20. package/dist/shared/auth.js +264 -0
  21. package/dist/shared/auth.js.map +1 -0
  22. package/dist/shared/constants.d.ts +9 -0
  23. package/dist/shared/constants.js +13 -0
  24. package/dist/shared/constants.js.map +1 -0
  25. package/dist/shared/ssrf.d.ts +42 -0
  26. package/dist/shared/ssrf.js +252 -0
  27. package/dist/shared/ssrf.js.map +1 -0
  28. package/package.json +41 -0
  29. package/src/credentials/DominusNodeApi.credentials.ts +39 -0
  30. package/src/index.ts +4 -0
  31. package/src/nodes/DominusNodeProxy/DominusNodeProxy.node.ts +459 -0
  32. package/src/nodes/DominusNodeUsage/DominusNodeUsage.node.ts +130 -0
  33. package/src/nodes/DominusNodeWallet/DominusNodeWallet.node.ts +898 -0
  34. package/src/shared/auth.ts +272 -0
  35. package/src/shared/constants.ts +11 -0
  36. package/src/shared/ssrf.ts +257 -0
  37. package/tests/DominusNodeProxy.test.ts +281 -0
  38. package/tests/DominusNodeUsage.test.ts +250 -0
  39. package/tests/DominusNodeWallet.test.ts +591 -0
  40. package/tests/ssrf.test.ts +238 -0
  41. package/tsconfig.json +18 -0
  42. package/vitest.config.ts +8 -0
@@ -0,0 +1,238 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { normalizeIpv4, isPrivateIp, validateUrl } from "../src/shared/ssrf";
3
+
4
+ // ===========================================================================
5
+ // normalizeIpv4
6
+ // ===========================================================================
7
+
8
+ describe("normalizeIpv4", () => {
9
+ it("normalizes decimal integer to dotted-decimal", () => {
10
+ expect(normalizeIpv4("2130706433")).toBe("127.0.0.1");
11
+ });
12
+
13
+ it("normalizes hex to dotted-decimal", () => {
14
+ expect(normalizeIpv4("0x7f000001")).toBe("127.0.0.1");
15
+ });
16
+
17
+ it("normalizes octal octets", () => {
18
+ expect(normalizeIpv4("0177.0.0.1")).toBe("127.0.0.1");
19
+ });
20
+
21
+ it("normalizes mixed-radix hex octets", () => {
22
+ expect(normalizeIpv4("0xC0.0xA8.0x01.0x01")).toBe("192.168.1.1");
23
+ });
24
+
25
+ it("returns null for hostnames", () => {
26
+ expect(normalizeIpv4("example.com")).toBeNull();
27
+ });
28
+
29
+ it("handles zero", () => {
30
+ expect(normalizeIpv4("0")).toBe("0.0.0.0");
31
+ });
32
+
33
+ it("handles max uint32", () => {
34
+ expect(normalizeIpv4("4294967295")).toBe("255.255.255.255");
35
+ });
36
+
37
+ it("returns null for out-of-range", () => {
38
+ expect(normalizeIpv4("4294967296")).toBeNull();
39
+ });
40
+ });
41
+
42
+ // ===========================================================================
43
+ // isPrivateIp
44
+ // ===========================================================================
45
+
46
+ describe("isPrivateIp", () => {
47
+ // IPv4 private ranges
48
+ it("detects 127.0.0.1 as private", () => {
49
+ expect(isPrivateIp("127.0.0.1")).toBe(true);
50
+ });
51
+
52
+ it("detects 10.0.0.0 as private", () => {
53
+ expect(isPrivateIp("10.0.0.0")).toBe(true);
54
+ });
55
+
56
+ it("detects 172.16.0.1 as private", () => {
57
+ expect(isPrivateIp("172.16.0.1")).toBe(true);
58
+ });
59
+
60
+ it("allows 172.15.0.1 (not private)", () => {
61
+ expect(isPrivateIp("172.15.0.1")).toBe(false);
62
+ });
63
+
64
+ it("detects 192.168.0.1 as private", () => {
65
+ expect(isPrivateIp("192.168.0.1")).toBe(true);
66
+ });
67
+
68
+ it("detects 169.254.169.254 (link-local/cloud metadata) as private", () => {
69
+ expect(isPrivateIp("169.254.169.254")).toBe(true);
70
+ });
71
+
72
+ it("detects 0.0.0.0 as private", () => {
73
+ expect(isPrivateIp("0.0.0.0")).toBe(true);
74
+ });
75
+
76
+ // CGNAT
77
+ it("detects 100.64.0.1 (CGNAT) as private", () => {
78
+ expect(isPrivateIp("100.64.0.1")).toBe(true);
79
+ });
80
+
81
+ it("detects 100.127.255.255 (CGNAT upper) as private", () => {
82
+ expect(isPrivateIp("100.127.255.255")).toBe(true);
83
+ });
84
+
85
+ it("allows 100.63.255.255 (below CGNAT)", () => {
86
+ expect(isPrivateIp("100.63.255.255")).toBe(false);
87
+ });
88
+
89
+ // Multicast
90
+ it("detects 224.0.0.1 (multicast) as private", () => {
91
+ expect(isPrivateIp("224.0.0.1")).toBe(true);
92
+ });
93
+
94
+ it("detects 255.255.255.255 (broadcast) as private", () => {
95
+ expect(isPrivateIp("255.255.255.255")).toBe(true);
96
+ });
97
+
98
+ // Public IPs
99
+ it("allows 8.8.8.8 (public)", () => {
100
+ expect(isPrivateIp("8.8.8.8")).toBe(false);
101
+ });
102
+
103
+ it("allows 1.1.1.1 (public)", () => {
104
+ expect(isPrivateIp("1.1.1.1")).toBe(false);
105
+ });
106
+
107
+ // IPv6
108
+ it("detects ::1 as private", () => {
109
+ expect(isPrivateIp("::1")).toBe(true);
110
+ });
111
+
112
+ it("detects :: as private", () => {
113
+ expect(isPrivateIp("::")).toBe(true);
114
+ });
115
+
116
+ it("detects fc00::1 as private (ULA)", () => {
117
+ expect(isPrivateIp("fc00::1")).toBe(true);
118
+ });
119
+
120
+ it("detects fe80::1 as private (link-local)", () => {
121
+ expect(isPrivateIp("fe80::1")).toBe(true);
122
+ });
123
+
124
+ // IPv4-mapped IPv6
125
+ it("detects ::ffff:127.0.0.1 as private", () => {
126
+ expect(isPrivateIp("::ffff:127.0.0.1")).toBe(true);
127
+ });
128
+
129
+ it("detects ::ffff:7f00:0001 as private (hex form)", () => {
130
+ expect(isPrivateIp("::ffff:7f00:0001")).toBe(true);
131
+ });
132
+
133
+ // IPv4-compatible IPv6
134
+ it("detects ::127.0.0.1 (IPv4-compatible) as private", () => {
135
+ expect(isPrivateIp("::127.0.0.1")).toBe(true);
136
+ });
137
+
138
+ // Bracketed IPv6
139
+ it("handles [::1] bracketed form", () => {
140
+ expect(isPrivateIp("[::1]")).toBe(true);
141
+ });
142
+
143
+ // Zone ID
144
+ it("strips IPv6 zone ID", () => {
145
+ expect(isPrivateIp("fe80::1%eth0")).toBe(true);
146
+ });
147
+
148
+ // Teredo (2001:0000::/32) — inverted IPv4 in last 32 bits
149
+ it("detects Teredo embedding private IPv4", () => {
150
+ // Teredo inverts bits: to embed 127.0.0.1 (7f.00.00.01), inverted = 80.ff.ff.fe
151
+ // But we check the INVERTED result, so embedding 80ff:fffe should decode to 127.0.0.1
152
+ expect(isPrivateIp("2001:0000:0000:0000:0000:0000:80ff:fffe")).toBe(true);
153
+ });
154
+
155
+ // 6to4 (2002::/16)
156
+ it("detects 6to4 embedding private IPv4 (127.0.0.1)", () => {
157
+ // 127.0.0.1 = 7f00:0001
158
+ expect(isPrivateIp("2002:7f00:0001::1")).toBe(true);
159
+ });
160
+
161
+ it("detects 6to4 embedding 10.0.0.1", () => {
162
+ // 10.0.0.1 = 0a00:0001
163
+ expect(isPrivateIp("2002:0a00:0001::1")).toBe(true);
164
+ });
165
+ });
166
+
167
+ // ===========================================================================
168
+ // validateUrl
169
+ // ===========================================================================
170
+
171
+ describe("validateUrl", () => {
172
+ it("accepts valid https URL", () => {
173
+ const parsed = validateUrl("https://httpbin.org/ip");
174
+ expect(parsed.hostname).toBe("httpbin.org");
175
+ });
176
+
177
+ it("accepts valid http URL", () => {
178
+ const parsed = validateUrl("http://example.com/path");
179
+ expect(parsed.hostname).toBe("example.com");
180
+ });
181
+
182
+ it("rejects invalid URL", () => {
183
+ expect(() => validateUrl("not-a-url")).toThrow(/Invalid URL/);
184
+ });
185
+
186
+ it("rejects file:// protocol", () => {
187
+ expect(() => validateUrl("file:///etc/passwd")).toThrow(/protocols/);
188
+ });
189
+
190
+ it("rejects ftp:// protocol", () => {
191
+ expect(() => validateUrl("ftp://ftp.example.com")).toThrow(/protocols/);
192
+ });
193
+
194
+ it("rejects localhost", () => {
195
+ expect(() => validateUrl("http://localhost/secret")).toThrow(/localhost/);
196
+ });
197
+
198
+ it("rejects 0.0.0.0", () => {
199
+ expect(() => validateUrl("http://0.0.0.0/")).toThrow(/localhost/);
200
+ });
201
+
202
+ it("rejects private IPs", () => {
203
+ expect(() => validateUrl("http://192.168.1.1/admin")).toThrow(/private/i);
204
+ });
205
+
206
+ it("rejects .localhost TLD", () => {
207
+ expect(() => validateUrl("http://evil.localhost/")).toThrow(/localhost/);
208
+ });
209
+
210
+ it("rejects .local hostname", () => {
211
+ expect(() => validateUrl("http://printer.local/")).toThrow(/internal/);
212
+ });
213
+
214
+ it("rejects .internal hostname", () => {
215
+ expect(() => validateUrl("http://db.internal/")).toThrow(/internal/);
216
+ });
217
+
218
+ it("rejects .arpa hostname", () => {
219
+ expect(() => validateUrl("http://1.168.192.in-addr.arpa/")).toThrow(/internal/);
220
+ });
221
+
222
+ it("rejects embedded credentials", () => {
223
+ expect(() => validateUrl("http://user:pass@example.com/")).toThrow(/credentials/);
224
+ });
225
+
226
+ it("rejects cloud metadata endpoint", () => {
227
+ expect(() => validateUrl("http://169.254.169.254/latest/meta-data/")).toThrow(/blocked/i);
228
+ expect(() => validateUrl("http://metadata.google.internal/computeMetadata/v1/")).toThrow(/blocked/i);
229
+ });
230
+
231
+ it("rejects hex-encoded loopback", () => {
232
+ expect(() => validateUrl("http://0x7f000001/")).toThrow(/private/i);
233
+ });
234
+
235
+ it("rejects decimal-encoded loopback", () => {
236
+ expect(() => validateUrl("http://2130706433/")).toThrow(/private/i);
237
+ });
238
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "CommonJS",
5
+ "moduleResolution": "node",
6
+ "declaration": true,
7
+ "outDir": "dist",
8
+ "rootDir": "src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "resolveJsonModule": true,
14
+ "sourceMap": true
15
+ },
16
+ "include": ["src/**/*.ts"],
17
+ "exclude": ["node_modules", "dist", "tests"]
18
+ }
@@ -0,0 +1,8 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ include: ["tests/**/*.test.ts"],
6
+ globals: false,
7
+ },
8
+ });