@geekity/cms 0.5.0 → 0.7.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/README.md +78 -24
- package/admin/pages/documents/editor.njk +13 -1
- package/admin/pages/navigation/menus.njk +8 -5
- package/admin/pages/users/edit.njk +25 -2
- package/admin/static/admin.css +18 -3
- package/dist/admin/accounts.d.ts +10 -0
- package/dist/admin/accounts.d.ts.map +1 -1
- package/dist/admin/accounts.js +15 -3
- package/dist/admin/accounts.js.map +1 -1
- package/dist/admin/comments.d.ts.map +1 -1
- package/dist/admin/comments.js +2 -1
- package/dist/admin/comments.js.map +1 -1
- package/dist/admin/documents.d.ts +3 -0
- package/dist/admin/documents.d.ts.map +1 -1
- package/dist/admin/documents.js +51 -11
- package/dist/admin/documents.js.map +1 -1
- package/dist/admin/federation.d.ts.map +1 -1
- package/dist/admin/federation.js +3 -2
- package/dist/admin/federation.js.map +1 -1
- package/dist/admin/preview.js +3 -0
- package/dist/admin/preview.js.map +1 -1
- package/dist/admin/routes.d.ts.map +1 -1
- package/dist/admin/routes.js +2 -1
- package/dist/admin/routes.js.map +1 -1
- package/dist/admin/users.d.ts +24 -0
- package/dist/admin/users.d.ts.map +1 -1
- package/dist/admin/users.js +102 -30
- package/dist/admin/users.js.map +1 -1
- package/dist/comments/submission.d.ts.map +1 -1
- package/dist/comments/submission.js +2 -1
- package/dist/comments/submission.js.map +1 -1
- package/dist/config.d.ts +10 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/content/document.d.ts +18 -7
- package/dist/content/document.d.ts.map +1 -1
- package/dist/content/document.js +1 -0
- package/dist/content/document.js.map +1 -1
- package/dist/content/index.d.ts +2 -0
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +1 -0
- package/dist/content/index.js.map +1 -1
- package/dist/content/parser.d.ts.map +1 -1
- package/dist/content/parser.js +19 -1
- package/dist/content/parser.js.map +1 -1
- package/dist/content/post-type.d.ts +48 -0
- package/dist/content/post-type.d.ts.map +1 -0
- package/dist/content/post-type.js +79 -0
- package/dist/content/post-type.js.map +1 -0
- package/dist/content/store.d.ts.map +1 -1
- package/dist/content/store.js +17 -2
- package/dist/content/store.js.map +1 -1
- package/dist/content/sync.d.ts.map +1 -1
- package/dist/content/sync.js +6 -0
- package/dist/content/sync.js.map +1 -1
- package/dist/content/writer.d.ts +1 -1
- package/dist/content/writer.d.ts.map +1 -1
- package/dist/content/writer.js +9 -2
- package/dist/content/writer.js.map +1 -1
- package/dist/federation/article.d.ts +18 -9
- package/dist/federation/article.d.ts.map +1 -1
- package/dist/federation/article.js +87 -17
- package/dist/federation/article.js.map +1 -1
- package/dist/federation/index.d.ts +1 -1
- package/dist/federation/index.d.ts.map +1 -1
- package/dist/federation/index.js +1 -1
- package/dist/federation/index.js.map +1 -1
- package/dist/federation/mount.d.ts.map +1 -1
- package/dist/federation/mount.js +19 -6
- package/dist/federation/mount.js.map +1 -1
- package/dist/index.d.ts +13 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -4
- package/dist/index.js.map +1 -1
- package/dist/notifications/comments.d.ts.map +1 -1
- package/dist/notifications/comments.js +2 -1
- package/dist/notifications/comments.js.map +1 -1
- package/dist/notifications/digest.d.ts.map +1 -1
- package/dist/notifications/digest.js +2 -1
- package/dist/notifications/digest.js.map +1 -1
- package/dist/web/archive.d.ts +1 -1
- package/dist/web/archive.d.ts.map +1 -1
- package/dist/web/archive.js +2 -1
- package/dist/web/archive.js.map +1 -1
- package/dist/web/authors.d.ts +15 -1
- package/dist/web/authors.d.ts.map +1 -1
- package/dist/web/authors.js +9 -1
- package/dist/web/authors.js.map +1 -1
- package/dist/web/context.d.ts +22 -2
- package/dist/web/context.d.ts.map +1 -1
- package/dist/web/context.js +5 -0
- package/dist/web/context.js.map +1 -1
- package/dist/web/conversation.d.ts.map +1 -1
- package/dist/web/conversation.js +2 -1
- package/dist/web/conversation.js.map +1 -1
- package/dist/web/feed-atom.d.ts.map +1 -1
- package/dist/web/feed-atom.js +14 -2
- package/dist/web/feed-atom.js.map +1 -1
- package/dist/web/feed-item.d.ts +21 -7
- package/dist/web/feed-item.d.ts.map +1 -1
- package/dist/web/feed-item.js +13 -6
- package/dist/web/feed-item.js.map +1 -1
- package/dist/web/feed-json.d.ts +13 -2
- package/dist/web/feed-json.d.ts.map +1 -1
- package/dist/web/feed-json.js +3 -1
- package/dist/web/feed-json.js.map +1 -1
- package/dist/web/feed-rss.d.ts.map +1 -1
- package/dist/web/feed-rss.js +2 -2
- package/dist/web/feed-rss.js.map +1 -1
- package/dist/web/feed-xml.d.ts +2 -0
- package/dist/web/feed-xml.d.ts.map +1 -1
- package/dist/web/feed-xml.js +2 -0
- package/dist/web/feed-xml.js.map +1 -1
- package/dist/web/feeds.d.ts +1 -1
- package/dist/web/feeds.d.ts.map +1 -1
- package/dist/web/feeds.js.map +1 -1
- package/dist/web/index.d.ts +4 -4
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js +1 -1
- package/dist/web/index.js.map +1 -1
- package/dist/web/navigation.d.ts +106 -28
- package/dist/web/navigation.d.ts.map +1 -1
- package/dist/web/navigation.js +135 -49
- package/dist/web/navigation.js.map +1 -1
- package/dist/web/render.d.ts +9 -0
- package/dist/web/render.d.ts.map +1 -1
- package/dist/web/render.js +19 -1
- package/dist/web/render.js.map +1 -1
- package/dist/web/routes.d.ts.map +1 -1
- package/dist/web/routes.js +2 -1
- package/dist/web/routes.js.map +1 -1
- package/dist/webmention/index.d.ts +6 -0
- package/dist/webmention/index.d.ts.map +1 -1
- package/dist/webmention/index.js +3 -0
- package/dist/webmention/index.js.map +1 -1
- package/dist/webmention/links.d.ts +5 -0
- package/dist/webmention/links.d.ts.map +1 -1
- package/dist/webmention/links.js +14 -7
- package/dist/webmention/links.js.map +1 -1
- package/dist/webmention/microformats.d.ts +21 -0
- package/dist/webmention/microformats.d.ts.map +1 -1
- package/dist/webmention/microformats.js +35 -5
- package/dist/webmention/microformats.js.map +1 -1
- package/dist/webmention/public-address.d.ts +30 -0
- package/dist/webmention/public-address.d.ts.map +1 -0
- package/dist/webmention/public-address.js +71 -0
- package/dist/webmention/public-address.js.map +1 -0
- package/dist/webmention/receive.d.ts.map +1 -1
- package/dist/webmention/receive.js +1 -23
- package/dist/webmention/receive.js.map +1 -1
- package/dist/webmention/reply-context.d.ts +67 -0
- package/dist/webmention/reply-context.d.ts.map +1 -0
- package/dist/webmention/reply-context.js +189 -0
- package/dist/webmention/reply-context.js.map +1 -0
- package/dist/webmention/reply-contexts.d.ts +50 -0
- package/dist/webmention/reply-contexts.d.ts.map +1 -0
- package/dist/webmention/reply-contexts.js +163 -0
- package/dist/webmention/reply-contexts.js.map +1 -0
- package/dist/webmention/service.d.ts.map +1 -1
- package/dist/webmention/service.js +9 -2
- package/dist/webmention/service.js.map +1 -1
- package/package.json +10 -10
- package/themes/default/README.md +25 -10
- package/themes/default/layouts/base.njk +5 -3
- package/themes/default/layouts/post.njk +8 -0
- package/themes/default/layouts/search.njk +4 -2
- package/themes/default/partials/bio.njk +5 -1
- package/themes/default/partials/menu.njk +6 -4
- package/themes/default/partials/post-list.njk +17 -5
- package/themes/default/partials/reply-context.njk +29 -0
- package/themes/default/static/style.css +28 -10
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { lookup as dnsLookup } from 'node:dns/promises';
|
|
2
|
+
import { BlockList, isIP } from 'node:net';
|
|
3
|
+
/** Resolve a name through the system resolver, every address it has. */
|
|
4
|
+
export const systemHostLookup = async (hostname) => (await dnsLookup(hostname, { all: true })).map((found) => found.address);
|
|
5
|
+
/** Every range that is not the public internet. */
|
|
6
|
+
const PRIVATE_RANGES = new BlockList();
|
|
7
|
+
for (const [network, prefix] of [
|
|
8
|
+
['0.0.0.0', 8],
|
|
9
|
+
['10.0.0.0', 8],
|
|
10
|
+
['100.64.0.0', 10],
|
|
11
|
+
['127.0.0.0', 8],
|
|
12
|
+
['169.254.0.0', 16],
|
|
13
|
+
['172.16.0.0', 12],
|
|
14
|
+
['192.0.0.0', 24],
|
|
15
|
+
['192.168.0.0', 16],
|
|
16
|
+
['198.18.0.0', 15],
|
|
17
|
+
['224.0.0.0', 4],
|
|
18
|
+
['240.0.0.0', 4],
|
|
19
|
+
]) {
|
|
20
|
+
PRIVATE_RANGES.addSubnet(network, prefix, 'ipv4');
|
|
21
|
+
}
|
|
22
|
+
for (const [network, prefix] of [
|
|
23
|
+
['::', 128],
|
|
24
|
+
['::1', 128],
|
|
25
|
+
['fc00::', 7],
|
|
26
|
+
['fe80::', 10],
|
|
27
|
+
['ff00::', 8],
|
|
28
|
+
]) {
|
|
29
|
+
PRIVATE_RANGES.addSubnet(network, prefix, 'ipv6');
|
|
30
|
+
}
|
|
31
|
+
/** Whether an IP address is on a loopback, private, link-local or reserved range. */
|
|
32
|
+
function isPrivateAddress(address) {
|
|
33
|
+
const mapped = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/i.exec(address)?.[1];
|
|
34
|
+
if (mapped !== undefined)
|
|
35
|
+
return isPrivateAddress(mapped);
|
|
36
|
+
const version = isIP(address);
|
|
37
|
+
if (version === 0)
|
|
38
|
+
return true;
|
|
39
|
+
return PRIVATE_RANGES.check(address, version === 4 ? 'ipv4' : 'ipv6');
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Whether a hostname, as written, is one only this network can see: a
|
|
43
|
+
* `localhost` or `.local` name, or an IP literal on a private range. A name
|
|
44
|
+
* that merely resolves to one is {@link publicHost}'s to catch.
|
|
45
|
+
*/
|
|
46
|
+
export function isPrivateHost(hostname) {
|
|
47
|
+
const host = hostname.toLowerCase().replace(/^\[|\]$/g, '');
|
|
48
|
+
if (host === 'localhost' || host.endsWith('.localhost') || host.endsWith('.local'))
|
|
49
|
+
return true;
|
|
50
|
+
return isIP(host) !== 0 && isPrivateAddress(host);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Whether a host is on the public internet: not private as written, and every
|
|
54
|
+
* address it resolves to public. A name that does not resolve is not.
|
|
55
|
+
*/
|
|
56
|
+
export async function publicHost(hostname, lookup) {
|
|
57
|
+
if (isPrivateHost(hostname))
|
|
58
|
+
return false;
|
|
59
|
+
const host = hostname.replace(/^\[|\]$/g, '');
|
|
60
|
+
if (isIP(host) !== 0)
|
|
61
|
+
return true;
|
|
62
|
+
let addresses;
|
|
63
|
+
try {
|
|
64
|
+
addresses = await lookup(host);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return addresses.length > 0 && !addresses.some(isPrivateAddress);
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=public-address.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-address.js","sourceRoot":"","sources":["../../src/webmention/public-address.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"receive.d.ts","sourceRoot":"","sources":["../../src/webmention/receive.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAmB,MAAM,wBAAwB,CAAC;AAC9F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"receive.d.ts","sourceRoot":"","sources":["../../src/webmention/receive.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { deleteComment, heldWebmention, intakeComment } from '../comments/record
|
|
|
2
2
|
import { sanitizeCommentHtml } from '../web/sanitize.js';
|
|
3
3
|
import { readCapped, WEBMENTION_USER_AGENT } from './discovery.js';
|
|
4
4
|
import { linksTo, sourceEntry } from './microformats.js';
|
|
5
|
+
import { isPrivateHost } from './public-address.js';
|
|
5
6
|
/**
|
|
6
7
|
* Taking a webmention somebody sent this site.
|
|
7
8
|
*
|
|
@@ -217,29 +218,6 @@ function webUrl(value) {
|
|
|
217
218
|
return undefined;
|
|
218
219
|
return url;
|
|
219
220
|
}
|
|
220
|
-
/** Whether a hostname is one only this network can see. */
|
|
221
|
-
function isPrivateHost(hostname) {
|
|
222
|
-
const host = hostname.toLowerCase().replace(/^\[|\]$/g, '');
|
|
223
|
-
if (host === 'localhost' || host.endsWith('.localhost') || host.endsWith('.local'))
|
|
224
|
-
return true;
|
|
225
|
-
if (host === '::1' || host === '0.0.0.0')
|
|
226
|
-
return true;
|
|
227
|
-
if (host.startsWith('fc') || host.startsWith('fd') || host.startsWith('fe80:'))
|
|
228
|
-
return true;
|
|
229
|
-
const parts = host.split('.');
|
|
230
|
-
if (parts.length !== 4 || parts.some((part) => !/^\d{1,3}$/.test(part)))
|
|
231
|
-
return false;
|
|
232
|
-
const [a = 0, b = 0] = parts.map(Number);
|
|
233
|
-
if (a === 127 || a === 10 || a === 0)
|
|
234
|
-
return true;
|
|
235
|
-
if (a === 192 && b === 168)
|
|
236
|
-
return true;
|
|
237
|
-
if (a === 169 && b === 254)
|
|
238
|
-
return true;
|
|
239
|
-
if (a === 172 && b >= 16 && b <= 31)
|
|
240
|
-
return true;
|
|
241
|
-
return false;
|
|
242
|
-
}
|
|
243
221
|
/** The host a source is on, for a page that never says who wrote it. */
|
|
244
222
|
function hostOf(source) {
|
|
245
223
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"receive.js","sourceRoot":"","sources":["../../src/webmention/receive.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAItF,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"receive.js","sourceRoot":"","sources":["../../src/webmention/receive.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { HostLookup } from './public-address.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Reply context: what a reply shows of the post it answers (TASK-123).
|
|
4
|
+
*
|
|
5
|
+
* The post is on somebody else's site, so this is the one place the CMS reads
|
|
6
|
+
* a stranger's page on an author's behalf. It happens when a reply is saved or
|
|
7
|
+
* synced, never while a page is served, and what it finds is kept in a file
|
|
8
|
+
* (decision-19). Everything here fails soft: a target that cannot be read is a
|
|
9
|
+
* reply with a bare link, never a save that fails.
|
|
10
|
+
*/
|
|
11
|
+
/** How long a target is given to answer, body included. */
|
|
12
|
+
export declare const REPLY_CONTEXT_TIMEOUT_MS = 10000;
|
|
13
|
+
/** The most of a target page that is read. A bigger page is not read at all. */
|
|
14
|
+
export declare const REPLY_CONTEXT_MAX_BYTES = 1000000;
|
|
15
|
+
/** What a reply shows of the post it answers. */
|
|
16
|
+
export interface ReplyContext {
|
|
17
|
+
/** The post answered: the reply's own `in-reply-to`, whatever it redirected to. */
|
|
18
|
+
readonly url: string;
|
|
19
|
+
/** Its title, when it has one of its own; a note's name is its text. */
|
|
20
|
+
readonly name?: string;
|
|
21
|
+
/** A short excerpt of what it says, or the page's description. */
|
|
22
|
+
readonly text?: string;
|
|
23
|
+
/** Who wrote it, with their page when that is an http(s) URL. */
|
|
24
|
+
readonly author?: {
|
|
25
|
+
readonly name: string;
|
|
26
|
+
readonly url?: string;
|
|
27
|
+
};
|
|
28
|
+
/** When it says it was published, as an ISO 8601 instant. */
|
|
29
|
+
readonly published?: string;
|
|
30
|
+
}
|
|
31
|
+
/** What fetching one target came to. */
|
|
32
|
+
export type ReplyContextFetch = {
|
|
33
|
+
readonly ok: true;
|
|
34
|
+
readonly context: ReplyContext;
|
|
35
|
+
} | {
|
|
36
|
+
readonly ok: false;
|
|
37
|
+
readonly reason: string;
|
|
38
|
+
};
|
|
39
|
+
/** What {@link fetchReplyContext} needs. */
|
|
40
|
+
export interface FetchReplyContextOptions {
|
|
41
|
+
/** How host names are resolved before they are trusted. */
|
|
42
|
+
readonly lookup: HostLookup;
|
|
43
|
+
/** Defaults to {@link REPLY_CONTEXT_TIMEOUT_MS}. */
|
|
44
|
+
readonly timeoutMs?: number | undefined;
|
|
45
|
+
/** Defaults to {@link REPLY_CONTEXT_MAX_BYTES}. */
|
|
46
|
+
readonly maxBytes?: number | undefined;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Fetch a reply's target and read what it says about itself.
|
|
50
|
+
*
|
|
51
|
+
* Only http and https, only public hosts (every redirect hop is checked, and a
|
|
52
|
+
* name is refused when any address it resolves to is private), one timeout
|
|
53
|
+
* over the whole exchange, and no page over the byte limit. Nothing throws.
|
|
54
|
+
*/
|
|
55
|
+
export declare function fetchReplyContext(target: string, options: FetchReplyContextOptions): Promise<ReplyContextFetch>;
|
|
56
|
+
/**
|
|
57
|
+
* What a target page says about itself, or `undefined` when it says nothing a
|
|
58
|
+
* preview could show.
|
|
59
|
+
*
|
|
60
|
+
* The first `h-entry` when there is one: its name when it has one of its own
|
|
61
|
+
* (the test Post Type Discovery uses), an excerpt of its text, its author and
|
|
62
|
+
* its date. A page with no `h-entry` is described by its `<title>` and its
|
|
63
|
+
* description metadata. Everything comes out as plain text; the theme escapes
|
|
64
|
+
* it like any other string.
|
|
65
|
+
*/
|
|
66
|
+
export declare function readReplyContext(html: string, target: string, base?: string): ReplyContext | undefined;
|
|
67
|
+
//# sourceMappingURL=reply-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reply-context.d.ts","sourceRoot":"","sources":["../../src/webmention/reply-context.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD;;;;;;;;GAQG;AAEH,2DAA2D;AAC3D,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAE/C,gFAAgF;AAChF,eAAO,MAAM,uBAAuB,UAAY,CAAC;AAWjD,iDAAiD;AACjD,MAAM,WAAW,YAAY;IAC3B,mFAAmF;IACnF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,kEAAkE;IAClE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,6DAA6D;IAC7D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,wCAAwC;AACxC,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpD,4CAA4C;AAC5C,MAAM,WAAW,wBAAwB;IACvC,2DAA2D;IAC3D,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,oDAAoD;IACpD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,iBAAiB,CAAC,CA+C5B;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,MAAe,GACpB,YAAY,GAAG,SAAS,CA6B1B"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { discoverPostType } from '../content/post-type.js';
|
|
2
|
+
import { WEBMENTION_USER_AGENT } from './discovery.js';
|
|
3
|
+
import { elementsIn, parseHtml, textOf } from './html.js';
|
|
4
|
+
import { citedEntry } from './microformats.js';
|
|
5
|
+
import { publicHost } from './public-address.js';
|
|
6
|
+
/**
|
|
7
|
+
* Reply context: what a reply shows of the post it answers (TASK-123).
|
|
8
|
+
*
|
|
9
|
+
* The post is on somebody else's site, so this is the one place the CMS reads
|
|
10
|
+
* a stranger's page on an author's behalf. It happens when a reply is saved or
|
|
11
|
+
* synced, never while a page is served, and what it finds is kept in a file
|
|
12
|
+
* (decision-19). Everything here fails soft: a target that cannot be read is a
|
|
13
|
+
* reply with a bare link, never a save that fails.
|
|
14
|
+
*/
|
|
15
|
+
/** How long a target is given to answer, body included. */
|
|
16
|
+
export const REPLY_CONTEXT_TIMEOUT_MS = 10_000;
|
|
17
|
+
/** The most of a target page that is read. A bigger page is not read at all. */
|
|
18
|
+
export const REPLY_CONTEXT_MAX_BYTES = 1_000_000;
|
|
19
|
+
/** How many redirects are followed, each one checked like the first. */
|
|
20
|
+
const MAX_REDIRECTS = 5;
|
|
21
|
+
/** How many words of a target's text a preview keeps. */
|
|
22
|
+
const EXCERPT_WORDS = 40;
|
|
23
|
+
/** And how many characters, for a text with few spaces in it. */
|
|
24
|
+
const EXCERPT_CHARACTERS = 300;
|
|
25
|
+
/**
|
|
26
|
+
* Fetch a reply's target and read what it says about itself.
|
|
27
|
+
*
|
|
28
|
+
* Only http and https, only public hosts (every redirect hop is checked, and a
|
|
29
|
+
* name is refused when any address it resolves to is private), one timeout
|
|
30
|
+
* over the whole exchange, and no page over the byte limit. Nothing throws.
|
|
31
|
+
*/
|
|
32
|
+
export async function fetchReplyContext(target, options) {
|
|
33
|
+
const maxBytes = options.maxBytes ?? REPLY_CONTEXT_MAX_BYTES;
|
|
34
|
+
const signal = AbortSignal.timeout(options.timeoutMs ?? REPLY_CONTEXT_TIMEOUT_MS);
|
|
35
|
+
let at = target;
|
|
36
|
+
try {
|
|
37
|
+
for (let hop = 0;; hop += 1) {
|
|
38
|
+
const url = webUrl(at);
|
|
39
|
+
if (url === undefined)
|
|
40
|
+
return refuse('not an http or https URL');
|
|
41
|
+
if (!(await publicHost(url.hostname, options.lookup))) {
|
|
42
|
+
return refuse('not a public address');
|
|
43
|
+
}
|
|
44
|
+
const response = await fetch(url, {
|
|
45
|
+
headers: { accept: 'text/html, */*;q=0.8', 'user-agent': WEBMENTION_USER_AGENT },
|
|
46
|
+
redirect: 'manual',
|
|
47
|
+
signal,
|
|
48
|
+
});
|
|
49
|
+
const location = response.headers.get('location');
|
|
50
|
+
if (response.status >= 300 && response.status < 400 && location !== null) {
|
|
51
|
+
await response.body?.cancel();
|
|
52
|
+
if (hop === MAX_REDIRECTS)
|
|
53
|
+
return refuse('too many redirects');
|
|
54
|
+
at = new URL(location, url).href;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (!response.ok) {
|
|
58
|
+
await response.body?.cancel();
|
|
59
|
+
return refuse(`answered ${String(response.status)}`);
|
|
60
|
+
}
|
|
61
|
+
const type = response.headers.get('content-type') ?? '';
|
|
62
|
+
if (!/^\s*(text\/html|application\/xhtml\+xml)/i.test(type)) {
|
|
63
|
+
await response.body?.cancel();
|
|
64
|
+
return refuse('not an HTML page');
|
|
65
|
+
}
|
|
66
|
+
const body = await readWithin(response, maxBytes);
|
|
67
|
+
if (body === undefined)
|
|
68
|
+
return refuse(`larger than ${String(maxBytes)} bytes`);
|
|
69
|
+
const context = readReplyContext(body, target, url.href);
|
|
70
|
+
return context === undefined ? refuse('nothing to show') : { ok: true, context };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch (thrown) {
|
|
74
|
+
return refuse(thrown instanceof Error ? thrown.message : String(thrown));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* What a target page says about itself, or `undefined` when it says nothing a
|
|
79
|
+
* preview could show.
|
|
80
|
+
*
|
|
81
|
+
* The first `h-entry` when there is one: its name when it has one of its own
|
|
82
|
+
* (the test Post Type Discovery uses), an excerpt of its text, its author and
|
|
83
|
+
* its date. A page with no `h-entry` is described by its `<title>` and its
|
|
84
|
+
* description metadata. Everything comes out as plain text; the theme escapes
|
|
85
|
+
* it like any other string.
|
|
86
|
+
*/
|
|
87
|
+
export function readReplyContext(html, target, base = target) {
|
|
88
|
+
const root = parseHtml(html);
|
|
89
|
+
const entry = citedEntry(root, base);
|
|
90
|
+
if (entry !== undefined) {
|
|
91
|
+
const named = discoverPostType({ name: entry.name, content: entry.text }) === 'article';
|
|
92
|
+
const text = excerpt(entry.text);
|
|
93
|
+
const authorUrl = entry.author?.url === null ? undefined : webUrl(entry.author?.url ?? '');
|
|
94
|
+
return {
|
|
95
|
+
url: target,
|
|
96
|
+
...(named ? { name: entry.name } : {}),
|
|
97
|
+
...(text === '' ? {} : { text }),
|
|
98
|
+
...(entry.author === undefined
|
|
99
|
+
? {}
|
|
100
|
+
: {
|
|
101
|
+
author: {
|
|
102
|
+
name: entry.author.name,
|
|
103
|
+
...(authorUrl === undefined ? {} : { url: authorUrl.href }),
|
|
104
|
+
},
|
|
105
|
+
}),
|
|
106
|
+
...(entry.published === null ? {} : { published: entry.published }),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const name = titleOf(root) || metaOf(root, 'og:title');
|
|
110
|
+
const text = excerpt(metaOf(root, 'description') || metaOf(root, 'og:description'));
|
|
111
|
+
if (name === '' && text === '')
|
|
112
|
+
return undefined;
|
|
113
|
+
return { url: target, ...(name === '' ? {} : { name }), ...(text === '' ? {} : { text }) };
|
|
114
|
+
}
|
|
115
|
+
/** A response body when it is no bigger than the limit, else `undefined`. */
|
|
116
|
+
async function readWithin(response, maxBytes) {
|
|
117
|
+
const declared = Number(response.headers.get('content-length') ?? '0');
|
|
118
|
+
if (declared > maxBytes) {
|
|
119
|
+
await response.body?.cancel();
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
const body = response.body;
|
|
123
|
+
if (body === null)
|
|
124
|
+
return '';
|
|
125
|
+
const reader = body.getReader();
|
|
126
|
+
const decoder = new TextDecoder();
|
|
127
|
+
const chunks = [];
|
|
128
|
+
let read = 0;
|
|
129
|
+
for (;;) {
|
|
130
|
+
const chunk = await reader.read();
|
|
131
|
+
if (chunk.done)
|
|
132
|
+
break;
|
|
133
|
+
const value = chunk.value;
|
|
134
|
+
read += value.length;
|
|
135
|
+
if (read > maxBytes) {
|
|
136
|
+
await reader.cancel();
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
chunks.push(decoder.decode(value, { stream: true }));
|
|
140
|
+
}
|
|
141
|
+
chunks.push(decoder.decode());
|
|
142
|
+
return chunks.join('');
|
|
143
|
+
}
|
|
144
|
+
/** The page's `<title>`, or empty. */
|
|
145
|
+
function titleOf(root) {
|
|
146
|
+
for (const element of elementsIn(root)) {
|
|
147
|
+
if (element.name === 'title')
|
|
148
|
+
return textOf(element);
|
|
149
|
+
}
|
|
150
|
+
return '';
|
|
151
|
+
}
|
|
152
|
+
/** The `content` of a `<meta name>` or `<meta property>`, or empty. */
|
|
153
|
+
function metaOf(root, key) {
|
|
154
|
+
for (const element of elementsIn(root)) {
|
|
155
|
+
if (element.name !== 'meta')
|
|
156
|
+
continue;
|
|
157
|
+
const names = [element.attributes['name'], element.attributes['property']];
|
|
158
|
+
if (!names.some((name) => name?.toLowerCase() === key))
|
|
159
|
+
continue;
|
|
160
|
+
return (element.attributes['content'] ?? '').replace(/\s+/g, ' ').trim();
|
|
161
|
+
}
|
|
162
|
+
return '';
|
|
163
|
+
}
|
|
164
|
+
/** The first words of a text, marked as cut when they are. */
|
|
165
|
+
function excerpt(text) {
|
|
166
|
+
const normalized = text.replace(/\s+/g, ' ').trim();
|
|
167
|
+
const words = normalized.split(' ');
|
|
168
|
+
let cut = words.length > EXCERPT_WORDS ? words.slice(0, EXCERPT_WORDS).join(' ') : normalized;
|
|
169
|
+
if (cut.length > EXCERPT_CHARACTERS)
|
|
170
|
+
cut = cut.slice(0, EXCERPT_CHARACTERS).trimEnd();
|
|
171
|
+
return cut === normalized ? normalized : `${cut} …`;
|
|
172
|
+
}
|
|
173
|
+
/** A URL, when it is an http or https one with a host. */
|
|
174
|
+
function webUrl(value) {
|
|
175
|
+
let url;
|
|
176
|
+
try {
|
|
177
|
+
url = new URL(value);
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:')
|
|
183
|
+
return undefined;
|
|
184
|
+
return url.hostname === '' ? undefined : url;
|
|
185
|
+
}
|
|
186
|
+
function refuse(reason) {
|
|
187
|
+
return { ok: false, reason };
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=reply-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reply-context.js","sourceRoot":"","sources":["../../src/webmention/reply-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ContentStore } from '../content/store.ts';
|
|
2
|
+
import type { DocumentChange } from '../content/sync.ts';
|
|
3
|
+
import type { HostLookup } from './public-address.ts';
|
|
4
|
+
import type { ReplyContext } from './reply-context.ts';
|
|
5
|
+
/**
|
|
6
|
+
* Where the fetched reply contexts are kept, relative to the content directory:
|
|
7
|
+
* one JSON object keyed by the URL replied to (decision-19). Eleventy reads it
|
|
8
|
+
* as the `replyContexts` global.
|
|
9
|
+
*/
|
|
10
|
+
export declare const REPLY_CONTEXTS_FILE = "_data/replyContexts.json";
|
|
11
|
+
/** Where the service reports a target it could not read. */
|
|
12
|
+
export interface ReplyContextLogger {
|
|
13
|
+
warn(message: string): void;
|
|
14
|
+
}
|
|
15
|
+
/** What {@link createReplyContextService} needs. */
|
|
16
|
+
export interface CreateReplyContextServiceOptions {
|
|
17
|
+
/** The index, asked which targets are still replied to. */
|
|
18
|
+
readonly store: ContentStore;
|
|
19
|
+
/** Where the file lives. */
|
|
20
|
+
readonly contentDir: string;
|
|
21
|
+
/** How host names are resolved before a target is fetched. */
|
|
22
|
+
readonly lookup: HostLookup;
|
|
23
|
+
/** Defaults to `console`. */
|
|
24
|
+
readonly logger?: ReplyContextLogger | undefined;
|
|
25
|
+
}
|
|
26
|
+
/** Keeps the stored reply contexts in step with the posts that reply. */
|
|
27
|
+
export interface ReplyContextService {
|
|
28
|
+
/**
|
|
29
|
+
* Consider one index change. A reply whose target is new, or has nothing
|
|
30
|
+
* stored, has its target fetched; a target no post replies to any more is
|
|
31
|
+
* forgotten. Returns at once: the work is queued, so a save never waits on
|
|
32
|
+
* a stranger's server.
|
|
33
|
+
*/
|
|
34
|
+
handle(change: DocumentChange): void;
|
|
35
|
+
/**
|
|
36
|
+
* Fetch every target a live post replies to that the file holds nothing
|
|
37
|
+
* for. Run when the site starts serving, because a scan of an index that is
|
|
38
|
+
* already up to date reports no change: a site upgraded to reply contexts,
|
|
39
|
+
* or one whose file was removed, would otherwise wait for each reply to be
|
|
40
|
+
* edited. Queued like {@link ReplyContextService.handle}.
|
|
41
|
+
*/
|
|
42
|
+
catchUp(): void;
|
|
43
|
+
/** The stored context for a target, from the file. Never touches the network. */
|
|
44
|
+
read(target: string): ReplyContext | undefined;
|
|
45
|
+
/** Resolve once everything queued has finished, however it finished. */
|
|
46
|
+
settled(): Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
/** Build the reply context service for one site. */
|
|
49
|
+
export declare function createReplyContextService(options: CreateReplyContextServiceOptions): ReplyContextService;
|
|
50
|
+
//# sourceMappingURL=reply-contexts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reply-contexts.d.ts","sourceRoot":"","sources":["../../src/webmention/reply-contexts.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,6BAA6B,CAAC;AAE9D,4DAA4D;AAC5D,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,oDAAoD;AACpD,MAAM,WAAW,gCAAgC;IAC/C,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,4BAA4B;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,6BAA6B;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;CAClD;AAED,yEAAyE;AACzE,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IACrC;;;;;;OAMG;IACH,OAAO,IAAI,IAAI,CAAC;IAChB,iFAAiF;IACjF,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;IAC/C,wEAAwE;IACxE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,oDAAoD;AACpD,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,gCAAgC,GACxC,mBAAmB,CA8FrB"}
|