@kernhq/module-quire 0.15.0 → 0.16.1

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.
@@ -0,0 +1,110 @@
1
+ import { PAGE_OBJECT_REF } from '@kernhq/ui/editor/page-doc';
2
+ /** How many distinct objects one page may name. A document decides how much work a render does. */
3
+ const MAX_OBJECTS = 40;
4
+ /**
5
+ * `quire:page:0192…` in three parts, or nothing.
6
+ *
7
+ * The same pattern the editor narrows with, checked again here for the reason every attribute in
8
+ * this module is: what arrives is JSON out of a CRDT, which is to say a string a client picked.
9
+ */
10
+ export function parseRef(value) {
11
+ if (typeof value !== 'string' || !PAGE_OBJECT_REF.test(value))
12
+ return null;
13
+ const [module, type, id] = value.split(':');
14
+ return { ref: value, module, type, id };
15
+ }
16
+ export function quireObjects(kernel, access) {
17
+ /**
18
+ * The module hosting a type, but only if this process hosts it.
19
+ *
20
+ * `kernel.registry` is local, which is the honest limit and the safe one: a module hosted by
21
+ * another service answers nothing here, so the embed draws an empty frame. Reaching across with
22
+ * `kernel.call` would need a procedure every module agreed to expose, and inventing one is a
23
+ * change to the module contract rather than to this module.
24
+ */
25
+ function hostOf(module, type) {
26
+ const mod = kernel.registry.get(module);
27
+ if (!mod)
28
+ return null;
29
+ const resolver = mod.resolvers?.find((r) => r.type === type);
30
+ if (!resolver)
31
+ return null;
32
+ const declared = mod.definition.objectTypes?.find((o) => o.type === type);
33
+ return { resolver, label: declared?.label ?? type, icon: declared?.icon ?? null };
34
+ }
35
+ return {
36
+ /**
37
+ * Resolve a set of references for one reader, in one pass.
38
+ *
39
+ * Grouped by module and type so a page naming twelve issues is one call into tracker rather
40
+ * than twelve — the same arrangement `macrosIn` and `referencesIn` exist for, and for the same
41
+ * reason: a document must not decide how many round trips a render makes.
42
+ *
43
+ * Anything that cannot be answered is simply absent from the map, and an absent answer is the
44
+ * empty frame. There is no path here that returns an object nobody was asked about.
45
+ */
46
+ async resolve(tx, workspaceId, refs, principal, href) {
47
+ const answers = new Map();
48
+ const parsed = refs
49
+ .map(parseRef)
50
+ .filter((r) => r !== null)
51
+ .slice(0, MAX_OBJECTS);
52
+ if (parsed.length === 0)
53
+ return answers;
54
+ const groups = new Map();
55
+ for (const ref of parsed) {
56
+ const key = `${ref.module}:${ref.type}`;
57
+ const bucket = groups.get(key);
58
+ if (bucket)
59
+ bucket.push(ref);
60
+ else
61
+ groups.set(key, [ref]);
62
+ }
63
+ for (const [key, bucket] of groups) {
64
+ const [module, type] = key.split(':');
65
+ const host = hostOf(module, type);
66
+ if (!host)
67
+ continue;
68
+ /*
69
+ * A workspace that has switched a module off has switched off everything it named. Asked
70
+ * here rather than left to the resolver, because a resolver reads its own tables and knows
71
+ * nothing about whether the customer still has the feature.
72
+ */
73
+ const enabled = await kernel.isModuleEnabled(workspaceId, module).catch(() => false);
74
+ if (!enabled)
75
+ continue;
76
+ const rows = await host.resolver
77
+ .resolve(workspaceId, bucket.map((r) => r.id), principal, kernel)
78
+ .catch(() => null);
79
+ if (!rows)
80
+ continue;
81
+ for (const [index, row] of rows.entries()) {
82
+ const ref = bucket[index];
83
+ if (!row || !ref)
84
+ continue;
85
+ // This module's own pages get this module's own rule; see the note at the top.
86
+ if (module === 'quire' &&
87
+ type === 'page' &&
88
+ !(await visiblePage(tx, workspaceId, principal, row.id)))
89
+ continue;
90
+ answers.set(ref.ref, {
91
+ label: host.label,
92
+ title: row.title,
93
+ icon: row.icon ?? host.icon,
94
+ href: href?.(ref, row.url) ?? row.url,
95
+ subtitle: row.subtitle ?? null,
96
+ });
97
+ }
98
+ }
99
+ return answers;
100
+ },
101
+ };
102
+ /** `quire.page.view` at page scope, with the ancestor chain a restriction on a section needs. */
103
+ async function visiblePage(tx, workspaceId, principal, pageId) {
104
+ const scope = await access.scopeOf(tx, workspaceId, pageId).catch(() => null);
105
+ if (!scope)
106
+ return false;
107
+ return access.canPage(principal, 'quire.page.view', workspaceId, scope);
108
+ }
109
+ }
110
+ //# sourceMappingURL=objects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"objects.js","sourceRoot":"","sources":["../../../src/server/services/objects.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,154 @@
1
+ /**
2
+ * The server fetching a URL somebody typed into a page.
3
+ *
4
+ * This is the most dangerous thing in the module, and it is worth saying why before anything else.
5
+ * Core listens on :4000 and Postgres on :5432 **on the same host as this process**, and a cloud
6
+ * instance sits behind a metadata service at 169.254.169.254 that hands out credentials to anyone
7
+ * who asks. A fetcher that will retrieve any address a user supplies is a way to make Kern read all
8
+ * of that on the attacker's behalf and hand back what it found — which is what "unfurl this link"
9
+ * would be, written the obvious way.
10
+ *
11
+ * So the defences come first and the feature second. In order, and every one of them is load-bearing:
12
+ *
13
+ * 1. **Scheme.** `http:` and `https:` only. `file:`, `gopher:` and `data:` are not addresses on
14
+ * the web, and a redirect to one is a redirect out of this function's assumptions.
15
+ * 2. **No credentials in the URL.** `http://user:pass@host/` sends those to the host, and a URL
16
+ * with them in is either an accident or a way to reach something that asked for them.
17
+ * 3. **Resolve, then judge.** The hostname is resolved and *every* address it answers with has to
18
+ * be public. `evil.example` resolving to 127.0.0.1 is the ordinary way past a name-based check,
19
+ * and a name-based check is the only kind that can run before DNS.
20
+ * 4. **Then the allow-list**, on the hostname, *after* the address check rather than instead of
21
+ * it. Order matters: an allow-list entry must never be a way *past* the address rule, so a host
22
+ * an administrator allowed which today resolves into private space is still refused.
23
+ * 5. **The connection is pinned to the addresses that were checked.** The guard is installed as
24
+ * the socket's own `lookup`, so there is no second resolution between the check and the
25
+ * connection for a DNS rebind to win — which is why this uses `node:http` rather than `fetch`,
26
+ * whose dispatcher cannot be given one without pulling undici in.
27
+ * 6. **Every redirect is a new request and gets the whole check again.** The first response is
28
+ * public and the second one is the loopback interface: that is the entire trick, and it is why
29
+ * redirects are followed here by hand rather than by the HTTP client.
30
+ * 7. **A ceiling on the body, the time and the number of hops**, because a fetcher with none is a
31
+ * way to hold a worker open on a socket that trickles bytes for ever.
32
+ *
33
+ * **The allow-list is empty by default, and every unfurl is refused until an operator sets one.**
34
+ * That is deliberate rather than unfinished. Fetching arbitrary addresses on a user's say-so is a
35
+ * capability an instance's operator should have to grant on purpose, and a self-hosted Kern sitting
36
+ * inside somebody's private network is exactly the deployment where granting it by default would be
37
+ * worst. `QUIRE_EMBED_HOSTS` is the switch; the procedure says so when it refuses, so an
38
+ * administrator reads a sentence about a setting rather than "something went wrong".
39
+ *
40
+ * What this file is **not** for: Kern's own objects. A page, an issue or a channel is named by
41
+ * reference and resolved through `objectTypes`/`resolvers` against whoever is reading — see
42
+ * `objects.ts`. Unfurling our own URL would point this fetcher at core, and would freeze a
43
+ * permission question into a stored answer.
44
+ */
45
+ import { type Kernel } from '@kernhq/kernel';
46
+ /**
47
+ * Why an address was not fetched.
48
+ *
49
+ * Named rather than free text, because the caller has to be able to tell an operator's problem
50
+ * ("nobody has allowed any host") from a writer's ("that address is not one of them") from the
51
+ * site's ("it never answered"), and because the tests assert on them: a refusal for the wrong
52
+ * reason is a check that happened to catch something the *next* URL will walk past.
53
+ */
54
+ export declare const UNFURL_REFUSALS: readonly ["no_allowlist", "not_allowed", "private_address", "unresolvable", "bad_url", "too_many_redirects", "unreachable", "not_readable"];
55
+ export type UnfurlRefusal = (typeof UNFURL_REFUSALS)[number];
56
+ export declare class UnfurlRefused extends Error {
57
+ readonly refusal: UnfurlRefusal;
58
+ constructor(refusal: UnfurlRefusal);
59
+ }
60
+ /**
61
+ * Is this address one the public internet can route to?
62
+ *
63
+ * **Anything this function cannot parse is not public.** That is the direction the default has to
64
+ * fall: an address shape nobody here anticipated is exactly the one an attacker went looking for.
65
+ */
66
+ export declare function isPublicAddress(ip: string): boolean;
67
+ /**
68
+ * `QUIRE_EMBED_HOSTS`, as a list.
69
+ *
70
+ * `example.com` allows exactly that host. `.example.com` allows it and everything under it — spelled
71
+ * with a leading dot rather than inferred, because "allow github.com" and "allow every host anybody
72
+ * can create under github.io" are different decisions and an operator should have to make the second
73
+ * one on purpose.
74
+ */
75
+ export declare function parseHostAllowlist(raw: string | null | undefined): string[];
76
+ export declare function hostAllowed(hostname: string, allowlist: readonly string[]): boolean;
77
+ export interface UnfurlPolicy {
78
+ /** Hosts an operator has allowed. Empty means every unfurl is refused. */
79
+ allowHosts: readonly string[];
80
+ /** How many redirects to follow. Each one is checked in full before it is requested. */
81
+ maxRedirects?: number;
82
+ /** The whole thing, redirects included. */
83
+ timeoutMs?: number;
84
+ /** How much of a page is read before the socket is dropped. The metadata is in the first few KB. */
85
+ maxBytes?: number;
86
+ /**
87
+ * How a hostname is resolved. Injectable so a test can prove the guard refuses a *name* that
88
+ * answers with 127.0.0.1 — which is the attack, and which cannot be arranged with real DNS.
89
+ */
90
+ resolve?: (hostname: string) => Promise<string[]>;
91
+ /** One request, no redirect following. Injectable so the redirect rule can be tested off-network. */
92
+ hop?: (url: URL, addresses: string[], policy: Required<UnfurlPolicy>) => Promise<Hop>;
93
+ }
94
+ export interface Hop {
95
+ status: number;
96
+ location: string | null;
97
+ contentType: string | null;
98
+ body: string;
99
+ }
100
+ /**
101
+ * Everything that has to be true before a request is made, in the order it has to be true in.
102
+ *
103
+ * Returns the addresses, because the connection is then pinned to exactly these — checking an
104
+ * address and then letting the socket resolve the name again is checking a different address from
105
+ * the one that gets connected to.
106
+ */
107
+ export declare function checkTarget(url: URL, policy: UnfurlPolicy): Promise<string[]>;
108
+ /**
109
+ * One HTTP request that does not follow redirects, capped in bytes and in time.
110
+ *
111
+ * `node:http` rather than `fetch`, and the reason is the `lookup` below: it is the only place a
112
+ * resolution can be pinned to addresses that have already been judged, and Node's `fetch` gives no
113
+ * way to install one without adding undici as a dependency. `agent: false` because a pooled socket
114
+ * is keyed on host and port and *not* on the lookup, so pooling would happily hand back a connection
115
+ * that was opened under someone else's guard.
116
+ */
117
+ export declare function httpHop(url: URL, addresses: string[], policy: Required<UnfurlPolicy>): Promise<Hop>;
118
+ export interface UnfurlResult {
119
+ /** The address that actually answered, after every redirect this followed. */
120
+ url: string;
121
+ title: string | null;
122
+ description: string | null;
123
+ siteName: string | null;
124
+ }
125
+ /**
126
+ * What an HTML page says about itself.
127
+ *
128
+ * Open Graph first because it is what a page puts there deliberately, `<title>` and the description
129
+ * meta as the fallback, and the hostname as the site of last resort — a card with an address and
130
+ * nothing else is still a card, and it is what the renderer draws when there is no title at all.
131
+ */
132
+ export declare function metadataFrom(html: string, url: URL): UnfurlResult;
133
+ /**
134
+ * Fetch a URL and read what it says about itself, or refuse and say which rule refused it.
135
+ *
136
+ * The redirect loop is the part worth reading. Every hop — including the first — goes through
137
+ * `checkTarget` *before* it is requested, so a 302 from a public site to `http://127.0.0.1:4000` is
138
+ * refused at the second check, with the second request never made. That is the only arrangement
139
+ * that works: an HTTP client following redirects on its own has already made the request by the
140
+ * time anything here could look at where it went.
141
+ */
142
+ export declare function unfurl(rawUrl: string, policy: UnfurlPolicy): Promise<UnfurlResult>;
143
+ export declare function quireUnfurl(kernel: Kernel): {
144
+ allowHosts: () => string[];
145
+ /**
146
+ * Unfurl one address, refusing with a sentence rather than a stack trace.
147
+ *
148
+ * Cached by the URL the writer typed. The cache is per process and small: it exists so that a
149
+ * page whose writer pastes the same link twice is one request, not so that an unfurl is free.
150
+ */
151
+ get(rawUrl: string): Promise<UnfurlResult>;
152
+ };
153
+ export type QuireUnfurl = ReturnType<typeof quireUnfurl>;
154
+ //# sourceMappingURL=unfurl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unfurl.d.ts","sourceRoot":"","sources":["../../../src/server/services/unfurl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAMH,OAAO,EAAa,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAYvD;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,6IASlB,CAAA;AACV,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAA;AAE5D,qBAAa,aAAc,SAAQ,KAAK;IAC1B,QAAQ,CAAC,OAAO,EAAE,aAAa;gBAAtB,OAAO,EAAE,aAAa;CAI5C;AAgHD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAOnD;AAMD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAK3E;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CASnF;AAMD,MAAM,WAAW,YAAY;IAC3B,0EAA0E;IAC1E,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;IAC7B,wFAAwF;IACxF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,oGAAoG;IACpG,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IACjD,qGAAqG;IACrG,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;CACtF;AAED,MAAM,WAAW,GAAG;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,IAAI,EAAE,MAAM,CAAA;CACb;AAcD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAmBnF;AAMD;;;;;;;;GAQG;AACH,wBAAsB,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAsFzG;AAmED,MAAM,WAAW,YAAY;IAC3B,8EAA8E;IAC9E,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,YAAY,CAgBjE;AAMD;;;;;;;;GAQG;AACH,wBAAsB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CA0CxF;AAkCD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM;;IAYtC;;;;;OAKG;gBACe,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;EAwBnD;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAA"}