@geekity/cms 0.23.0 → 0.25.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 +96 -160
- package/admin/pages/documents/editor.njk +45 -0
- package/admin/pages/federation/settings.njk +1 -59
- package/admin/pages/plugins/installed.njk +113 -0
- package/admin/pages/plugins/screen.njk +129 -0
- package/admin/static/admin.css +136 -4
- package/admin/static/editor-actions.js +192 -0
- package/admin/static/editor.js +1 -1
- package/dist/admin/accounts.d.ts +18 -39
- package/dist/admin/accounts.d.ts.map +1 -1
- package/dist/admin/accounts.js +19 -48
- package/dist/admin/accounts.js.map +1 -1
- package/dist/admin/documents.d.ts +5 -0
- package/dist/admin/documents.d.ts.map +1 -1
- package/dist/admin/documents.js +17 -8
- package/dist/admin/documents.js.map +1 -1
- package/dist/admin/editor-actions.d.ts +35 -0
- package/dist/admin/editor-actions.d.ts.map +1 -0
- package/dist/admin/editor-actions.js +168 -0
- package/dist/admin/editor-actions.js.map +1 -0
- package/dist/admin/federation.d.ts +4 -5
- package/dist/admin/federation.d.ts.map +1 -1
- package/dist/admin/federation.js +4 -5
- package/dist/admin/federation.js.map +1 -1
- package/dist/admin/index.d.ts +1 -1
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/menu.d.ts +1 -1
- package/dist/admin/menu.d.ts.map +1 -1
- package/dist/admin/menu.js +10 -3
- package/dist/admin/menu.js.map +1 -1
- package/dist/admin/plugins.d.ts +24 -0
- package/dist/admin/plugins.d.ts.map +1 -0
- package/dist/admin/plugins.js +312 -0
- package/dist/admin/plugins.js.map +1 -0
- package/dist/admin/routes.d.ts.map +1 -1
- package/dist/admin/routes.js +5 -1
- package/dist/admin/routes.js.map +1 -1
- package/dist/admin/settings-federation.d.ts +0 -25
- package/dist/admin/settings-federation.d.ts.map +1 -1
- package/dist/admin/settings-federation.js +1 -54
- package/dist/admin/settings-federation.js.map +1 -1
- package/dist/admin/settings.d.ts +2 -14
- package/dist/admin/settings.d.ts.map +1 -1
- package/dist/admin/settings.js +1 -21
- package/dist/admin/settings.js.map +1 -1
- package/dist/admin/store.d.ts +8 -1
- package/dist/admin/store.d.ts.map +1 -1
- package/dist/admin/store.js +7 -3
- package/dist/admin/store.js.map +1 -1
- package/dist/admin/templates.d.ts +2 -0
- package/dist/admin/templates.d.ts.map +1 -1
- package/dist/admin/templates.js +2 -0
- package/dist/admin/templates.js.map +1 -1
- package/dist/cli.d.ts +2 -3
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +278 -212
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +20 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +6 -0
- package/dist/config.js.map +1 -1
- package/dist/content/store.d.ts +6 -0
- package/dist/content/store.d.ts.map +1 -1
- package/dist/content/store.js +3 -0
- package/dist/content/store.js.map +1 -1
- package/dist/drain.d.ts +28 -0
- package/dist/drain.d.ts.map +1 -0
- package/dist/drain.js +106 -0
- package/dist/drain.js.map +1 -0
- package/dist/env.d.ts +11 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/federation/federation.d.ts +4 -2
- package/dist/federation/federation.d.ts.map +1 -1
- package/dist/federation/federation.js +16 -21
- package/dist/federation/federation.js.map +1 -1
- package/dist/federation/inbox.d.ts +23 -3
- package/dist/federation/inbox.d.ts.map +1 -1
- package/dist/federation/inbox.js +63 -1
- package/dist/federation/inbox.js.map +1 -1
- package/dist/federation/index.d.ts +0 -4
- package/dist/federation/index.d.ts.map +1 -1
- package/dist/federation/index.js +0 -2
- package/dist/federation/index.js.map +1 -1
- package/dist/federation/mount.d.ts +6 -12
- package/dist/federation/mount.d.ts.map +1 -1
- package/dist/federation/mount.js +3 -50
- package/dist/federation/mount.js.map +1 -1
- package/dist/federation/queue.d.ts +22 -0
- package/dist/federation/queue.d.ts.map +1 -0
- package/dist/federation/queue.js +58 -0
- package/dist/federation/queue.js.map +1 -0
- package/dist/files/atomic.d.ts +13 -0
- package/dist/files/atomic.d.ts.map +1 -1
- package/dist/files/atomic.js +45 -0
- package/dist/files/atomic.js.map +1 -1
- package/dist/index.d.ts +30 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +156 -79
- package/dist/index.js.map +1 -1
- package/dist/plugin.d.ts +513 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +23 -0
- package/dist/plugin.js.map +1 -0
- package/dist/plugins/enabled.d.ts +23 -0
- package/dist/plugins/enabled.d.ts.map +1 -0
- package/dist/plugins/enabled.js +49 -0
- package/dist/plugins/enabled.js.map +1 -0
- package/dist/plugins/federation.d.ts +26 -0
- package/dist/plugins/federation.d.ts.map +1 -0
- package/dist/plugins/federation.js +114 -0
- package/dist/plugins/federation.js.map +1 -0
- package/dist/plugins/fetch.d.ts +15 -0
- package/dist/plugins/fetch.d.ts.map +1 -0
- package/dist/plugins/fetch.js +33 -0
- package/dist/plugins/fetch.js.map +1 -0
- package/dist/plugins/folder.d.ts +50 -0
- package/dist/plugins/folder.d.ts.map +1 -0
- package/dist/plugins/folder.js +171 -0
- package/dist/plugins/folder.js.map +1 -0
- package/dist/plugins/install.d.ts +45 -0
- package/dist/plugins/install.d.ts.map +1 -0
- package/dist/plugins/install.js +275 -0
- package/dist/plugins/install.js.map +1 -0
- package/dist/plugins/mount.d.ts +17 -0
- package/dist/plugins/mount.d.ts.map +1 -0
- package/dist/plugins/mount.js +44 -0
- package/dist/plugins/mount.js.map +1 -0
- package/dist/plugins/registry.d.ts +110 -0
- package/dist/plugins/registry.d.ts.map +1 -0
- package/dist/plugins/registry.js +447 -0
- package/dist/plugins/registry.js.map +1 -0
- package/dist/plugins/settings.d.ts +64 -0
- package/dist/plugins/settings.d.ts.map +1 -0
- package/dist/plugins/settings.js +219 -0
- package/dist/plugins/settings.js.map +1 -0
- package/dist/plugins/site.d.ts +17 -0
- package/dist/plugins/site.d.ts.map +1 -0
- package/dist/plugins/site.js +67 -0
- package/dist/plugins/site.js.map +1 -0
- package/dist/supervisor/primary.d.ts +47 -0
- package/dist/supervisor/primary.d.ts.map +1 -0
- package/dist/supervisor/primary.js +208 -0
- package/dist/supervisor/primary.js.map +1 -0
- package/dist/supervisor/protocol.d.ts +37 -0
- package/dist/supervisor/protocol.d.ts.map +1 -0
- package/dist/supervisor/protocol.js +29 -0
- package/dist/supervisor/protocol.js.map +1 -0
- package/dist/supervisor/supervision.d.ts +25 -0
- package/dist/supervisor/supervision.d.ts.map +1 -0
- package/dist/supervisor/supervision.js +7 -0
- package/dist/supervisor/supervision.js.map +1 -0
- package/dist/supervisor/worker.d.ts +29 -0
- package/dist/supervisor/worker.d.ts.map +1 -0
- package/dist/supervisor/worker.js +97 -0
- package/dist/supervisor/worker.js.map +1 -0
- package/dist/web/errors.d.ts.map +1 -1
- package/dist/web/errors.js +5 -3
- package/dist/web/errors.js.map +1 -1
- package/dist/web/llms.d.ts +8 -0
- package/dist/web/llms.d.ts.map +1 -1
- package/dist/web/llms.js +25 -7
- package/dist/web/llms.js.map +1 -1
- package/dist/web/maintenance.d.ts +2 -2
- package/dist/web/maintenance.d.ts.map +1 -1
- package/dist/web/maintenance.js +7 -4
- package/dist/web/maintenance.js.map +1 -1
- package/dist/web/negotiate.d.ts +8 -5
- package/dist/web/negotiate.d.ts.map +1 -1
- package/dist/web/negotiate.js +21 -10
- package/dist/web/negotiate.js.map +1 -1
- package/dist/web/routes.d.ts.map +1 -1
- package/dist/web/routes.js +84 -36
- package/dist/web/routes.js.map +1 -1
- package/package.json +11 -5
- package/dist/comments/conversation.d.ts +0 -29
- package/dist/comments/conversation.d.ts.map +0 -1
- package/dist/comments/conversation.js +0 -60
- package/dist/comments/conversation.js.map +0 -1
- package/dist/federation/import-wordpress.d.ts +0 -128
- package/dist/federation/import-wordpress.d.ts.map +0 -1
- package/dist/federation/import-wordpress.js +0 -426
- package/dist/federation/import-wordpress.js.map +0 -1
- package/dist/federation/wordpress.d.ts +0 -131
- package/dist/federation/wordpress.d.ts.map +0 -1
- package/dist/federation/wordpress.js +0 -342
- package/dist/federation/wordpress.js.map +0 -1
- package/dist/web/comments.d.ts +0 -60
- package/dist/web/comments.d.ts.map +0 -1
- package/dist/web/comments.js +0 -207
- package/dist/web/comments.js.map +0 -1
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Native comments as the conversation sees them.
|
|
3
|
-
*
|
|
4
|
-
* `web/conversation.ts` deliberately knows nothing about where an answer came
|
|
5
|
-
* from, so this is the translation: a stored comment becomes an
|
|
6
|
-
* {@link Interaction} and joins the fediverse replies in the same thread,
|
|
7
|
-
* nested by the same rule. Nothing about a comment survives the trip that a
|
|
8
|
-
* theme would have to special-case — the source is on the record so a theme
|
|
9
|
-
* *may*, not so it must.
|
|
10
|
-
*
|
|
11
|
-
* Only approved comments come through. A comment waiting for a moderator and
|
|
12
|
-
* one filed as spam are both in the file and both in the index, and neither is
|
|
13
|
-
* anything a reader should be shown.
|
|
14
|
-
*/
|
|
15
|
-
/** The approved comments on a post, as interactions, oldest first. */
|
|
16
|
-
export function commentInteractions(admin, document) {
|
|
17
|
-
return admin
|
|
18
|
-
.listCommentsFor(document.slug)
|
|
19
|
-
.filter((comment) => comment.status === 'approved')
|
|
20
|
-
.map((comment) => interactionOf(comment, document));
|
|
21
|
-
}
|
|
22
|
-
/** One stored comment as the thread's own shape. */
|
|
23
|
-
export function interactionOf(comment, document) {
|
|
24
|
-
return {
|
|
25
|
-
id: comment.id,
|
|
26
|
-
source: comment.source,
|
|
27
|
-
kind: comment.kind,
|
|
28
|
-
author: {
|
|
29
|
-
name: comment.author.name,
|
|
30
|
-
// A commenter has no fediverse identity: they gave a name, maybe a
|
|
31
|
-
// website, and nothing that names them anywhere else.
|
|
32
|
-
handle: null,
|
|
33
|
-
url: comment.author.url,
|
|
34
|
-
// Only a webmention has one: it came out of the source page's `h-card`,
|
|
35
|
-
// and a form asks nobody for a picture.
|
|
36
|
-
avatar: comment.author.avatar,
|
|
37
|
-
actorId: null,
|
|
38
|
-
},
|
|
39
|
-
// Where it can be read. A comment written here lives here, at its own
|
|
40
|
-
// anchor; a webmention lives on the page it was sent from, and its `url`
|
|
41
|
-
// says so. A theme that prints `url` for a fediverse reply prints a
|
|
42
|
-
// working link for either.
|
|
43
|
-
url: comment.url ?? `${document.permalink}#${commentAnchor(comment.id)}`,
|
|
44
|
-
content: comment.content.html,
|
|
45
|
-
published: new Date(comment.submitted),
|
|
46
|
-
inReplyTo: comment.inReplyTo,
|
|
47
|
-
status: comment.status,
|
|
48
|
-
replies: [],
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* The `id` a comment is anchored at on the page.
|
|
53
|
-
*
|
|
54
|
-
* Prefixed rather than bare so a comment can never collide with a heading
|
|
55
|
-
* anchor the post's own Markdown produced.
|
|
56
|
-
*/
|
|
57
|
-
export function commentAnchor(id) {
|
|
58
|
-
return `comment-${id}`;
|
|
59
|
-
}
|
|
60
|
-
//# sourceMappingURL=conversation.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../src/comments/conversation.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AAEH,sEAAsE;AACtE,MAAM,UAAU,mBAAmB,CAAC,KAAiB,EAAE,QAAkB;IACvE,OAAO,KAAK;SACT,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC;SAC9B,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,KAAK,UAAU,CAAC;SAClD,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,aAAa,CAAC,OAAoB,EAAE,QAAkB;IACpE,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,MAAM,EAAE;YACN,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI;YACzB,mEAAmE;YACnE,sDAAsD;YACtD,MAAM,EAAE,IAAI;YACZ,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG;YACvB,wEAAwE;YACxE,wCAAwC;YACxC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM;YAC7B,OAAO,EAAE,IAAI;SACd;QACD,sEAAsE;QACtE,yEAAyE;QACzE,oEAAoE;QACpE,2BAA2B;QAC3B,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,QAAQ,CAAC,SAAS,IAAI,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;QACxE,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI;QAC7B,SAAS,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;QACtC,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,OAAO,EAAE,EAAE;KACZ,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,EAAU;IACtC,OAAO,WAAW,EAAE,EAAE,CAAC;AACzB,CAAC"}
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import type { AdminStore } from '../admin/store.ts';
|
|
2
|
-
import type { ActorKeyAlgorithm } from './keys.ts';
|
|
3
|
-
/** What {@link importWordPressActor} is given. */
|
|
4
|
-
export interface ImportWordPressActorOptions {
|
|
5
|
-
/** The index the followers are written into as the files are written. */
|
|
6
|
-
readonly admin: AdminStore;
|
|
7
|
-
/** Where `users.json` and `keys/` live. */
|
|
8
|
-
readonly dataDir: string;
|
|
9
|
-
/** Where `_data/federation/{username}/followers.json` lives. */
|
|
10
|
-
readonly contentDir: string;
|
|
11
|
-
/** Which account on this site the plugin's actor becomes. */
|
|
12
|
-
readonly username: string;
|
|
13
|
-
/**
|
|
14
|
-
* The actor's id exactly as WordPress published it, query string and all:
|
|
15
|
-
* `https://example.com/?author=2`.
|
|
16
|
-
*/
|
|
17
|
-
readonly actorId: string;
|
|
18
|
-
/** The WordPress user id, which is the number in every one of its paths. */
|
|
19
|
-
readonly wordpressActorId: number;
|
|
20
|
-
/** The private key as PEM, PKCS#1 or PKCS#8, as `wp` printed it. */
|
|
21
|
-
readonly privateKeyPem: string;
|
|
22
|
-
/**
|
|
23
|
-
* The public key as PEM, when the export carried one.
|
|
24
|
-
*
|
|
25
|
-
* Checked against the private half rather than stored: the public key is
|
|
26
|
-
* derivable, so the only thing a second file can tell us is whether the two
|
|
27
|
-
* halves of the export belong together — and a pair that does not is an
|
|
28
|
-
* export somebody got wrong, which is worth finding out now rather than
|
|
29
|
-
* after the DNS has moved.
|
|
30
|
-
*/
|
|
31
|
-
readonly publicKeyPem?: string | undefined;
|
|
32
|
-
/**
|
|
33
|
-
* Where the followers come from.
|
|
34
|
-
*
|
|
35
|
-
* Left off, the plugin's public followers collection on the actor id's own
|
|
36
|
-
* origin, which is the whole point of running this before the DNS moves. A
|
|
37
|
-
* URL asks a different one; a path reads a saved collection out of a file,
|
|
38
|
-
* for a site that is already gone; `false` skips the step, for a run that is
|
|
39
|
-
* only there to put the key and the ids in place.
|
|
40
|
-
*/
|
|
41
|
-
readonly followers?: string | false | undefined;
|
|
42
|
-
/** Replace a key pair this user already has. Refused without it. */
|
|
43
|
-
readonly force?: boolean | undefined;
|
|
44
|
-
}
|
|
45
|
-
/** What happened to one key file. */
|
|
46
|
-
export interface ImportedKey {
|
|
47
|
-
/** The file, absolute. */
|
|
48
|
-
readonly file: string;
|
|
49
|
-
/** Which pair it holds. */
|
|
50
|
-
readonly algorithm: ActorKeyAlgorithm;
|
|
51
|
-
/** What the run did with it. */
|
|
52
|
-
readonly state: 'imported' | 'generated' | 'unchanged' | 'replaced';
|
|
53
|
-
}
|
|
54
|
-
/** One follower the collection named and nothing could be made of. */
|
|
55
|
-
export interface UnreachableFollower {
|
|
56
|
-
/** The actor the collection named. */
|
|
57
|
-
readonly actor: string;
|
|
58
|
-
/** Why it was skipped, for the report. */
|
|
59
|
-
readonly reason: string;
|
|
60
|
-
}
|
|
61
|
-
/** What the followers step did. */
|
|
62
|
-
export interface FollowersImportReport {
|
|
63
|
-
/** The collection it read, or `undefined` when the step was skipped. */
|
|
64
|
-
readonly source: string | undefined;
|
|
65
|
-
/** Actors written into the file for the first time. */
|
|
66
|
-
readonly added: readonly string[];
|
|
67
|
-
/** Actors the file already held, with nothing about them changed. */
|
|
68
|
-
readonly unchanged: readonly string[];
|
|
69
|
-
/** Actors whose profile the file held and this run refreshed. */
|
|
70
|
-
readonly refreshed: readonly string[];
|
|
71
|
-
/**
|
|
72
|
-
* Actors that could not be turned into followers, and why.
|
|
73
|
-
*
|
|
74
|
-
* Reported rather than fatal: an instance that is down, or an account that
|
|
75
|
-
* has been deleted, must not stop the other hundred followers from coming
|
|
76
|
-
* across, and the owner can run the command again once it is back.
|
|
77
|
-
*/
|
|
78
|
-
readonly failed: readonly UnreachableFollower[];
|
|
79
|
-
}
|
|
80
|
-
/** What the run did. */
|
|
81
|
-
export interface ImportWordPressActorReport {
|
|
82
|
-
/** Who was imported. */
|
|
83
|
-
readonly username: string;
|
|
84
|
-
/** The id their followers hold. */
|
|
85
|
-
readonly actorId: string;
|
|
86
|
-
/** The number the plugin's paths are built from. */
|
|
87
|
-
readonly wordpressActorId: number;
|
|
88
|
-
/**
|
|
89
|
-
* Whether the two ids had to be written, or the record already said so.
|
|
90
|
-
*/
|
|
91
|
-
readonly identity: 'set' | 'unchanged';
|
|
92
|
-
/** One entry per key file, RSA first, as the key loader orders them. */
|
|
93
|
-
readonly keys: readonly ImportedKey[];
|
|
94
|
-
/** What came of the followers collection. */
|
|
95
|
-
readonly followers: FollowersImportReport;
|
|
96
|
-
/** Whether anything on disk is different because of this run. */
|
|
97
|
-
readonly changed: boolean;
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Thrown when the user already has a key pair and this run was not told to
|
|
101
|
-
* replace it.
|
|
102
|
-
*
|
|
103
|
-
* Its own class because the answer is a flag rather than a correction, and
|
|
104
|
-
* because losing a private key is the one mistake this CMS cannot help with:
|
|
105
|
-
* every follower's server has cached the public half, and a new key means none
|
|
106
|
-
* of them can verify this person again.
|
|
107
|
-
*/
|
|
108
|
-
export declare class ExistingKeyPairError extends Error {
|
|
109
|
-
readonly name = "ExistingKeyPairError";
|
|
110
|
-
/** The file that is already there. */
|
|
111
|
-
readonly file: string;
|
|
112
|
-
constructor(username: string, file: string);
|
|
113
|
-
}
|
|
114
|
-
/** Thrown when the PEM is not an RSA private key at all. */
|
|
115
|
-
export declare class UnusableKeyPemError extends Error {
|
|
116
|
-
readonly name = "UnusableKeyPemError";
|
|
117
|
-
constructor(message: string, options?: {
|
|
118
|
-
cause?: unknown;
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Bring one WordPress actor's key pair across, and say what changed.
|
|
123
|
-
*
|
|
124
|
-
* Run twice with the same inputs it changes nothing and says so, which is what
|
|
125
|
-
* makes it safe to run again after a follower's server was down.
|
|
126
|
-
*/
|
|
127
|
-
export declare function importWordPressActor(options: ImportWordPressActorOptions): Promise<ImportWordPressActorReport>;
|
|
128
|
-
//# sourceMappingURL=import-wordpress.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"import-wordpress.d.ts","sourceRoot":"","sources":["../../src/federation/import-wordpress.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,426 +0,0 @@
|
|
|
1
|
-
import { createPrivateKey, createPublicKey } from 'node:crypto';
|
|
2
|
-
import { exportJwk } from '@fedify/fedify';
|
|
3
|
-
import { setUserWordPressActor } from '../admin/accounts.js';
|
|
4
|
-
import { readFileIfPresentSync } from '../files/atomic.js';
|
|
5
|
-
import { actorKeyFile, loadActorKeyPairs, writeActorKeyFile } from './keys.js';
|
|
6
|
-
import { addFollower, readFollowers } from './records.js';
|
|
7
|
-
import { actorHandle, uriOf } from './replies.js';
|
|
8
|
-
/**
|
|
9
|
-
* Bringing one person across from the WordPress ActivityPub plugin
|
|
10
|
-
* (decision-14, TASK-71).
|
|
11
|
-
*
|
|
12
|
-
* Three things a site leaving the plugin cannot regenerate, and this is where
|
|
13
|
-
* they arrive: the RSA key pair its followers have cached, the actor id its
|
|
14
|
-
* followers key the account by, and the followers themselves. Everything else
|
|
15
|
-
* about the move — the posts, their ids, the compatibility paths — comes in
|
|
16
|
-
* with the content or is a setting.
|
|
17
|
-
*
|
|
18
|
-
* Nothing here is a screen, on purpose. A stored actor id is identity for the
|
|
19
|
-
* life of the account (doc-4), and identity is not something a form should be
|
|
20
|
-
* able to retype.
|
|
21
|
-
*/
|
|
22
|
-
/** The algorithm the plugin signs with, and the only one it has a key for. */
|
|
23
|
-
const RSA = 'RSASSA-PKCS1-v1_5';
|
|
24
|
-
/**
|
|
25
|
-
* Thrown when the user already has a key pair and this run was not told to
|
|
26
|
-
* replace it.
|
|
27
|
-
*
|
|
28
|
-
* Its own class because the answer is a flag rather than a correction, and
|
|
29
|
-
* because losing a private key is the one mistake this CMS cannot help with:
|
|
30
|
-
* every follower's server has cached the public half, and a new key means none
|
|
31
|
-
* of them can verify this person again.
|
|
32
|
-
*/
|
|
33
|
-
export class ExistingKeyPairError extends Error {
|
|
34
|
-
name = 'ExistingKeyPairError';
|
|
35
|
-
/** The file that is already there. */
|
|
36
|
-
file;
|
|
37
|
-
constructor(username, file) {
|
|
38
|
-
super(`${username} already has a different key pair, in ${file}. Importing over it would ` +
|
|
39
|
-
'change their identity: every follower has cached the public half of the key that is ' +
|
|
40
|
-
'there, and none of them could verify this person again. Pass --force only if you are ' +
|
|
41
|
-
'sure the pair being imported is the one the followers hold.');
|
|
42
|
-
this.file = file;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
/** Thrown when the PEM is not an RSA private key at all. */
|
|
46
|
-
export class UnusableKeyPemError extends Error {
|
|
47
|
-
name = 'UnusableKeyPemError';
|
|
48
|
-
constructor(message, options) {
|
|
49
|
-
super(message, options);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Bring one WordPress actor's key pair across, and say what changed.
|
|
54
|
-
*
|
|
55
|
-
* Run twice with the same inputs it changes nothing and says so, which is what
|
|
56
|
-
* makes it safe to run again after a follower's server was down.
|
|
57
|
-
*/
|
|
58
|
-
export async function importWordPressActor(options) {
|
|
59
|
-
const { dataDir, username } = options;
|
|
60
|
-
// Everything that can be refused is decided before anything is written, so a
|
|
61
|
-
// run that is going to stop stops with the disk as it was.
|
|
62
|
-
const planned = await planKeyImport(options);
|
|
63
|
-
const identity = (await setUserWordPressActor({
|
|
64
|
-
dataDir,
|
|
65
|
-
username,
|
|
66
|
-
actorId: options.actorId,
|
|
67
|
-
wordpressActorId: options.wordpressActorId,
|
|
68
|
-
}))
|
|
69
|
-
? 'set'
|
|
70
|
-
: 'unchanged';
|
|
71
|
-
const keys = [applyKeyImport(dataDir, username, planned)];
|
|
72
|
-
// The Ed25519 pair is minted here rather than left to the first request,
|
|
73
|
-
// because this is also what proves the file just written imports: Fedify
|
|
74
|
-
// swallows what a key pairs dispatcher throws, so an unusable key found at
|
|
75
|
-
// request time would be found by nobody.
|
|
76
|
-
const ed25519File = actorKeyFile(dataDir, username, 'Ed25519');
|
|
77
|
-
const hadEd25519 = readFileIfPresentSync(ed25519File) !== undefined;
|
|
78
|
-
await loadActorKeyPairs(dataDir, username);
|
|
79
|
-
keys.push({
|
|
80
|
-
file: ed25519File,
|
|
81
|
-
algorithm: 'Ed25519',
|
|
82
|
-
state: hadEd25519 ? 'unchanged' : 'generated',
|
|
83
|
-
});
|
|
84
|
-
const followers = await importFollowers(options);
|
|
85
|
-
return {
|
|
86
|
-
username,
|
|
87
|
-
actorId: options.actorId,
|
|
88
|
-
wordpressActorId: options.wordpressActorId,
|
|
89
|
-
identity,
|
|
90
|
-
keys,
|
|
91
|
-
followers,
|
|
92
|
-
changed: identity === 'set' ||
|
|
93
|
-
keys.some((key) => key.state !== 'unchanged') ||
|
|
94
|
-
followers.added.length > 0 ||
|
|
95
|
-
followers.refreshed.length > 0,
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Bring the followers across: read the collection, work out who each item is,
|
|
100
|
-
* and put them in the user's `followers.json` and the index.
|
|
101
|
-
*
|
|
102
|
-
* The plugin's collection carries nothing but a `first` page, and the page's
|
|
103
|
-
* `orderedItems` are bare actor URLs, so almost every follower here costs one
|
|
104
|
-
* fetch. That is the one step of the import that is really a network
|
|
105
|
-
* operation, which is why it can be pointed at a file instead: an owner who
|
|
106
|
-
* saved the collection before the DNS moved has everything they need offline.
|
|
107
|
-
*
|
|
108
|
-
* {@link addFollower} is what writes, so a follower already in the file keeps
|
|
109
|
-
* the place and the follow time it has — running this again after an instance
|
|
110
|
-
* came back adds the missing people and moves nobody.
|
|
111
|
-
*/
|
|
112
|
-
async function importFollowers(options) {
|
|
113
|
-
const empty = {
|
|
114
|
-
source: undefined,
|
|
115
|
-
added: [],
|
|
116
|
-
unchanged: [],
|
|
117
|
-
refreshed: [],
|
|
118
|
-
failed: [],
|
|
119
|
-
};
|
|
120
|
-
if (options.followers === false)
|
|
121
|
-
return empty;
|
|
122
|
-
const { admin, contentDir, username } = options;
|
|
123
|
-
const source = options.followers ?? followersCollectionUrl(options);
|
|
124
|
-
const added = [];
|
|
125
|
-
const unchanged = [];
|
|
126
|
-
const refreshed = [];
|
|
127
|
-
const failed = [];
|
|
128
|
-
for (const item of await collectionItems(source)) {
|
|
129
|
-
const actor = uriOf(item) ?? String(item);
|
|
130
|
-
try {
|
|
131
|
-
const document = isRecord(item) && uriOf(item['inbox']) !== null ? item : await fetchAs(actor);
|
|
132
|
-
const follower = followerFrom(document);
|
|
133
|
-
const held = readFollowers(contentDir, username).find((entry) => entry.actorId === follower.actorId);
|
|
134
|
-
await addFollower({ admin, contentDir }, username, follower);
|
|
135
|
-
if (held === undefined)
|
|
136
|
-
added.push(follower.actorId);
|
|
137
|
-
else if (sameFollower(held, follower))
|
|
138
|
-
unchanged.push(follower.actorId);
|
|
139
|
-
else
|
|
140
|
-
refreshed.push(follower.actorId);
|
|
141
|
-
}
|
|
142
|
-
catch (error) {
|
|
143
|
-
failed.push({ actor, reason: messageOf(error) });
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
return { source, added, unchanged, refreshed, failed };
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* The plugin's public followers collection for this actor.
|
|
150
|
-
*
|
|
151
|
-
* Built from the stored actor id's own origin rather than from anything the
|
|
152
|
-
* command was told separately: the id is the one URL an owner is certain to
|
|
153
|
-
* have right, and it is the site the followers are still pointed at.
|
|
154
|
-
*/
|
|
155
|
-
function followersCollectionUrl(options) {
|
|
156
|
-
const number = String(options.wordpressActorId);
|
|
157
|
-
return new URL(`/wp-json/activitypub/1.0/actors/${number}/followers`, options.actorId).href;
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Everything a followers collection names, in the order it names them.
|
|
161
|
-
*
|
|
162
|
-
* A collection with no items of its own is followed through `first`, and a
|
|
163
|
-
* page through `next`, until there is nowhere left to go; either may be a URL
|
|
164
|
-
* to fetch or a page already embedded in the document. URLs already visited
|
|
165
|
-
* are not visited again, because a server whose `next` points back at itself
|
|
166
|
-
* would otherwise be an endless import.
|
|
167
|
-
*/
|
|
168
|
-
async function collectionItems(source) {
|
|
169
|
-
const items = [];
|
|
170
|
-
const seen = new Set();
|
|
171
|
-
let document = isUrl(source) ? await fetchAs(source) : readJsonFile(source);
|
|
172
|
-
if (isUrl(source))
|
|
173
|
-
seen.add(source);
|
|
174
|
-
while (isRecord(document)) {
|
|
175
|
-
const listed = document['orderedItems'] ?? document['items'];
|
|
176
|
-
const here = Array.isArray(listed) ? listed : undefined;
|
|
177
|
-
if (here !== undefined)
|
|
178
|
-
items.push(...here);
|
|
179
|
-
// `next` on a page; `first` only when this document listed nothing itself,
|
|
180
|
-
// which is the plugin's outer collection.
|
|
181
|
-
const onward = document['next'] ?? (here === undefined ? document['first'] : undefined);
|
|
182
|
-
if (onward === undefined || onward === null)
|
|
183
|
-
break;
|
|
184
|
-
if (isRecord(onward)) {
|
|
185
|
-
document = onward;
|
|
186
|
-
continue;
|
|
187
|
-
}
|
|
188
|
-
const url = uriOf(onward);
|
|
189
|
-
if (url === null || seen.has(url))
|
|
190
|
-
break;
|
|
191
|
-
seen.add(url);
|
|
192
|
-
document = await fetchAs(url);
|
|
193
|
-
}
|
|
194
|
-
return items;
|
|
195
|
-
}
|
|
196
|
-
/** A saved collection, as the JSON it holds. */
|
|
197
|
-
function readJsonFile(file) {
|
|
198
|
-
const source = readFileIfPresentSync(file);
|
|
199
|
-
if (source === undefined) {
|
|
200
|
-
throw new Error(`There is no followers collection at ${file}.`);
|
|
201
|
-
}
|
|
202
|
-
try {
|
|
203
|
-
return JSON.parse(source);
|
|
204
|
-
}
|
|
205
|
-
catch (error) {
|
|
206
|
-
throw new Error(`${file} could not be read as JSON: ${messageOf(error)}`, { cause: error });
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
/** Whether a `--followers` value is a URL to fetch rather than a file to read. */
|
|
210
|
-
function isUrl(source) {
|
|
211
|
-
try {
|
|
212
|
-
const url = new URL(source);
|
|
213
|
-
return url.protocol === 'http:' || url.protocol === 'https:';
|
|
214
|
-
}
|
|
215
|
-
catch {
|
|
216
|
-
return false;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
/** What a peer should ask a fediverse server for. */
|
|
220
|
-
const ACTIVITY_STREAMS_ACCEPT = 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"';
|
|
221
|
-
/** One ActivityStreams document, or a thrown error naming the URL and the status. */
|
|
222
|
-
async function fetchAs(url) {
|
|
223
|
-
let response;
|
|
224
|
-
try {
|
|
225
|
-
response = await fetch(url, { headers: { accept: ACTIVITY_STREAMS_ACCEPT } });
|
|
226
|
-
}
|
|
227
|
-
catch (error) {
|
|
228
|
-
throw new Error(`${url} could not be fetched: ${messageOf(error)}`, { cause: error });
|
|
229
|
-
}
|
|
230
|
-
if (!response.ok) {
|
|
231
|
-
throw new Error(`${url} answered ${String(response.status)} ${response.statusText}`.trim());
|
|
232
|
-
}
|
|
233
|
-
try {
|
|
234
|
-
return await response.json();
|
|
235
|
-
}
|
|
236
|
-
catch (error) {
|
|
237
|
-
throw new Error(`${url} did not answer with JSON: ${messageOf(error)}`, { cause: error });
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* One actor document as the follower it stands for.
|
|
242
|
-
*
|
|
243
|
-
* Read straight out of the JSON rather than through Fedify's vocabulary,
|
|
244
|
-
* because this is the one place in the CMS that has a plain document and no
|
|
245
|
-
* federation context to dereference with. The six fields are the ones
|
|
246
|
-
* `followers.json` holds (doc-4): two to deliver with, four to show.
|
|
247
|
-
*/
|
|
248
|
-
function followerFrom(document) {
|
|
249
|
-
if (!isRecord(document))
|
|
250
|
-
throw new Error('that is not an actor document');
|
|
251
|
-
const actorId = uriOf(document['id']);
|
|
252
|
-
const inboxId = uriOf(document['inbox']);
|
|
253
|
-
if (actorId === null)
|
|
254
|
-
throw new Error('that actor document has no id');
|
|
255
|
-
if (inboxId === null)
|
|
256
|
-
throw new Error(`${actorId} publishes no inbox to deliver to`);
|
|
257
|
-
const endpoints = document['endpoints'];
|
|
258
|
-
const icon = document['icon'];
|
|
259
|
-
return {
|
|
260
|
-
actorId,
|
|
261
|
-
inboxId,
|
|
262
|
-
sharedInboxId: isRecord(endpoints) ? uriOf(endpoints['sharedInbox']) : null,
|
|
263
|
-
handle: handleOf(document, actorId),
|
|
264
|
-
name: textOf(document['name']) ?? null,
|
|
265
|
-
iconUrl: uriOf(isRecord(icon) ? icon['url'] : icon),
|
|
266
|
-
url: uriOf(document['url']),
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* `@name@host` for an actor, from its `preferredUsername` where it has one.
|
|
271
|
-
*
|
|
272
|
-
* Falling back to {@link actorHandle}, which guesses from the URL, for the
|
|
273
|
-
* server that publishes no `preferredUsername` at all.
|
|
274
|
-
*/
|
|
275
|
-
function handleOf(document, actorId) {
|
|
276
|
-
const preferred = textOf(document['preferredUsername']);
|
|
277
|
-
if (preferred === undefined || preferred === '')
|
|
278
|
-
return actorHandle(actorId) ?? null;
|
|
279
|
-
try {
|
|
280
|
-
return `@${preferred.replace(/^@/, '')}@${new URL(actorId).host}`;
|
|
281
|
-
}
|
|
282
|
-
catch {
|
|
283
|
-
return null;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
/** Whether a stored follower already says everything this one does. */
|
|
287
|
-
function sameFollower(held, incoming) {
|
|
288
|
-
return (held.inboxId === incoming.inboxId &&
|
|
289
|
-
held.sharedInboxId === incoming.sharedInboxId &&
|
|
290
|
-
held.handle === incoming.handle &&
|
|
291
|
-
held.name === incoming.name &&
|
|
292
|
-
held.iconUrl === incoming.iconUrl &&
|
|
293
|
-
held.url === incoming.url);
|
|
294
|
-
}
|
|
295
|
-
/** A JSON-LD string value, which may be wrapped in a language map. */
|
|
296
|
-
function textOf(value) {
|
|
297
|
-
if (Array.isArray(value)) {
|
|
298
|
-
for (const item of value) {
|
|
299
|
-
const found = textOf(item);
|
|
300
|
-
if (found !== undefined)
|
|
301
|
-
return found;
|
|
302
|
-
}
|
|
303
|
-
return undefined;
|
|
304
|
-
}
|
|
305
|
-
if (isRecord(value))
|
|
306
|
-
return textOf(value['@value']);
|
|
307
|
-
return typeof value === 'string' && value !== '' ? value : undefined;
|
|
308
|
-
}
|
|
309
|
-
function isRecord(value) {
|
|
310
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
311
|
-
}
|
|
312
|
-
/**
|
|
313
|
-
* Work out what the exported PEM means for
|
|
314
|
-
* `data/keys/{username}.rsassa-pkcs1-v1_5.jwk`, without touching it.
|
|
315
|
-
*
|
|
316
|
-
* A file already holding this very key is left alone and reported unchanged —
|
|
317
|
-
* that is what makes the whole command idempotent — and one holding a
|
|
318
|
-
* different key is refused unless the run was told to replace it.
|
|
319
|
-
*/
|
|
320
|
-
async function planKeyImport(options) {
|
|
321
|
-
const { dataDir, username } = options;
|
|
322
|
-
const privateKey = privateKeyFrom(options.privateKeyPem);
|
|
323
|
-
assertPairMatches(privateKey, options.publicKeyPem);
|
|
324
|
-
const jwk = `${JSON.stringify(await privateJwkOf(privateKey), undefined, 2)}\n`;
|
|
325
|
-
const file = actorKeyFile(dataDir, username, RSA);
|
|
326
|
-
const held = readFileIfPresentSync(file);
|
|
327
|
-
if (held === undefined)
|
|
328
|
-
return { file, algorithm: RSA, state: 'imported', jwk };
|
|
329
|
-
if (sameKeyFile(held, jwk))
|
|
330
|
-
return { file, algorithm: RSA, state: 'unchanged', jwk: undefined };
|
|
331
|
-
if (options.force !== true)
|
|
332
|
-
throw new ExistingKeyPairError(username, file);
|
|
333
|
-
return { file, algorithm: RSA, state: 'replaced', jwk };
|
|
334
|
-
}
|
|
335
|
-
/** Carry out what {@link planKeyImport} decided. */
|
|
336
|
-
function applyKeyImport(dataDir, username, planned) {
|
|
337
|
-
const { jwk, ...key } = planned;
|
|
338
|
-
if (jwk !== undefined)
|
|
339
|
-
writeActorKeyFile(dataDir, username, key.algorithm, jwk);
|
|
340
|
-
return key;
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* The PEM as a key object, whichever of the two encodings the export used.
|
|
344
|
-
*
|
|
345
|
-
* PHP writes `-----BEGIN PRIVATE KEY-----` (PKCS#8) on OpenSSL 3 and
|
|
346
|
-
* `-----BEGIN RSA PRIVATE KEY-----` (PKCS#1) on older builds, and an owner
|
|
347
|
-
* copying one out of `wp option get` has no reason to know which they have.
|
|
348
|
-
* `createPrivateKey` reads both.
|
|
349
|
-
*/
|
|
350
|
-
function privateKeyFrom(pem) {
|
|
351
|
-
const text = pem.trim();
|
|
352
|
-
if (text === '') {
|
|
353
|
-
throw new UnusableKeyPemError('The private key is empty. Check what the export wrote.');
|
|
354
|
-
}
|
|
355
|
-
let key;
|
|
356
|
-
try {
|
|
357
|
-
key = createPrivateKey({ key: text, format: 'pem' });
|
|
358
|
-
}
|
|
359
|
-
catch (error) {
|
|
360
|
-
throw new UnusableKeyPemError(`That is not a PEM private key: ${messageOf(error)}. It should begin with ` +
|
|
361
|
-
'"-----BEGIN PRIVATE KEY-----" or "-----BEGIN RSA PRIVATE KEY-----".', { cause: error });
|
|
362
|
-
}
|
|
363
|
-
if (key.asymmetricKeyType !== 'rsa') {
|
|
364
|
-
throw new UnusableKeyPemError(`That is a ${String(key.asymmetricKeyType)} key, and the WordPress ActivityPub plugin ` +
|
|
365
|
-
'signs with RSA. Check that the right key was exported.');
|
|
366
|
-
}
|
|
367
|
-
return key;
|
|
368
|
-
}
|
|
369
|
-
/** Refuse an export whose two halves are not halves of one pair. */
|
|
370
|
-
function assertPairMatches(privateKey, publicKeyPem) {
|
|
371
|
-
const text = (publicKeyPem ?? '').trim();
|
|
372
|
-
if (text === '')
|
|
373
|
-
return;
|
|
374
|
-
let given;
|
|
375
|
-
try {
|
|
376
|
-
given = createPublicKey({ key: text, format: 'pem' });
|
|
377
|
-
}
|
|
378
|
-
catch (error) {
|
|
379
|
-
throw new UnusableKeyPemError(`That is not a PEM public key: ${messageOf(error)}.`, {
|
|
380
|
-
cause: error,
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
const derived = createPublicKey(privateKey);
|
|
384
|
-
if (!given
|
|
385
|
-
.export({ type: 'spki', format: 'der' })
|
|
386
|
-
.equals(derived.export({ type: 'spki', format: 'der' }))) {
|
|
387
|
-
throw new UnusableKeyPemError('The public and private keys are not two halves of one pair. Export both again from the ' +
|
|
388
|
-
'same WordPress user, or leave the public key off — it is derived from the private one.');
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
/**
|
|
392
|
-
* The private JWK the key file holds, produced the way a generated one is.
|
|
393
|
-
*
|
|
394
|
-
* The PEM goes to DER through node:crypto, into WebCrypto, and out through
|
|
395
|
-
* Fedify's `exportJwk` — the same call `loadActorKeyPairs` makes when it mints
|
|
396
|
-
* a pair. Going the long way round rather than asking node:crypto for the JWK
|
|
397
|
-
* directly is what guarantees an imported file and a generated one carry the
|
|
398
|
-
* same members in the same shape, `alg: "RS256"` included, which is what the
|
|
399
|
-
* loader's boot check insists on.
|
|
400
|
-
*/
|
|
401
|
-
async function privateJwkOf(privateKey) {
|
|
402
|
-
const pkcs8 = privateKey.export({ type: 'pkcs8', format: 'der' });
|
|
403
|
-
const key = await crypto.subtle.importKey('pkcs8', pkcs8, { name: RSA, hash: 'SHA-256' }, true, [
|
|
404
|
-
'sign',
|
|
405
|
-
]);
|
|
406
|
-
return await exportJwk(key);
|
|
407
|
-
}
|
|
408
|
-
/**
|
|
409
|
-
* Whether a key file already holds the key being imported.
|
|
410
|
-
*
|
|
411
|
-
* Compared as the parsed JWK rather than as bytes, so a file somebody
|
|
412
|
-
* reindented is still the same key.
|
|
413
|
-
*/
|
|
414
|
-
function sameKeyFile(held, incoming) {
|
|
415
|
-
try {
|
|
416
|
-
return (JSON.stringify(JSON.parse(held)) ===
|
|
417
|
-
JSON.stringify(JSON.parse(incoming)));
|
|
418
|
-
}
|
|
419
|
-
catch {
|
|
420
|
-
return false;
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
function messageOf(error) {
|
|
424
|
-
return error instanceof Error ? error.message : String(error);
|
|
425
|
-
}
|
|
426
|
-
//# sourceMappingURL=import-wordpress.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"import-wordpress.js","sourceRoot":"","sources":["../../src/federation/import-wordpress.ts"],"names":[],"mappings":"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"}
|