@geekity/cms 0.24.0 → 0.26.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 +48 -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 +144 -4
- package/admin/static/editor-actions.js +202 -0
- 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 +187 -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 +524 -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/maintenance.d.ts +2 -2
- package/dist/web/maintenance.js +2 -2
- package/dist/web/negotiate.d.ts +4 -3
- package/dist/web/negotiate.d.ts.map +1 -1
- package/dist/web/negotiate.js +4 -3
- package/dist/web/negotiate.js.map +1 -1
- package/dist/web/routes.d.ts.map +1 -1
- package/dist/web/routes.js +33 -14
- package/dist/web/routes.js.map +1 -1
- package/package.json +10 -1
- 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,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":"AAAA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGhE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAE/E,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAElD;;;;;;;;;;;;;GAaG;AAEH,8EAA8E;AAC9E,MAAM,GAAG,GAAG,mBAAmB,CAAC;AAuGhC;;;;;;;;GAQG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC3B,IAAI,GAAG,sBAAsB,CAAC;IAChD,sCAAsC;IAC7B,IAAI,CAAS;IAEtB,YAAY,QAAgB,EAAE,IAAY;QACxC,KAAK,CACH,GAAG,QAAQ,yCAAyC,IAAI,4BAA4B;YAClF,sFAAsF;YACtF,uFAAuF;YACvF,6DAA6D,CAChE,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,4DAA4D;AAC5D,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC1B,IAAI,GAAG,qBAAqB,CAAC;IAE/C,YAAY,OAAe,EAAE,OAA6B;QACxD,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC1B,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAAoC;IAEpC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAEtC,6EAA6E;IAC7E,2DAA2D;IAC3D,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC;IAE7C,MAAM,QAAQ,GAAG,CAAC,MAAM,qBAAqB,CAAC;QAC5C,OAAO;QACP,QAAQ;QACR,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;KAC3C,CAAC,CAAC;QACD,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,WAAW,CAAC;IAEhB,MAAM,IAAI,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IAE1D,yEAAyE;IACzE,yEAAyE;IACzE,2EAA2E;IAC3E,yCAAyC;IACzC,MAAM,WAAW,GAAG,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IAC/D,MAAM,UAAU,GAAG,qBAAqB,CAAC,WAAW,CAAC,KAAK,SAAS,CAAC;IACpE,MAAM,iBAAiB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC3C,IAAI,CAAC,IAAI,CAAC;QACR,IAAI,EAAE,WAAW;QACjB,SAAS,EAAE,SAAS;QACpB,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW;KAC9C,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,OAAO,CAAC,CAAC;IAEjD,OAAO;QACL,QAAQ;QACR,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;QAC1C,QAAQ;QACR,IAAI;QACJ,SAAS;QACT,OAAO,EACL,QAAQ,KAAK,KAAK;YAClB,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,WAAW,CAAC;YAC7C,SAAS,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;YAC1B,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;KACjC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,KAAK,UAAU,eAAe,CAC5B,OAAoC;IAEpC,MAAM,KAAK,GAA0B;QACnC,MAAM,EAAE,SAAS;QACjB,KAAK,EAAE,EAAE;QACT,SAAS,EAAE,EAAE;QACb,SAAS,EAAE,EAAE;QACb,MAAM,EAAE,EAAE;KACX,CAAC;IACF,IAAI,OAAO,CAAC,SAAS,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IAE9C,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAChD,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,IAAI,sBAAsB,CAAC,OAAO,CAAC,CAAC;IACpE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,MAAM,GAA0B,EAAE,CAAC;IAEzC,KAAK,MAAM,IAAI,IAAI,MAAM,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;QACjD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,CAAC;YACH,MAAM,QAAQ,GACZ,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;YAChF,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;YACxC,MAAM,IAAI,GAAG,aAAa,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,IAAI,CACnD,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,KAAK,QAAQ,CAAC,OAAO,CAC9C,CAAC;YACF,MAAM,WAAW,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAE7D,IAAI,IAAI,KAAK,SAAS;gBAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;iBAChD,IAAI,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC;gBAAE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;;gBACnE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;AACzD,CAAC;AAED;;;;;;GAMG;AACH,SAAS,sBAAsB,CAAC,OAAoC;IAClE,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAChD,OAAO,IAAI,GAAG,CAAC,mCAAmC,MAAM,YAAY,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;AAC9F,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,eAAe,CAAC,MAAc;IAC3C,MAAM,KAAK,GAAc,EAAE,CAAC;IAC5B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,IAAI,QAAQ,GAAY,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IACrF,IAAI,KAAK,CAAC,MAAM,CAAC;QAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAEpC,OAAO,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAY,QAAQ,CAAC,cAAc,CAAC,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC;QACtE,MAAM,IAAI,GAA0B,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAE,MAAoB,CAAC,CAAC,CAAC,SAAS,CAAC;QAC9F,IAAI,IAAI,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QAE5C,2EAA2E;QAC3E,0CAA0C;QAC1C,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACxF,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI;YAAE,MAAM;QACnD,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACrB,QAAQ,GAAG,MAAM,CAAC;YAClB,SAAS;QACX,CAAC;QAED,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;QAC1B,IAAI,GAAG,KAAK,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,MAAM;QACzC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,gDAAgD;AAChD,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,MAAM,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,uCAAuC,IAAI,GAAG,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,+BAA+B,SAAS,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9F,CAAC;AACH,CAAC;AAED,kFAAkF;AAClF,SAAS,KAAK,CAAC,MAAc;IAC3B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5B,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,qDAAqD;AACrD,MAAM,uBAAuB,GAC3B,iGAAiG,CAAC;AAEpG,qFAAqF;AACrF,KAAK,UAAU,OAAO,CAAC,GAAW;IAChC,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,uBAAuB,EAAE,EAAE,CAAC,CAAC;IAChF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,0BAA0B,SAAS,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACxF,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,aAAa,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9F,CAAC;IACD,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,8BAA8B,SAAS,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAC5F,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,YAAY,CAAC,QAAiB;IACrC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAE1E,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IACzC,IAAI,OAAO,KAAK,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACvE,IAAI,OAAO,KAAK,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,mCAAmC,CAAC,CAAC;IAErF,MAAM,SAAS,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE9B,OAAO;QACL,OAAO;QACP,OAAO;QACP,aAAa,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;QAC3E,MAAM,EAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;QACnC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI;QACtC,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACnD,GAAG,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;KAC5B,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAS,QAAQ,CAAC,QAAiC,EAAE,OAAe;IAClE,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC;IACxD,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,EAAE;QAAE,OAAO,WAAW,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;IACrF,IAAI,CAAC;QACH,OAAO,IAAI,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,uEAAuE;AACvE,SAAS,YAAY,CAAC,IAAc,EAAE,QAAuC;IAC3E,OAAO,CACL,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,OAAO;QACjC,IAAI,CAAC,aAAa,KAAK,QAAQ,CAAC,aAAa;QAC7C,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM;QAC/B,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI;QAC3B,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,OAAO;QACjC,IAAI,CAAC,GAAG,KAAK,QAAQ,CAAC,GAAG,CAC1B,CAAC;AACJ,CAAC;AAED,sEAAsE;AACtE,SAAS,MAAM,CAAC,KAAc;IAC5B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;YAC3B,IAAI,KAAK,KAAK,SAAS;gBAAE,OAAO,KAAK,CAAC;QACxC,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvE,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAQD;;;;;;;GAOG;AACH,KAAK,UAAU,aAAa,CAAC,OAAoC;IAC/D,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IACtC,MAAM,UAAU,GAAG,cAAc,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACzD,iBAAiB,CAAC,UAAU,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAEpD,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,YAAY,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC;IAChF,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAEzC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC;IAChF,IAAI,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;IAChG,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI;QAAE,MAAM,IAAI,oBAAoB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC3E,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC;AAC1D,CAAC;AAED,oDAAoD;AACpD,SAAS,cAAc,CAAC,OAAe,EAAE,QAAgB,EAAE,OAAmB;IAC5E,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC;IAChC,IAAI,GAAG,KAAK,SAAS;QAAE,iBAAiB,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAChF,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,cAAc,CAAC,GAAW;IACjC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACxB,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QAChB,MAAM,IAAI,mBAAmB,CAAC,wDAAwD,CAAC,CAAC;IAC1F,CAAC;IAED,IAAI,GAAc,CAAC;IACnB,IAAI,CAAC;QACH,GAAG,GAAG,gBAAgB,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACvD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,mBAAmB,CAC3B,kCAAkC,SAAS,CAAC,KAAK,CAAC,yBAAyB;YACzE,qEAAqE,EACvE,EAAE,KAAK,EAAE,KAAK,EAAE,CACjB,CAAC;IACJ,CAAC;IAED,IAAI,GAAG,CAAC,iBAAiB,KAAK,KAAK,EAAE,CAAC;QACpC,MAAM,IAAI,mBAAmB,CAC3B,aAAa,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,6CAA6C;YACrF,wDAAwD,CAC3D,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,oEAAoE;AACpE,SAAS,iBAAiB,CAAC,UAAqB,EAAE,YAAgC;IAChF,MAAM,IAAI,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACzC,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO;IAExB,IAAI,KAAgB,CAAC;IACrB,IAAI,CAAC;QACH,KAAK,GAAG,eAAe,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACxD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,mBAAmB,CAAC,iCAAiC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE;YAClF,KAAK,EAAE,KAAK;SACb,CAAC,CAAC;IACL,CAAC;IAED,MAAM,OAAO,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;IAC5C,IACE,CAAC,KAAK;SACH,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;SACvC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,EAC1D,CAAC;QACD,MAAM,IAAI,mBAAmB,CAC3B,yFAAyF;YACvF,wFAAwF,CAC3F,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,KAAK,UAAU,YAAY,CAAC,UAAqB;IAC/C,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAClE,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE;QAC9F,MAAM;KACP,CAAC,CAAC;IACH,OAAO,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;AAC9B,CAAC;AAED;;;;;GAKG;AACH,SAAS,WAAW,CAAC,IAAY,EAAE,QAAgB;IACjD,IAAI,CAAC;QACH,OAAO,CACL,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC;YAC3C,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAY,CAAC,CAChD,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import type { InboxContext } from '@fedify/fedify';
|
|
2
|
-
import type { User } from '../admin/accounts.ts';
|
|
3
|
-
import type { CreateSiteFederationOptions, FederationContextData } from './federation.ts';
|
|
4
|
-
import type { SiteFederation } from './federation.ts';
|
|
5
|
-
/**
|
|
6
|
-
* The WordPress ActivityPub plugin's paths, served behind a switch (TASK-70).
|
|
7
|
-
*
|
|
8
|
-
* A follower's server delivers to the inbox URL it cached from the actor
|
|
9
|
-
* document, and replaces it only when it next refetches the actor. A site that
|
|
10
|
-
* moved here from the plugin therefore goes on being delivered to at
|
|
11
|
-
* `/wp-json/activitypub/1.0/actors/2/inbox` and `/wp-json/activitypub/1.0/inbox`
|
|
12
|
-
* for as long as those caches last, and decision-14 calls that **cache rather
|
|
13
|
-
* than identity**: the CMS carries the plugin's layout until the caches have
|
|
14
|
-
* moved on, and no longer.
|
|
15
|
-
*
|
|
16
|
-
* So everything here is behind the `wordpressActivityPub` site setting, and
|
|
17
|
-
* everything a peer reads back is the canonical identity. The actor served at
|
|
18
|
-
* `…/actors/2` is the same `Person` the author URL serves — same `id`, same
|
|
19
|
-
* canonical `inbox` — so a peer that refetches here learns the new endpoints
|
|
20
|
-
* rather than being handed the old ones again. That is what eventually makes
|
|
21
|
-
* the switch safe to turn off.
|
|
22
|
-
*
|
|
23
|
-
* A second `Federation` is how Fedify serves a second inbox path at all: one
|
|
24
|
-
* object may have exactly one pair of inbox listeners, and `ctx.routeActivity`
|
|
25
|
-
* re-verifies from scratch in a way a Mastodon or WordPress `Follow` cannot
|
|
26
|
-
* satisfy (doc-8). The second object shares the canonical one's KV store, and
|
|
27
|
-
* both sets of listeners are set to `per-origin` idempotence, because the
|
|
28
|
-
* default folds the recipient identifier into the key — so the same `Follow`
|
|
29
|
-
* redelivered to `andrew` and to `2` would otherwise be handled twice.
|
|
30
|
-
*/
|
|
31
|
-
/** Where the plugin's REST namespace lives, on the site's origin. */
|
|
32
|
-
export declare const WORDPRESS_ACTIVITYPUB_BASE = "/wp-json/activitypub/1.0";
|
|
33
|
-
/** The plugin's actor path. Its identifier is the WordPress user's number. */
|
|
34
|
-
export declare const WORDPRESS_ACTOR_PATH: "/wp-json/activitypub/1.0/actors/{identifier}";
|
|
35
|
-
/** The actor's inbox, outbox and two follow collections, as the plugin spells them. */
|
|
36
|
-
export declare const WORDPRESS_INBOX_PATH: "/wp-json/activitypub/1.0/actors/{identifier}/inbox";
|
|
37
|
-
export declare const WORDPRESS_OUTBOX_PATH: "/wp-json/activitypub/1.0/actors/{identifier}/outbox";
|
|
38
|
-
export declare const WORDPRESS_FOLLOWERS_PATH: "/wp-json/activitypub/1.0/actors/{identifier}/followers";
|
|
39
|
-
export declare const WORDPRESS_FOLLOWING_PATH: "/wp-json/activitypub/1.0/actors/{identifier}/following";
|
|
40
|
-
/** The plugin's instance-wide inbox, which its `sharedInbox` endpoint names. */
|
|
41
|
-
export declare const WORDPRESS_SHARED_INBOX_PATH: "/wp-json/activitypub/1.0/inbox";
|
|
42
|
-
/** What {@link createWordPressFederation} takes beyond the canonical options. */
|
|
43
|
-
export interface CreateWordPressFederationOptions extends CreateSiteFederationOptions {
|
|
44
|
-
/**
|
|
45
|
-
* The site's own federation, whose contexts every identity here is built
|
|
46
|
-
* from.
|
|
47
|
-
*
|
|
48
|
-
* Fedify derives an actor's id, its key ids and its collection URLs from the
|
|
49
|
-
* path it dispatches the actor at, and the paths here are the plugin's. A
|
|
50
|
-
* document built off this object's own context would tell a peer that the
|
|
51
|
-
* person *is* `…/wp-json/…/actors/2` and sign with a key id under it, which
|
|
52
|
-
* is the opposite of what the switch is for.
|
|
53
|
-
*/
|
|
54
|
-
canonical: SiteFederation;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Build the compatibility federation: the plugin's inbox and collections,
|
|
58
|
-
* mapped to users by the number WordPress gave them.
|
|
59
|
-
*
|
|
60
|
-
* Nothing else is registered. WebFinger, NodeInfo and the actor's real
|
|
61
|
-
* endpoints belong to the canonical federation and stay there; this object
|
|
62
|
-
* exists only so that deliveries and fetches aimed at the old layout land
|
|
63
|
-
* somewhere, signature-verified at the real request path exactly as the
|
|
64
|
-
* canonical inbox verifies them.
|
|
65
|
-
*/
|
|
66
|
-
export declare function createWordPressFederation(options: CreateWordPressFederationOptions): SiteFederation;
|
|
67
|
-
/**
|
|
68
|
-
* The user the WordPress ActivityPub plugin numbered `identifier`, or
|
|
69
|
-
* `undefined`.
|
|
70
|
-
*
|
|
71
|
-
* The identifier is a path segment, so it is compared as the decimal the
|
|
72
|
-
* plugin writes: `02` and `2.0` name nobody, because neither is a URL the
|
|
73
|
-
* plugin ever published.
|
|
74
|
-
*/
|
|
75
|
-
export declare function userByWordPressActorId(dataDir: string, identifier: string): User | undefined;
|
|
76
|
-
/** One of the plugin's paths, as the record of what was asked for names it. */
|
|
77
|
-
export type WordPressRoute = 'actor' | 'inbox' | 'outbox' | 'followers' | 'following';
|
|
78
|
-
/** Which compatibility path a request is for, and whose. */
|
|
79
|
-
export interface WordPressRequestTarget {
|
|
80
|
-
/** The path it is, or `sharedInbox` for the instance-wide one. */
|
|
81
|
-
readonly route: WordPressRoute | 'sharedInbox';
|
|
82
|
-
/** The WordPress number in the path, or `undefined` for the shared inbox. */
|
|
83
|
-
readonly wordpressActorId?: string | undefined;
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* The compatibility path a request asks for, or `undefined` for anything else.
|
|
87
|
-
*
|
|
88
|
-
* Matched here rather than left to Fedify because the record of what was last
|
|
89
|
-
* asked for has to be written whether or not a user answers: a delivery to a
|
|
90
|
-
* number nobody carries is still a peer holding the old URL, and it is exactly
|
|
91
|
-
* the sort of thing the owner watching the screen wants to see. Fedify's
|
|
92
|
-
* router still decides what is actually served.
|
|
93
|
-
*/
|
|
94
|
-
export declare function wordPressRequestTarget(pathname: string): WordPressRequestTarget | undefined;
|
|
95
|
-
/** The file the instants live in, relative to `dataDir`. */
|
|
96
|
-
export declare const WORDPRESS_REQUESTS_FILE = "wordpress-activitypub.json";
|
|
97
|
-
/** Where that file lives for a given data directory. */
|
|
98
|
-
export declare function wordPressRequestsFile(dataDir: string): string;
|
|
99
|
-
/**
|
|
100
|
-
* When each compatibility path was last asked for.
|
|
101
|
-
*
|
|
102
|
-
* A file under `data/` rather than a table, because the database is a cache a
|
|
103
|
-
* site may delete (decision-9) and this is the one thing the switch is watched
|
|
104
|
-
* by: an owner deciding whether every follower's server has refetched the
|
|
105
|
-
* actor should not have that answer reset by a rebuild.
|
|
106
|
-
*/
|
|
107
|
-
export interface WordPressRequests {
|
|
108
|
-
/** When the instance-wide inbox was last delivered to, or `undefined`. */
|
|
109
|
-
readonly sharedInbox?: string | undefined;
|
|
110
|
-
/** When each of a user's own paths was last asked for, by username. */
|
|
111
|
-
readonly users: Readonly<Record<string, Readonly<Partial<Record<WordPressRoute, string>>>>>;
|
|
112
|
-
}
|
|
113
|
-
/** The file as it reads now; a site nobody has asked has nothing to say. */
|
|
114
|
-
export declare function readWordPressRequests(dataDir: string): WordPressRequests;
|
|
115
|
-
/**
|
|
116
|
-
* Record that one compatibility path was just asked for.
|
|
117
|
-
*
|
|
118
|
-
* Written through {@link updateFileAtomically}, so two deliveries arriving
|
|
119
|
-
* together cannot lose one another's instant and a reader never sees a
|
|
120
|
-
* half-written file. A path whose number names nobody is not recorded: the
|
|
121
|
-
* record is per user, and there is no user to record it against.
|
|
122
|
-
*/
|
|
123
|
-
export declare function recordWordPressRequest(options: {
|
|
124
|
-
dataDir: string;
|
|
125
|
-
target: WordPressRequestTarget;
|
|
126
|
-
username?: string | undefined;
|
|
127
|
-
at: Date;
|
|
128
|
-
}): Promise<void>;
|
|
129
|
-
/** A compatibility context, for the handlers that are handed one. */
|
|
130
|
-
export type WordPressInboxContext = InboxContext<FederationContextData>;
|
|
131
|
-
//# sourceMappingURL=wordpress.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"wordpress.d.ts","sourceRoot":"","sources":["../../src/federation/wordpress.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAW,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAe5D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAKjD,OAAO,KAAK,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAc1F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,qEAAqE;AACrE,eAAO,MAAM,0BAA0B,6BAA6B,CAAC;AAErE,8EAA8E;AAC9E,eAAO,MAAM,oBAAoB,gDAA+D,CAAC;AAEjG,uFAAuF;AACvF,eAAO,MAAM,oBAAoB,sDAA2C,CAAC;AAC7E,eAAO,MAAM,qBAAqB,uDAA4C,CAAC;AAC/E,eAAO,MAAM,wBAAwB,0DAA+C,CAAC;AACrF,eAAO,MAAM,wBAAwB,0DAA+C,CAAC;AAErF,gFAAgF;AAChF,eAAO,MAAM,2BAA2B,kCAAiD,CAAC;AAE1F,iFAAiF;AACjF,MAAM,WAAW,gCAAiC,SAAQ,2BAA2B;IACnF;;;;;;;;;OASG;IACH,SAAS,EAAE,cAAc,CAAC;CAC3B;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,gCAAgC,GACxC,cAAc,CAwIhB;AA6BD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAI5F;AAED,+EAA+E;AAC/E,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,CAAC;AAEtF,4DAA4D;AAC5D,MAAM,WAAW,sBAAsB;IACrC,kEAAkE;IAClE,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG,aAAa,CAAC;IAC/C,6EAA6E;IAC7E,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChD;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,sBAAsB,GAAG,SAAS,CAc3F;AAED,4DAA4D;AAC5D,eAAO,MAAM,uBAAuB,+BAA+B,CAAC;AAEpE,wDAAwD;AACxD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,0EAA0E;IAC1E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC7F;AAED,4EAA4E;AAC5E,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAaxE;AAED;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,sBAAsB,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,EAAE,EAAE,IAAI,CAAC;CACV,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBhB;AAsDD,qEAAqE;AACrE,MAAM,MAAM,qBAAqB,GAAG,YAAY,CAAC,qBAAqB,CAAC,CAAC"}
|