@cotal-ai/workspace 0.50.0 → 0.51.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.
- package/dist/auth-paths.d.ts +50 -0
- package/dist/auth-paths.d.ts.map +1 -1
- package/dist/auth-paths.js +109 -1
- package/dist/auth-paths.js.map +1 -1
- package/dist/connect.d.ts +4 -1
- package/dist/connect.d.ts.map +1 -1
- package/dist/connect.js +7 -3
- package/dist/connect.js.map +1 -1
- package/dist/control-target.d.ts +1 -0
- package/dist/control-target.d.ts.map +1 -1
- package/dist/control-target.js +2 -0
- package/dist/control-target.js.map +1 -1
- package/dist/flags.d.ts +6 -2
- package/dist/flags.d.ts.map +1 -1
- package/dist/flags.js +10 -2
- package/dist/flags.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/join-target.d.ts +173 -0
- package/dist/join-target.d.ts.map +1 -0
- package/dist/join-target.js +335 -0
- package/dist/join-target.js.map +1 -0
- package/dist/mesh-registry.d.ts +29 -5
- package/dist/mesh-registry.d.ts.map +1 -1
- package/dist/mesh-registry.js +64 -20
- package/dist/mesh-registry.js.map +1 -1
- package/dist/mesh-target.d.ts +2 -0
- package/dist/mesh-target.d.ts.map +1 -1
- package/dist/mesh-target.js +1 -0
- package/dist/mesh-target.js.map +1 -1
- package/dist/preflight.d.ts.map +1 -1
- package/dist/preflight.js +6 -0
- package/dist/preflight.js.map +1 -1
- package/dist/registration-policy.d.ts +69 -0
- package/dist/registration-policy.d.ts.map +1 -0
- package/dist/registration-policy.js +179 -0
- package/dist/registration-policy.js.map +1 -0
- package/dist/render.js +3 -3
- package/dist/render.js.map +1 -1
- package/dist/seat-checkpoint.d.ts +167 -0
- package/dist/seat-checkpoint.d.ts.map +1 -0
- package/dist/seat-checkpoint.js +413 -0
- package/dist/seat-checkpoint.js.map +1 -0
- package/package.json +2 -2
package/dist/flags.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flags.js","sourceRoot":"","sources":["../src/flags.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,2CAA2C,EAA8B,CAAC;AAC/J,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,gDAAgD,EAA8B,CAAC;AACxK,MAAM,CAAC,MAAM,SAAS,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,2CAA2C,EAA8B,CAAC;AAElK;;uCAEuC;AACvC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,SAAS,CAAwC,CAAC;AAErG;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,qDAAqD,EAAE;IAClH,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,wEAAwE,EAAE;IACrJ,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,gFAAgF,EAAE;IAC9I,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,kDAAkD,EAAE;IAC/G,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,oDAAoD,EAAE;IAClH,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,iFAAiF,EAAE;IACjJ,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,kGAAkG,EAAE;IAChL,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,wCAAwC,EAAE;IACtG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,wCAAwC,EAAE;IAC1G,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,yHAAyH,EAAE;IACzL,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"flags.js","sourceRoot":"","sources":["../src/flags.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -17,12 +17,15 @@ export * from "./manager-shutdown.js";
|
|
|
17
17
|
export * from "./flags.js";
|
|
18
18
|
export * from "./provenance.js";
|
|
19
19
|
export * from "./mesh-registry.js";
|
|
20
|
+
export * from "./join-target.js";
|
|
21
|
+
export * from "./registration-policy.js";
|
|
20
22
|
export * from "./broker-policy.js";
|
|
21
23
|
export * from "./mesh-target.js";
|
|
22
24
|
export * from "./preflight.js";
|
|
23
25
|
export * from "./render.js";
|
|
24
26
|
export * from "./renewal.js";
|
|
25
27
|
export * from "./secret-store-fs.js";
|
|
28
|
+
export * from "./seat-checkpoint.js";
|
|
26
29
|
export * from "./space.js";
|
|
27
30
|
export * from "./space-segmentation.js";
|
|
28
31
|
export * from "./system-rotation.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -17,12 +17,15 @@ export * from "./manager-shutdown.js";
|
|
|
17
17
|
export * from "./flags.js";
|
|
18
18
|
export * from "./provenance.js";
|
|
19
19
|
export * from "./mesh-registry.js";
|
|
20
|
+
export * from "./join-target.js";
|
|
21
|
+
export * from "./registration-policy.js";
|
|
20
22
|
export * from "./broker-policy.js";
|
|
21
23
|
export * from "./mesh-target.js";
|
|
22
24
|
export * from "./preflight.js";
|
|
23
25
|
export * from "./render.js";
|
|
24
26
|
export * from "./renewal.js";
|
|
25
27
|
export * from "./secret-store-fs.js";
|
|
28
|
+
export * from "./seat-checkpoint.js";
|
|
26
29
|
export * from "./space.js";
|
|
27
30
|
export * from "./space-segmentation.js";
|
|
28
31
|
export * from "./system-rotation.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which broker addresses `cotal meshes add` may register.
|
|
3
|
+
*
|
|
4
|
+
* Registering a mesh is how a machine begins sending its agent credentials to a broker it does
|
|
5
|
+
* not run. NATS sends the initial INFO in plaintext and unauthenticated, so an on-path attacker
|
|
6
|
+
* can forge one that does not set `tls_required`, and a client that was never told to demand
|
|
7
|
+
* encryption puts its credentials in the CONNECT line for the attacker to read. The fence has to
|
|
8
|
+
* be client-side.
|
|
9
|
+
*
|
|
10
|
+
* The URL scheme is NOT that fence. Measured against `@nats-io/transport-node` 3.4.0 (the client
|
|
11
|
+
* this repo uses) pointed at a broker with no TLS configured at all:
|
|
12
|
+
*
|
|
13
|
+
* nats://host:port {} -> CONNECTED
|
|
14
|
+
* tls://host:port {} -> CONNECTED <- the scheme is cosmetic
|
|
15
|
+
* nats://host:port {tls:{}} -> REFUSED: server does not support 'tls'
|
|
16
|
+
*
|
|
17
|
+
* Only the explicit `tls` connect option makes the client demand TLS, and that option is the
|
|
18
|
+
* broker-TLS work's surface, not this one's. So this gates on the ADDRESS instead, in two steps.
|
|
19
|
+
* Step one, here: refuse public addresses, ordinary private ranges and every hostname outright,
|
|
20
|
+
* and refuse an overlay literal TOO unless the operator accepted it explicitly
|
|
21
|
+
* ({@link DialPolicy.allowUnencryptedOverlay}); accepted, it returns a {@link JoinTarget.residual}
|
|
22
|
+
* the caller prints and records as consent. Step two, once a record can carry TLS intent: the
|
|
23
|
+
* acceptance stops being needed because the transport is proven instead of promised.
|
|
24
|
+
*
|
|
25
|
+
* ONE deliberate limitation, stated rather than papered over: this classifies an ADDRESS, which
|
|
26
|
+
* is a guard against the obvious mistake (dialing a LAN or public address in the clear), not
|
|
27
|
+
* proof that the bytes are encrypted. An overlay address only rides an encrypted tunnel while the
|
|
28
|
+
* overlay is actually up on this machine; the same literal with the overlay down is just a CGNAT
|
|
29
|
+
* address.
|
|
30
|
+
*
|
|
31
|
+
* WHERE THIS WENT, so the next editor knows the relaxation below is the authorized one. The
|
|
32
|
+
* previous header said, measured on this stack: the `tls` connect option verifies the certificate
|
|
33
|
+
* CHAIN AND THE HOSTNAME (Node defaults, `rejectUnauthorized: true`, servername from the URL), so
|
|
34
|
+
* a redirected name cannot complete the handshake and hostnames become safe — but only once
|
|
35
|
+
* something REQUIRES TLS. The relaxation is a function of recorded strictness, not of time
|
|
36
|
+
* passing, and the agreed shape is `classifyJoinTarget(url, { tlsRequired })` rather than a third
|
|
37
|
+
* verdict: one place keeps answering "may this machine send credentials to that address", with
|
|
38
|
+
* strictness as an input it cannot otherwise see. THAT PRECONDITION HAS NOW LANDED: the broker
|
|
39
|
+
* can serve TLS and the mesh record carries `tlsRequired`, so with `tlsRequired: true` a hostname
|
|
40
|
+
* or a public literal classifies as {@link JoinReach} `"public-tls"`. Two counterintuitive
|
|
41
|
+
* consequences remain in force: the overlay ranges are the AWKWARD case under TLS (CGNAT space,
|
|
42
|
+
* no public CA will issue for it, verifying a literal needs an IP SAN, so it implies a private CA
|
|
43
|
+
* on every joiner), while the `<host>.ts.net` names are the EASY case (publicly resolvable,
|
|
44
|
+
* publicly-trusted certs). With `tlsRequired: false` nothing is relaxed: literals-only stays the
|
|
45
|
+
* rule, verbatim. And ordinary private ranges are refused in BOTH modes — no public CA issues for
|
|
46
|
+
* them, so required TLS cannot make them verifiable, and a cafe LAN is private too.
|
|
47
|
+
*/
|
|
48
|
+
/** The address class a permitted target belongs to. This is a REACHABILITY allowlist: it says the
|
|
49
|
+
* address is one we are willing to consider, never that the connection is protected. What
|
|
50
|
+
* protects it is {@link DialPolicy.tlsRequired}, except on loopback where nothing leaves the
|
|
51
|
+
* machine to protect. */
|
|
52
|
+
export type JoinReach =
|
|
53
|
+
/** A loopback literal: the bytes never leave the machine. */
|
|
54
|
+
"loopback"
|
|
55
|
+
/** A private-overlay literal. Permitted TODAY without required TLS, carrying a
|
|
56
|
+
* {@link JoinTarget.residual} that says so; it becomes conditional on TLS in step two. The
|
|
57
|
+
* address alone is not a guarantee - see {@link DialPolicy.tlsRequired}. */
|
|
58
|
+
| "overlay"
|
|
59
|
+
/** A hostname or public literal dialed with REQUIRED TLS ({@link DialPolicy.tlsRequired}):
|
|
60
|
+
* the certificate chain + hostname check is the authority, so the resolver no longer picks
|
|
61
|
+
* the peer. Never produced with `tlsRequired: false`. */
|
|
62
|
+
| "public-tls";
|
|
63
|
+
export interface JoinTarget {
|
|
64
|
+
/** The normalized dial URL, port defaulted. */
|
|
65
|
+
server: string;
|
|
66
|
+
reach: JoinReach;
|
|
67
|
+
/**
|
|
68
|
+
* Set when the target is permitted but its protection is NOT guaranteed, carrying the sentence
|
|
69
|
+
* the operator needs to read. Exactly one case produces it today: an overlay literal dialed
|
|
70
|
+
* without required TLS, where the address class is right but the tunnel being up is an
|
|
71
|
+
* assumption rather than a fact.
|
|
72
|
+
*
|
|
73
|
+
* It is a returned value rather than a throw because by the time it is produced the operator has
|
|
74
|
+
* ALREADY accepted the risk, so the remaining job is to carry the sentence: the caller prints it
|
|
75
|
+
* as a second notice and records it on the entry as evidence of consent. The refusal for someone
|
|
76
|
+
* who has NOT accepted happens earlier, and is a throw.
|
|
77
|
+
*/
|
|
78
|
+
residual?: string;
|
|
79
|
+
}
|
|
80
|
+
/** What the eventual connection will insist on, which the address alone cannot tell us. */
|
|
81
|
+
export interface DialPolicy {
|
|
82
|
+
/**
|
|
83
|
+
* Will the dial to this target REQUIRE TLS?
|
|
84
|
+
*
|
|
85
|
+
* This is the difference between an address and a guarantee, and getting it wrong was the
|
|
86
|
+
* defect this parameter exists to close. An overlay address is not proof the overlay transport
|
|
87
|
+
* is up: with the tunnel daemon stopped, `100.64.0.0/10` is ordinary CGNAT space, and hostile
|
|
88
|
+
* DHCP or routing can answer a dial to it. So the address class establishes only that we are
|
|
89
|
+
* willing to consider the target; requiring TLS is what makes it safe.
|
|
90
|
+
*
|
|
91
|
+
* The mesh record now carries this intent (`MeshEntry.tlsRequired`), so callers pass the
|
|
92
|
+
* record's real strictness. With it `false` an overlay literal is refused unless
|
|
93
|
+
* {@link DialPolicy.allowUnencryptedOverlay} says the operator accepted the tunnel dependency.
|
|
94
|
+
* With it `true` the acceptance stops being needed — the transport is proven rather than
|
|
95
|
+
* promised — and a hostname or public literal becomes registrable as `"public-tls"`.
|
|
96
|
+
*/
|
|
97
|
+
tlsRequired: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Did the operator EXPLICITLY accept the overlay's tunnel dependency?
|
|
100
|
+
*
|
|
101
|
+
* The default is `false` and the default refuses, because the previous shape — permit and print
|
|
102
|
+
* a warning — is not a fence. A warning is written to stderr, which a non-interactive caller
|
|
103
|
+
* need not read, and it was not persisted, so nothing repeated it at the dials that followed. A
|
|
104
|
+
* scripted registration therefore got the risk with none of the notice.
|
|
105
|
+
*
|
|
106
|
+
* A flag is the one form of notice a script cannot miss: without it the command fails, and the
|
|
107
|
+
* failure is in the exit code rather than in prose nobody reads. The acceptance is then recorded
|
|
108
|
+
* on the mesh entry, so a later dial can tell that a human agreed to this rather than inferring
|
|
109
|
+
* consent from an address.
|
|
110
|
+
*/
|
|
111
|
+
allowUnencryptedOverlay: boolean;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* WHICH fence refused, as a closed set rather than as prose.
|
|
115
|
+
*
|
|
116
|
+
* The union is exhaustive on purpose: a new refusal arm must name itself here or it will not
|
|
117
|
+
* compile, so an unlabelled refusal is a type error rather than a cell that passes for the wrong
|
|
118
|
+
* reason.
|
|
119
|
+
*/
|
|
120
|
+
export declare const JOIN_REFUSAL_CODES: readonly ["not-a-url", "bad-scheme", "no-host", "overlay-unacked", "private-range", "unprotected-target"];
|
|
121
|
+
/**
|
|
122
|
+
* The type is DERIVED from the runtime array above, so there is exactly ONE universe of codes.
|
|
123
|
+
*
|
|
124
|
+
* A suite that restated this list would carry a second copy of the thing it measures, and copies
|
|
125
|
+
* drift in the direction that hurts: an arm added here but not there makes the emitted-code check
|
|
126
|
+
* either falsely red or, if loosened to compensate, permanently green. Exporting the array and
|
|
127
|
+
* deriving the type means a new arm is visible to the suite by construction, with the union no
|
|
128
|
+
* less closed than a hand-written one.
|
|
129
|
+
*/
|
|
130
|
+
export type JoinRefusalCode = (typeof JOIN_REFUSAL_CODES)[number];
|
|
131
|
+
/**
|
|
132
|
+
* A refusal from THIS classifier, identified structurally.
|
|
133
|
+
*
|
|
134
|
+
* The suite used to decide "was this a refusal?" by matching the rendered message, which is a
|
|
135
|
+
* string shape standing in for a decision — the exact defect the address fences in this file exist
|
|
136
|
+
* to correct, reproduced in the harness that proves them. Measured: a fault firing before the
|
|
137
|
+
* privacy check that emitted the privacy refusal's text VERBATIM was accepted as a genuine
|
|
138
|
+
* private-range refusal. A tag the classifier sets deliberately cannot be produced by an unrelated
|
|
139
|
+
* fault, so a cell can require not merely "something refused" but "the fence I am testing refused".
|
|
140
|
+
*
|
|
141
|
+
* BOUNDARY, stated so "typed" is not read as "unspoofable": this class is EXPORTED so the suite can
|
|
142
|
+
* assert `instanceof`, and that same export hands the constructor to every importer — so a refusal
|
|
143
|
+
* is NOT unforgeable from outside. What holds is narrower, and is the property that matters:
|
|
144
|
+
* unforgeable BY ACCIDENT — constructible only by deliberate code that imports the class, wherever
|
|
145
|
+
* it lives; and `classifyJoinTarget` throws its own. The reachable threat was never a malicious
|
|
146
|
+
* importer manufacturing one; it was a non-privacy fault inside this module reporting as a privacy
|
|
147
|
+
* refusal, and a deliberate tag plus a per-cell code closes that.
|
|
148
|
+
*/
|
|
149
|
+
export declare class JoinRefusal extends Error {
|
|
150
|
+
readonly code: JoinRefusalCode;
|
|
151
|
+
constructor(code: JoinRefusalCode, message: string);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Is this host the loopback machine, whatever spelling it arrived in?
|
|
155
|
+
*
|
|
156
|
+
* THE ANSWER COMES FROM PARSING AN ADDRESS, NEVER FROM HOW THE TEXT BEGINS. A prefix test like
|
|
157
|
+
* `/^127\./` matches `127.evil.com`, `127.0.0.1.nip.io` and `127.com` — all registrable by anyone
|
|
158
|
+
* — and misses real loopback spellings such as `0177.0.0.1` or `[::ffff:127.0.0.1]`. It is wrong
|
|
159
|
+
* in both directions, which is what a string standing in for an address decision usually is.
|
|
160
|
+
*
|
|
161
|
+
* Exported so every caller that needs "is this loopback" shares ONE authority, canonicalization
|
|
162
|
+
* included, rather than growing a second opinion. Brackets are tolerated so a caller may pass a
|
|
163
|
+
* URL hostname straight in.
|
|
164
|
+
*/
|
|
165
|
+
export declare function isLoopbackHost(host: string): boolean;
|
|
166
|
+
/**
|
|
167
|
+
* Classify a registration target, or throw the reason it is refused.
|
|
168
|
+
*
|
|
169
|
+
* Refusal is the point: an unclassifiable target is one whose credentials would cross a network
|
|
170
|
+
* this build cannot encrypt, so it fails loud here rather than dialing and hoping.
|
|
171
|
+
*/
|
|
172
|
+
export declare function classifyJoinTarget(raw: string, policy: DialPolicy): JoinTarget;
|
|
173
|
+
//# sourceMappingURL=join-target.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"join-target.d.ts","sourceRoot":"","sources":["../src/join-target.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAEH;;;0BAG0B;AAC1B,MAAM,MAAM,SAAS;AACnB,6DAA6D;AAC3D,UAAU;AACZ;;6EAE6E;GAC3E,SAAS;AACX;;0DAE0D;GACxD,YAAY,CAAC;AAEjB,MAAM,WAAW,UAAU;IACzB,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IACjB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,2FAA2F;AAC3F,MAAM,WAAW,UAAU;IACzB;;;;;;;;;;;;;;OAcG;IACH,WAAW,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;;OAYG;IACH,uBAAuB,EAAE,OAAO,CAAC;CAClC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,2GAarB,CAAC;AAEX;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAElE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;gBACnB,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM;CAKnD;AAKD;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGpD;AA8ID;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,UAAU,CAqE9E"}
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which broker addresses `cotal meshes add` may register.
|
|
3
|
+
*
|
|
4
|
+
* Registering a mesh is how a machine begins sending its agent credentials to a broker it does
|
|
5
|
+
* not run. NATS sends the initial INFO in plaintext and unauthenticated, so an on-path attacker
|
|
6
|
+
* can forge one that does not set `tls_required`, and a client that was never told to demand
|
|
7
|
+
* encryption puts its credentials in the CONNECT line for the attacker to read. The fence has to
|
|
8
|
+
* be client-side.
|
|
9
|
+
*
|
|
10
|
+
* The URL scheme is NOT that fence. Measured against `@nats-io/transport-node` 3.4.0 (the client
|
|
11
|
+
* this repo uses) pointed at a broker with no TLS configured at all:
|
|
12
|
+
*
|
|
13
|
+
* nats://host:port {} -> CONNECTED
|
|
14
|
+
* tls://host:port {} -> CONNECTED <- the scheme is cosmetic
|
|
15
|
+
* nats://host:port {tls:{}} -> REFUSED: server does not support 'tls'
|
|
16
|
+
*
|
|
17
|
+
* Only the explicit `tls` connect option makes the client demand TLS, and that option is the
|
|
18
|
+
* broker-TLS work's surface, not this one's. So this gates on the ADDRESS instead, in two steps.
|
|
19
|
+
* Step one, here: refuse public addresses, ordinary private ranges and every hostname outright,
|
|
20
|
+
* and refuse an overlay literal TOO unless the operator accepted it explicitly
|
|
21
|
+
* ({@link DialPolicy.allowUnencryptedOverlay}); accepted, it returns a {@link JoinTarget.residual}
|
|
22
|
+
* the caller prints and records as consent. Step two, once a record can carry TLS intent: the
|
|
23
|
+
* acceptance stops being needed because the transport is proven instead of promised.
|
|
24
|
+
*
|
|
25
|
+
* ONE deliberate limitation, stated rather than papered over: this classifies an ADDRESS, which
|
|
26
|
+
* is a guard against the obvious mistake (dialing a LAN or public address in the clear), not
|
|
27
|
+
* proof that the bytes are encrypted. An overlay address only rides an encrypted tunnel while the
|
|
28
|
+
* overlay is actually up on this machine; the same literal with the overlay down is just a CGNAT
|
|
29
|
+
* address.
|
|
30
|
+
*
|
|
31
|
+
* WHERE THIS WENT, so the next editor knows the relaxation below is the authorized one. The
|
|
32
|
+
* previous header said, measured on this stack: the `tls` connect option verifies the certificate
|
|
33
|
+
* CHAIN AND THE HOSTNAME (Node defaults, `rejectUnauthorized: true`, servername from the URL), so
|
|
34
|
+
* a redirected name cannot complete the handshake and hostnames become safe — but only once
|
|
35
|
+
* something REQUIRES TLS. The relaxation is a function of recorded strictness, not of time
|
|
36
|
+
* passing, and the agreed shape is `classifyJoinTarget(url, { tlsRequired })` rather than a third
|
|
37
|
+
* verdict: one place keeps answering "may this machine send credentials to that address", with
|
|
38
|
+
* strictness as an input it cannot otherwise see. THAT PRECONDITION HAS NOW LANDED: the broker
|
|
39
|
+
* can serve TLS and the mesh record carries `tlsRequired`, so with `tlsRequired: true` a hostname
|
|
40
|
+
* or a public literal classifies as {@link JoinReach} `"public-tls"`. Two counterintuitive
|
|
41
|
+
* consequences remain in force: the overlay ranges are the AWKWARD case under TLS (CGNAT space,
|
|
42
|
+
* no public CA will issue for it, verifying a literal needs an IP SAN, so it implies a private CA
|
|
43
|
+
* on every joiner), while the `<host>.ts.net` names are the EASY case (publicly resolvable,
|
|
44
|
+
* publicly-trusted certs). With `tlsRequired: false` nothing is relaxed: literals-only stays the
|
|
45
|
+
* rule, verbatim. And ordinary private ranges are refused in BOTH modes — no public CA issues for
|
|
46
|
+
* them, so required TLS cannot make them verifiable, and a cafe LAN is private too.
|
|
47
|
+
*/
|
|
48
|
+
/**
|
|
49
|
+
* WHICH fence refused, as a closed set rather than as prose.
|
|
50
|
+
*
|
|
51
|
+
* The union is exhaustive on purpose: a new refusal arm must name itself here or it will not
|
|
52
|
+
* compile, so an unlabelled refusal is a type error rather than a cell that passes for the wrong
|
|
53
|
+
* reason.
|
|
54
|
+
*/
|
|
55
|
+
export const JOIN_REFUSAL_CODES = [
|
|
56
|
+
/** The string is not a URL at all. */
|
|
57
|
+
"not-a-url",
|
|
58
|
+
/** Parsed, but not a broker scheme this policy classifies. */
|
|
59
|
+
"bad-scheme",
|
|
60
|
+
/** Parsed, but carries no host to classify. */
|
|
61
|
+
"no-host",
|
|
62
|
+
/** An overlay literal without required TLS and without recorded acceptance. */
|
|
63
|
+
"overlay-unacked",
|
|
64
|
+
/** A private range, which required TLS cannot make verifiable. */
|
|
65
|
+
"private-range",
|
|
66
|
+
/** A hostname or public literal with no TLS requirement to protect it. */
|
|
67
|
+
"unprotected-target",
|
|
68
|
+
];
|
|
69
|
+
/**
|
|
70
|
+
* A refusal from THIS classifier, identified structurally.
|
|
71
|
+
*
|
|
72
|
+
* The suite used to decide "was this a refusal?" by matching the rendered message, which is a
|
|
73
|
+
* string shape standing in for a decision — the exact defect the address fences in this file exist
|
|
74
|
+
* to correct, reproduced in the harness that proves them. Measured: a fault firing before the
|
|
75
|
+
* privacy check that emitted the privacy refusal's text VERBATIM was accepted as a genuine
|
|
76
|
+
* private-range refusal. A tag the classifier sets deliberately cannot be produced by an unrelated
|
|
77
|
+
* fault, so a cell can require not merely "something refused" but "the fence I am testing refused".
|
|
78
|
+
*
|
|
79
|
+
* BOUNDARY, stated so "typed" is not read as "unspoofable": this class is EXPORTED so the suite can
|
|
80
|
+
* assert `instanceof`, and that same export hands the constructor to every importer — so a refusal
|
|
81
|
+
* is NOT unforgeable from outside. What holds is narrower, and is the property that matters:
|
|
82
|
+
* unforgeable BY ACCIDENT — constructible only by deliberate code that imports the class, wherever
|
|
83
|
+
* it lives; and `classifyJoinTarget` throws its own. The reachable threat was never a malicious
|
|
84
|
+
* importer manufacturing one; it was a non-privacy fault inside this module reporting as a privacy
|
|
85
|
+
* refusal, and a deliberate tag plus a per-cell code closes that.
|
|
86
|
+
*/
|
|
87
|
+
export class JoinRefusal extends Error {
|
|
88
|
+
code;
|
|
89
|
+
constructor(code, message) {
|
|
90
|
+
super(message);
|
|
91
|
+
this.name = "JoinRefusal";
|
|
92
|
+
this.code = code;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** The NATS default client port, used when the join URL omits one. */
|
|
96
|
+
const DEFAULT_PORT = 4222;
|
|
97
|
+
/**
|
|
98
|
+
* Is this host the loopback machine, whatever spelling it arrived in?
|
|
99
|
+
*
|
|
100
|
+
* THE ANSWER COMES FROM PARSING AN ADDRESS, NEVER FROM HOW THE TEXT BEGINS. A prefix test like
|
|
101
|
+
* `/^127\./` matches `127.evil.com`, `127.0.0.1.nip.io` and `127.com` — all registrable by anyone
|
|
102
|
+
* — and misses real loopback spellings such as `0177.0.0.1` or `[::ffff:127.0.0.1]`. It is wrong
|
|
103
|
+
* in both directions, which is what a string standing in for an address decision usually is.
|
|
104
|
+
*
|
|
105
|
+
* Exported so every caller that needs "is this loopback" shares ONE authority, canonicalization
|
|
106
|
+
* included, rather than growing a second opinion. Brackets are tolerated so a caller may pass a
|
|
107
|
+
* URL hostname straight in.
|
|
108
|
+
*/
|
|
109
|
+
export function isLoopbackHost(host) {
|
|
110
|
+
const bare = host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
|
|
111
|
+
return isLoopbackLiteral(normalizeLegacyV4(normalizeMappedV4(bare)));
|
|
112
|
+
}
|
|
113
|
+
/** Loopback: `127.0.0.0/8` and `::1`. LITERALS ONLY, never `localhost`, because the whole point is
|
|
114
|
+
* a verdict that does not depend on a resolver an attacker could influence (a hosts-file entry or
|
|
115
|
+
* a poisoned lookup would otherwise turn "loopback" into any address at all). */
|
|
116
|
+
function isLoopbackLiteral(host) {
|
|
117
|
+
if (host === "::1" || host === "0:0:0:0:0:0:0:1")
|
|
118
|
+
return true;
|
|
119
|
+
const v4 = host.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
|
|
120
|
+
if (!v4)
|
|
121
|
+
return false;
|
|
122
|
+
const parts = v4.slice(1).map(Number);
|
|
123
|
+
if (parts.some((n) => n > 255))
|
|
124
|
+
return false;
|
|
125
|
+
return parts[0] === 127;
|
|
126
|
+
}
|
|
127
|
+
/** The private overlay's address space: `100.64.0.0/10` (the CGNAT range Tailscale assigns) and
|
|
128
|
+
* `fd7a:115c:a1e0::/48` (its ULA prefix). LITERALS ONLY, for the same reason as loopback: a
|
|
129
|
+
* MagicDNS name like `<host>.ts.net` is a resolver answer, and accepting it would let whoever
|
|
130
|
+
* answers that lookup redirect a plaintext credential-bearing dial anywhere they like. */
|
|
131
|
+
function isOverlayLiteral(host) {
|
|
132
|
+
const v4 = host.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
|
|
133
|
+
if (v4) {
|
|
134
|
+
const parts = v4.slice(1).map(Number);
|
|
135
|
+
if (parts.some((n) => n > 255))
|
|
136
|
+
return false;
|
|
137
|
+
// 100.64.0.0/10 == 100.64.0.0 through 100.127.255.255.
|
|
138
|
+
return parts[0] === 100 && parts[1] >= 64 && parts[1] <= 127;
|
|
139
|
+
}
|
|
140
|
+
return /^fd7a:115c:a1e0:/i.test(host);
|
|
141
|
+
}
|
|
142
|
+
/** Ordinary private ranges: RFC1918, link-local, and the non-overlay ULA/link-local v6 space.
|
|
143
|
+
* Refused in BOTH modes — a cafe LAN is private too, and no public CA issues certificates for
|
|
144
|
+
* these ranges, so required TLS cannot make an address here verifiable. */
|
|
145
|
+
function isPrivateLiteral(host) {
|
|
146
|
+
const v4 = host.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
|
|
147
|
+
if (v4) {
|
|
148
|
+
const p = v4.slice(1).map(Number);
|
|
149
|
+
if (p.some((n) => n > 255))
|
|
150
|
+
return false; // not an IP literal at all; treated as a hostname
|
|
151
|
+
if (p[0] === 10)
|
|
152
|
+
return true; // 10.0.0.0/8
|
|
153
|
+
if (p[0] === 172 && p[1] >= 16 && p[1] <= 31)
|
|
154
|
+
return true; // 172.16.0.0/12
|
|
155
|
+
if (p[0] === 192 && p[1] === 168)
|
|
156
|
+
return true; // 192.168.0.0/16
|
|
157
|
+
if (p[0] === 169 && p[1] === 254)
|
|
158
|
+
return true; // 169.254.0.0/16 link-local
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
// ULA fc00::/7 and link-local fe80::/10; the overlay's fd7a:115c:a1e0::/48 is classified first.
|
|
162
|
+
return /^(f[cd][0-9a-f]{2}:|fe[89ab][0-9a-f]{0,2}:)/i.test(host);
|
|
163
|
+
}
|
|
164
|
+
/** A URL's hostname with an IPv6 literal's brackets removed (`[::1]` -> `::1`). */
|
|
165
|
+
function bareHost(url) {
|
|
166
|
+
return url.hostname.startsWith("[") && url.hostname.endsWith("]")
|
|
167
|
+
? url.hostname.slice(1, -1)
|
|
168
|
+
: url.hostname;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Collapse ANY legacy IPv4 spelling to canonical dotted-quad, so that one address has ONE
|
|
172
|
+
* verdict however it is written.
|
|
173
|
+
*
|
|
174
|
+
* `inet_aton` — which the C library, Node's resolver and every OS dialer accept — does not
|
|
175
|
+
* require four decimal octets. It takes 1, 2, 3 or 4 parts, each of which may be decimal, octal
|
|
176
|
+
* (leading `0`) or hex (leading `0x`), and a short form's final part absorbs the remaining bytes.
|
|
177
|
+
* All of these are 192.168.1.10, verified against `dns.lookup` on this machine:
|
|
178
|
+
*
|
|
179
|
+
* 3232235786 (decimal dword) -> 192.168.1.10
|
|
180
|
+
* 0300.0250.01.012 (octal dotted) -> 192.168.1.10
|
|
181
|
+
* 0xC0A8010A (hex dword) -> 192.168.1.10
|
|
182
|
+
* 0177.0.0.1 (octal, loopback) -> 127.0.0.1
|
|
183
|
+
* 192.168.257 (3-part shorthand) -> 192.168.1.1
|
|
184
|
+
*
|
|
185
|
+
* A classifier that only matched four decimal octets treated each of these as a HOSTNAME, so it
|
|
186
|
+
* fell through the private-range fence and registered as a public address, while the dotted form
|
|
187
|
+
* of the very same host was refused. Canonicalize first; classify once.
|
|
188
|
+
*
|
|
189
|
+
* Returns the dotted form, or the input unchanged when it is not an IPv4 literal in any spelling
|
|
190
|
+
* (a real hostname, or a v6 literal handled below).
|
|
191
|
+
*/
|
|
192
|
+
function normalizeLegacyV4(host) {
|
|
193
|
+
if (!/^[0-9a-fx.]+$/i.test(host) || host.endsWith("."))
|
|
194
|
+
return host;
|
|
195
|
+
const parts = host.split(".");
|
|
196
|
+
if (parts.length > 4)
|
|
197
|
+
return host;
|
|
198
|
+
const nums = [];
|
|
199
|
+
for (const part of parts) {
|
|
200
|
+
if (part === "")
|
|
201
|
+
return host;
|
|
202
|
+
let n;
|
|
203
|
+
if (/^0[xX][0-9a-fA-F]+$/.test(part))
|
|
204
|
+
n = parseInt(part.slice(2), 16);
|
|
205
|
+
else if (/^0[0-7]+$/.test(part))
|
|
206
|
+
n = parseInt(part.slice(1), 8);
|
|
207
|
+
else if (/^(0|[1-9][0-9]*)$/.test(part))
|
|
208
|
+
n = Number(part);
|
|
209
|
+
else
|
|
210
|
+
return host; // e.g. 09 or 0xZ: not a number in any base, so not an IPv4 literal
|
|
211
|
+
if (!Number.isSafeInteger(n) || n < 0)
|
|
212
|
+
return host;
|
|
213
|
+
nums.push(n);
|
|
214
|
+
}
|
|
215
|
+
// The last part absorbs the bytes the earlier parts did not name (inet_aton's short forms).
|
|
216
|
+
const leading = nums.slice(0, -1);
|
|
217
|
+
const last = nums[nums.length - 1];
|
|
218
|
+
if (leading.some((n) => n > 255))
|
|
219
|
+
return host;
|
|
220
|
+
const width = 4 - leading.length;
|
|
221
|
+
if (last > (width === 4 ? 0xffffffff : Math.pow(256, width) - 1))
|
|
222
|
+
return host;
|
|
223
|
+
const bytes = [...leading];
|
|
224
|
+
for (let i = width - 1; i >= 0; i--)
|
|
225
|
+
bytes.push((last >>> (8 * i)) & 0xff);
|
|
226
|
+
return bytes.join(".");
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Collapse an IPv4-MAPPED IPv6 literal to its dotted IPv4 form, so that one address has ONE
|
|
230
|
+
* verdict however it is spelled.
|
|
231
|
+
*
|
|
232
|
+
* `::ffff:192.168.1.10` and `::ffff:c0a8:010a` are the same 192.168.1.10, and the kernel dials
|
|
233
|
+
* them to the same host. RFC 4291 mapped form is exactly `::ffff:a.b.c.d` (equivalently
|
|
234
|
+
* `::ffff:xxxx:xxxx`) and NOTHING ELSE: `::ffff:0:127.0.0.1` looks similar but is a different
|
|
235
|
+
* address, which a socket proves — it dials ENETUNREACH where `::ffff:127.0.0.1` connects to
|
|
236
|
+
* loopback. Collapsing it would be this fence's own bug in mirror image, granting a loopback,
|
|
237
|
+
* overlay or public verdict to an address that is none of those. Classifying the v6 spelling separately meant the private-range check ran
|
|
238
|
+
* a v4 regex that could not match, the address fell through to "not private", and
|
|
239
|
+
* `--tls` registered a LAN broker that the dotted form correctly refuses. Every classifier below
|
|
240
|
+
* therefore sees the normalized form, which keeps loopback/overlay/private answers identical
|
|
241
|
+
* across spellings rather than fixing only the range that was reported.
|
|
242
|
+
*
|
|
243
|
+
* Anything that is not a v4-mapped literal is returned unchanged.
|
|
244
|
+
*/
|
|
245
|
+
function normalizeMappedV4(host) {
|
|
246
|
+
const m = host.match(/^::ffff:([0-9a-f.:]+)$/i);
|
|
247
|
+
if (!m)
|
|
248
|
+
return host;
|
|
249
|
+
const tail = m[1];
|
|
250
|
+
const dotted = tail.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
|
|
251
|
+
if (dotted) {
|
|
252
|
+
const p = dotted.slice(1).map(Number);
|
|
253
|
+
return p.some((n) => n > 255) ? host : p.join(".");
|
|
254
|
+
}
|
|
255
|
+
// Only the two RFC 4291 tails are mapped. A legacy-spelled tail (`::ffff:3232235786`) is not
|
|
256
|
+
// handled here and does not need to be: `new URL()` rejects it as an invalid IPv6 literal
|
|
257
|
+
// before this function is ever called, so the target is refused as "not a URL" — a stricter
|
|
258
|
+
// answer than any collapse. Adding a branch for it would be unreachable code that no test
|
|
259
|
+
// could kill, and the address does not resolve anyway (a socket reports ENOTFOUND).
|
|
260
|
+
const hex = tail.match(/^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i);
|
|
261
|
+
if (hex) {
|
|
262
|
+
const hi = parseInt(hex[1], 16);
|
|
263
|
+
const lo = parseInt(hex[2], 16);
|
|
264
|
+
return [hi >> 8, hi & 0xff, lo >> 8, lo & 0xff].join(".");
|
|
265
|
+
}
|
|
266
|
+
return host;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Classify a registration target, or throw the reason it is refused.
|
|
270
|
+
*
|
|
271
|
+
* Refusal is the point: an unclassifiable target is one whose credentials would cross a network
|
|
272
|
+
* this build cannot encrypt, so it fails loud here rather than dialing and hoping.
|
|
273
|
+
*/
|
|
274
|
+
export function classifyJoinTarget(raw, policy) {
|
|
275
|
+
let url;
|
|
276
|
+
try {
|
|
277
|
+
url = new URL(raw);
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
throw new JoinRefusal("not-a-url", `${JSON.stringify(raw)} is not a URL - pass a broker address like nats://100.64.0.1:4222`);
|
|
281
|
+
}
|
|
282
|
+
if (url.protocol !== "nats:" && url.protocol !== "tls:" && url.protocol !== "ws:" && url.protocol !== "wss:")
|
|
283
|
+
throw new JoinRefusal("bad-scheme", `${JSON.stringify(raw)} must be a nats://, tls://, ws:// or wss:// URL, not ${url.protocol}//`);
|
|
284
|
+
// ONE address, ONE verdict: every legacy IPv4 spelling (decimal dword, octal, hex, short form)
|
|
285
|
+
// and every v4-mapped v6 literal is collapsed to canonical dotted form BEFORE any classifier
|
|
286
|
+
// runs, so an alternate spelling cannot walk past the private-range fence.
|
|
287
|
+
const host = normalizeLegacyV4(normalizeMappedV4(bareHost(url)));
|
|
288
|
+
if (!host)
|
|
289
|
+
throw new JoinRefusal("no-host", `${JSON.stringify(raw)} has no host`);
|
|
290
|
+
// A websocket broker rides the web's ports and may live under a PATH (`wss://host/mesh-ws`
|
|
291
|
+
// behind an HTTPS edge) - the path is part of the address and must survive into the record,
|
|
292
|
+
// where a plain NATS URL has no path to keep.
|
|
293
|
+
const ws = url.protocol === "ws:" || url.protocol === "wss:";
|
|
294
|
+
const port = url.port || String(ws ? (url.protocol === "wss:" ? 443 : 80) : DEFAULT_PORT);
|
|
295
|
+
const path = ws && url.pathname !== "/" ? url.pathname : "";
|
|
296
|
+
const server = `${url.protocol}//${url.hostname}:${port}${path}`;
|
|
297
|
+
// Loopback is the one class that needs no transport guarantee: nothing leaves the machine, so
|
|
298
|
+
// there is nothing on a wire for anyone to sit on.
|
|
299
|
+
if (isLoopbackLiteral(host))
|
|
300
|
+
return { server, reach: "loopback" };
|
|
301
|
+
if (isOverlayLiteral(host)) {
|
|
302
|
+
if (policy.tlsRequired)
|
|
303
|
+
return { server, reach: "overlay" };
|
|
304
|
+
if (!policy.allowUnencryptedOverlay)
|
|
305
|
+
throw new JoinRefusal("overlay-unacked", `${JSON.stringify(raw)} refused: ${host} is a private-overlay address, and this build cannot require TLS on the connection.\n` +
|
|
306
|
+
` That is safe while the overlay tunnel is up, and NOT safe if it is down: the range is then ordinary carrier-grade\n` +
|
|
307
|
+
` NAT, and whoever answers the dial receives the credentials this machine sends.\n` +
|
|
308
|
+
` Only you can know whether the tunnel is up, so accept it explicitly with --allow-unencrypted-overlay, which records\n` +
|
|
309
|
+
` your acceptance on the mesh entry. The flag goes away once the broker can be served over TLS.`);
|
|
310
|
+
return {
|
|
311
|
+
server,
|
|
312
|
+
reach: "overlay",
|
|
313
|
+
residual: `${host} is a private-overlay address, and this build cannot yet require TLS on the connection.\n` +
|
|
314
|
+
` That is safe while the overlay tunnel is actually up: it authenticates both machines and encrypts the link.\n` +
|
|
315
|
+
` It is NOT safe if the tunnel is down. That range is then ordinary carrier-grade NAT space, and whoever\n` +
|
|
316
|
+
` answers the dial receives the credentials this machine will send. Keep the tunnel up, and expect this to\n` +
|
|
317
|
+
` become a refusal once the broker can be served over TLS and the record can say TLS is required.`,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
// Recorded strictness relaxes the fence, exactly as the header pre-authorized: with TLS
|
|
321
|
+
// REQUIRED, the `tls` connect option verifies the certificate chain and the hostname, so a
|
|
322
|
+
// hostname or a public literal is safe — the resolver stops choosing the peer. Private ranges
|
|
323
|
+
// stay refused: no public CA issues for them, and a cafe LAN is private too.
|
|
324
|
+
if (policy.tlsRequired) {
|
|
325
|
+
if (!isPrivateLiteral(host))
|
|
326
|
+
return { server, reach: "public-tls" };
|
|
327
|
+
throw new JoinRefusal("private-range", `${JSON.stringify(raw)} refused: ${host} is a private-range address, and requiring TLS does not make it verifiable - no public CA issues certificates for RFC1918 or link-local space, and a cafe LAN is private, not yours.\n` +
|
|
328
|
+
` Register the broker by its public name or address, or run it on this machine and use a loopback literal.`);
|
|
329
|
+
}
|
|
330
|
+
throw new JoinRefusal("unprotected-target", `${JSON.stringify(raw)} refused: this build cannot protect a connection to ${host}, and a machine that registers a mesh sends its agent credentials to that broker.\n` +
|
|
331
|
+
` Only a loopback literal (127.0.0.0/8, ::1) or a private-overlay literal (100.64.0.0/10, fd7a:115c:a1e0::/48) may be registered. An overlay literal additionally needs --allow-unencrypted-overlay, which records that you accepted its tunnel dependency.\n` +
|
|
332
|
+
` Ordinary private ranges are refused too: a cafe network is private, and private is not the same as yours.\n` +
|
|
333
|
+
` A hostname is refused even when it resolves somewhere permitted - otherwise whoever answers the lookup chooses which machine receives the credentials. Pass the address itself.`);
|
|
334
|
+
}
|
|
335
|
+
//# sourceMappingURL=join-target.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"join-target.js","sourceRoot":"","sources":["../src/join-target.ts"],"names":[],"mappings":"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"}
|