@volter/world-core 2.0.20 → 2.0.21
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.
- package/dist/inject.cjs +18 -5
- package/dist/network-policy.cjs +4 -2
- package/inject.cjs +18 -5
- package/network-policy.cjs +4 -2
- package/package.json +1 -1
package/dist/inject.cjs
CHANGED
|
@@ -728,8 +728,9 @@ function socketTargetHosts(args, isTls) {
|
|
|
728
728
|
return hosts;
|
|
729
729
|
}
|
|
730
730
|
if (typeof first === 'string' && !/^\d+$/.test(first)) return hosts; // a unix socket path
|
|
731
|
-
hosts.push(typeof second === 'string' ? second : 'localhost');
|
|
732
731
|
const options = typeof second === 'object' && second !== null ? second : typeof third === 'object' && third !== null ? third : null;
|
|
732
|
+
// connect(port, host) names the host; connect(port, { host }) puts it in the options, which Node merges
|
|
733
|
+
hosts.push(typeof second === 'string' ? second : typeof options?.host === 'string' ? options.host : 'localhost');
|
|
733
734
|
if (isTls && options && options.servername) hosts.push(options.servername);
|
|
734
735
|
return hosts;
|
|
735
736
|
}
|
|
@@ -811,7 +812,15 @@ function patchedPromisesLookup(original) {
|
|
|
811
812
|
};
|
|
812
813
|
}
|
|
813
814
|
|
|
814
|
-
|
|
815
|
+
/** The port a net/tls connect names (`connect(port, host)`, `connect({ port, host })`), or undefined. */
|
|
816
|
+
function socketTargetPort(args) {
|
|
817
|
+
const [first] = args;
|
|
818
|
+
const raw = first !== null && typeof first === 'object' ? first.port : first;
|
|
819
|
+
const port = Number(raw);
|
|
820
|
+
return Number.isInteger(port) && port > 0 && port < 65536 ? port : undefined;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
function socketRefusal(hostname, port, isTls) {
|
|
815
824
|
const host = String(hostname || '').toLowerCase();
|
|
816
825
|
if (host === WORLD_ADDRESS[4] || host === WORLD_ADDRESS[6]) {
|
|
817
826
|
return `[twin-inject] refused a socket to ${host}, the address this World's DNS gives the names it routes: `
|
|
@@ -831,8 +840,11 @@ function socketRefusal(hostname) {
|
|
|
831
840
|
return `[twin-inject] refused a raw socket to ${host}, which this world routes to the application (volter-world app-url --host): `
|
|
832
841
|
+ 'the client opened its own connection instead of going through http/https or fetch, so it could not be routed.';
|
|
833
842
|
}
|
|
834
|
-
|
|
835
|
-
|
|
843
|
+
// the destination as an origin, its port and its protocol included: a policy that lists https://host allows TLS to
|
|
844
|
+
// host:443, never another port or a plaintext connection to it
|
|
845
|
+
const authority = `${isIP(host) === 6 ? `[${host}]` : host}${port !== undefined && !(isTls && port === 443) ? `:${port}` : ''}`;
|
|
846
|
+
const url = (() => { try { return new URL(`${isTls ? 'https' : 'http'}://${authority}/`); } catch { return null; } })();
|
|
847
|
+
if (url && shouldBlockUntwinned(url)) return `[twin-inject] blocked untwinned external socket to ${authority}`;
|
|
836
848
|
return null;
|
|
837
849
|
}
|
|
838
850
|
|
|
@@ -844,8 +856,9 @@ function refusedSocket(message) {
|
|
|
844
856
|
|
|
845
857
|
function patchedConnect(originalConnect, isTls) {
|
|
846
858
|
return function patchedSocketConnect(...args) {
|
|
859
|
+
const port = socketTargetPort(args);
|
|
847
860
|
for (const host of socketTargetHosts(args, isTls)) {
|
|
848
|
-
const refusal = socketRefusal(host);
|
|
861
|
+
const refusal = socketRefusal(host, port, isTls);
|
|
849
862
|
if (refusal) return refusedSocket(refusal);
|
|
850
863
|
}
|
|
851
864
|
return originalConnect.apply(this, args);
|
package/dist/network-policy.cjs
CHANGED
|
@@ -66,9 +66,11 @@ function isWorldInternalHost(hostname) {
|
|
|
66
66
|
const v4 = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/.exec(h);
|
|
67
67
|
if (v4) {
|
|
68
68
|
const a = Number(v4[1]); const b = Number(v4[2]);
|
|
69
|
-
|
|
69
|
+
// not link-local 169.254/16: it holds a cloud's instance metadata (169.254.169.254), the box's credentials
|
|
70
|
+
return a === 127 || a === 10 || (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168);
|
|
70
71
|
}
|
|
71
|
-
|
|
72
|
+
// nor fe80::/10, nor a cloud's IPv6 metadata address (fd00:ec2::254)
|
|
73
|
+
return h.includes(':') && (h.startsWith('fc') || h.startsWith('fd')) && h !== 'fd00:ec2::254';
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
/**
|
package/inject.cjs
CHANGED
|
@@ -728,8 +728,9 @@ function socketTargetHosts(args, isTls) {
|
|
|
728
728
|
return hosts;
|
|
729
729
|
}
|
|
730
730
|
if (typeof first === 'string' && !/^\d+$/.test(first)) return hosts; // a unix socket path
|
|
731
|
-
hosts.push(typeof second === 'string' ? second : 'localhost');
|
|
732
731
|
const options = typeof second === 'object' && second !== null ? second : typeof third === 'object' && third !== null ? third : null;
|
|
732
|
+
// connect(port, host) names the host; connect(port, { host }) puts it in the options, which Node merges
|
|
733
|
+
hosts.push(typeof second === 'string' ? second : typeof options?.host === 'string' ? options.host : 'localhost');
|
|
733
734
|
if (isTls && options && options.servername) hosts.push(options.servername);
|
|
734
735
|
return hosts;
|
|
735
736
|
}
|
|
@@ -811,7 +812,15 @@ function patchedPromisesLookup(original) {
|
|
|
811
812
|
};
|
|
812
813
|
}
|
|
813
814
|
|
|
814
|
-
|
|
815
|
+
/** The port a net/tls connect names (`connect(port, host)`, `connect({ port, host })`), or undefined. */
|
|
816
|
+
function socketTargetPort(args) {
|
|
817
|
+
const [first] = args;
|
|
818
|
+
const raw = first !== null && typeof first === 'object' ? first.port : first;
|
|
819
|
+
const port = Number(raw);
|
|
820
|
+
return Number.isInteger(port) && port > 0 && port < 65536 ? port : undefined;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
function socketRefusal(hostname, port, isTls) {
|
|
815
824
|
const host = String(hostname || '').toLowerCase();
|
|
816
825
|
if (host === WORLD_ADDRESS[4] || host === WORLD_ADDRESS[6]) {
|
|
817
826
|
return `[twin-inject] refused a socket to ${host}, the address this World's DNS gives the names it routes: `
|
|
@@ -831,8 +840,11 @@ function socketRefusal(hostname) {
|
|
|
831
840
|
return `[twin-inject] refused a raw socket to ${host}, which this world routes to the application (volter-world app-url --host): `
|
|
832
841
|
+ 'the client opened its own connection instead of going through http/https or fetch, so it could not be routed.';
|
|
833
842
|
}
|
|
834
|
-
|
|
835
|
-
|
|
843
|
+
// the destination as an origin, its port and its protocol included: a policy that lists https://host allows TLS to
|
|
844
|
+
// host:443, never another port or a plaintext connection to it
|
|
845
|
+
const authority = `${isIP(host) === 6 ? `[${host}]` : host}${port !== undefined && !(isTls && port === 443) ? `:${port}` : ''}`;
|
|
846
|
+
const url = (() => { try { return new URL(`${isTls ? 'https' : 'http'}://${authority}/`); } catch { return null; } })();
|
|
847
|
+
if (url && shouldBlockUntwinned(url)) return `[twin-inject] blocked untwinned external socket to ${authority}`;
|
|
836
848
|
return null;
|
|
837
849
|
}
|
|
838
850
|
|
|
@@ -844,8 +856,9 @@ function refusedSocket(message) {
|
|
|
844
856
|
|
|
845
857
|
function patchedConnect(originalConnect, isTls) {
|
|
846
858
|
return function patchedSocketConnect(...args) {
|
|
859
|
+
const port = socketTargetPort(args);
|
|
847
860
|
for (const host of socketTargetHosts(args, isTls)) {
|
|
848
|
-
const refusal = socketRefusal(host);
|
|
861
|
+
const refusal = socketRefusal(host, port, isTls);
|
|
849
862
|
if (refusal) return refusedSocket(refusal);
|
|
850
863
|
}
|
|
851
864
|
return originalConnect.apply(this, args);
|
package/network-policy.cjs
CHANGED
|
@@ -66,9 +66,11 @@ function isWorldInternalHost(hostname) {
|
|
|
66
66
|
const v4 = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/.exec(h);
|
|
67
67
|
if (v4) {
|
|
68
68
|
const a = Number(v4[1]); const b = Number(v4[2]);
|
|
69
|
-
|
|
69
|
+
// not link-local 169.254/16: it holds a cloud's instance metadata (169.254.169.254), the box's credentials
|
|
70
|
+
return a === 127 || a === 10 || (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168);
|
|
70
71
|
}
|
|
71
|
-
|
|
72
|
+
// nor fe80::/10, nor a cloud's IPv6 metadata address (fd00:ec2::254)
|
|
73
|
+
return h.includes(':') && (h.startsWith('fc') || h.startsWith('fd')) && h !== 'fd00:ec2::254';
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/world-core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.21",
|
|
4
4
|
"description": "The kernel of Volter World: one log per twin, branches as pointers, checkpoints, the fold that keeps a twin current, the head that performs a write against the vendor, references, and the git plane. A twin package builds on it; the runtime serves it.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"twin",
|