@geekity/cms 0.35.0 → 0.36.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/components/job-status.njk +15 -10
- package/admin/components/upload.njk +26 -0
- package/admin/pages/documents/editor.njk +34 -19
- package/admin/pages/federation/followers.njk +2 -1
- package/admin/pages/media/file.njk +5 -4
- package/admin/pages/media/library.njk +7 -3
- package/admin/pages/settings/general.njk +4 -1
- package/admin/pages/tools/export.njk +54 -51
- package/admin/pages/tools/maintenance.njk +2 -1
- package/admin/pages/users/edit.njk +3 -0
- package/admin/src/admin.css +1 -0
- package/admin/static/admin.css +74 -0
- package/admin/static/job-status.js +158 -0
- package/admin/static/upload-drop.js +225 -0
- package/dist/admin/documents.d.ts.map +1 -1
- package/dist/admin/documents.js +0 -2
- package/dist/admin/documents.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/job-status.d.ts +1 -0
- package/dist/admin/job-status.d.ts.map +1 -1
- package/dist/admin/job-status.js +1 -0
- package/dist/admin/job-status.js.map +1 -1
- package/dist/admin/media.d.ts +6 -9
- package/dist/admin/media.d.ts.map +1 -1
- package/dist/admin/media.js +85 -27
- package/dist/admin/media.js.map +1 -1
- package/dist/admin/routes.d.ts.map +1 -1
- package/dist/admin/routes.js +1 -0
- package/dist/admin/routes.js.map +1 -1
- package/dist/admin/uploads.d.ts +2 -1
- package/dist/admin/uploads.d.ts.map +1 -1
- package/dist/admin/uploads.js +5 -2
- package/dist/admin/uploads.js.map +1 -1
- package/dist/media/library.d.ts +9 -0
- package/dist/media/library.d.ts.map +1 -1
- package/dist/media/library.js +25 -1
- package/dist/media/library.js.map +1 -1
- package/package.json +6 -1
- package/dist/comments/routes.d.ts +0 -65
- package/dist/comments/routes.d.ts.map +0 -1
- package/dist/comments/routes.js +0 -235
- package/dist/comments/routes.js.map +0 -1
- package/dist/content/media.d.ts +0 -85
- package/dist/content/media.d.ts.map +0 -1
- package/dist/content/media.js +0 -237
- package/dist/content/media.js.map +0 -1
- package/dist/content/read-form.d.ts +0 -31
- package/dist/content/read-form.d.ts.map +0 -1
- package/dist/content/read-form.js +0 -157
- package/dist/content/read-form.js.map +0 -1
- package/dist/content/read.d.ts +0 -29
- package/dist/content/read.d.ts.map +0 -1
- package/dist/content/read.js +0 -82
- package/dist/content/read.js.map +0 -1
- package/dist/export/export-archives.d.ts +0 -29
- package/dist/export/export-archives.d.ts.map +0 -1
- package/dist/export/export-archives.js +0 -88
- package/dist/export/export-archives.js.map +0 -1
- package/dist/federation/mount.d.ts +0 -53
- package/dist/federation/mount.d.ts.map +0 -1
- package/dist/federation/mount.js +0 -344
- package/dist/federation/mount.js.map +0 -1
- package/dist/mail/credentials.d.ts +0 -62
- package/dist/mail/credentials.d.ts.map +0 -1
- package/dist/mail/credentials.js +0 -86
- package/dist/mail/credentials.js.map +0 -1
- package/dist/site/setting-rows.d.ts +0 -45
- package/dist/site/setting-rows.d.ts.map +0 -1
- package/dist/site/setting-rows.js +0 -361
- package/dist/site/setting-rows.js.map +0 -1
- package/dist/site/settings-form.d.ts +0 -30
- package/dist/site/settings-form.d.ts.map +0 -1
- package/dist/site/settings-form.js +0 -54
- package/dist/site/settings-form.js.map +0 -1
- package/dist/site/site-json.d.ts +0 -38
- package/dist/site/site-json.d.ts.map +0 -1
- package/dist/site/site-json.js +0 -69
- package/dist/site/site-json.js.map +0 -1
- package/dist/webmention/routes.d.ts +0 -37
- package/dist/webmention/routes.d.ts.map +0 -1
- package/dist/webmention/routes.js +0 -75
- package/dist/webmention/routes.js.map +0 -1
package/dist/federation/mount.js
DELETED
|
@@ -1,344 +0,0 @@
|
|
|
1
|
-
import { respondWithObject } from '@fedify/fedify';
|
|
2
|
-
import { federation as federationMiddleware } from '@fedify/hono';
|
|
3
|
-
import { isGone, isFederatedDocument } from '../content/served.js';
|
|
4
|
-
import { isTrashedPath } from '../content/store.js';
|
|
5
|
-
import { listUsers } from '../site/users.js';
|
|
6
|
-
import { absoluteUrl } from '../util/url.js';
|
|
7
|
-
import { authorHref, parseAuthorPath, accountOf } from '../content/authors.js';
|
|
8
|
-
import { goneDocumentAt, publicDocumentAt } from '../content/permalinks.js';
|
|
9
|
-
import { prefersActivityStreams } from '../web/negotiate.js';
|
|
10
|
-
import { notFound, requestPath } from '../web/request.js';
|
|
11
|
-
import { actorAliases, actorId, userActor } from './actor.js';
|
|
12
|
-
import { postObject, postTombstone } from './article.js';
|
|
13
|
-
import { handleHref } from './paths.js';
|
|
14
|
-
/**
|
|
15
|
-
* Put Fedify in front of the rest of the app.
|
|
16
|
-
*
|
|
17
|
-
* The middleware only answers the paths Fedify registered — the actor, its
|
|
18
|
-
* collections, WebFinger and NodeInfo; everything else falls through to
|
|
19
|
-
* `next()` and reaches the admin and the public site as before. That is why it
|
|
20
|
-
* is mounted first: the public site claims every unmatched path in its
|
|
21
|
-
* not-found handler, so anything registered after it never sees a request.
|
|
22
|
-
*
|
|
23
|
-
* A post's object is not one of Fedify's paths at all. decision-13 makes a
|
|
24
|
-
* post's ActivityStreams id its permalink, so {@link activityStreamsDocument}
|
|
25
|
-
* is what serves the `Article`: one URL, answering a browser with the page and
|
|
26
|
-
* a peer with the object. The same handler answers at the `activitypub.id` a
|
|
27
|
-
* migrated post's file names, and sends a browser from there to the permalink.
|
|
28
|
-
*
|
|
29
|
-
* The dispatchers are handed the stores off the Hono context rather than
|
|
30
|
-
* closing over them, so one federation object could serve more than one CMS
|
|
31
|
-
* and so a dispatcher is never reading a store the request did not come with.
|
|
32
|
-
*/
|
|
33
|
-
export function mountFederation(app, federation, options = {}) {
|
|
34
|
-
// WebFinger is ours rather than Fedify's, and so has to be registered before
|
|
35
|
-
// the middleware that would otherwise answer it. Fedify hard-codes the
|
|
36
|
-
// `self` link to the dispatcher path and computes `aliases` from the
|
|
37
|
-
// resource, neither of which can be added to, so an actor served under the
|
|
38
|
-
// id it had elsewhere could never be discovered by it (doc-8). Owning the
|
|
39
|
-
// route is a dozen lines and gives complete control of `subject`, `aliases`
|
|
40
|
-
// and `links`.
|
|
41
|
-
app.get(WEBFINGER_PATH, (c) => {
|
|
42
|
-
const resource = c.req.query('resource') ?? '';
|
|
43
|
-
const user = webFingerSubject(c, resource);
|
|
44
|
-
if (user === undefined)
|
|
45
|
-
return c.notFound();
|
|
46
|
-
const context = federation.createContext(c.req.raw, contextData(c));
|
|
47
|
-
const { baseUrl } = c.var.config;
|
|
48
|
-
const aliases = actorAliases(context, user, baseUrl);
|
|
49
|
-
return c.json({
|
|
50
|
-
subject: acctOf(user.username, c.var.config.baseUrl),
|
|
51
|
-
aliases: aliases.map((alias) => alias.href),
|
|
52
|
-
links: [
|
|
53
|
-
{
|
|
54
|
-
rel: 'self',
|
|
55
|
-
type: 'application/activity+json',
|
|
56
|
-
href: actorId(context, user).href,
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
rel: 'http://webfinger.net/rel/profile-page',
|
|
60
|
-
type: 'text/html',
|
|
61
|
-
href: absoluteUrl(authorHref(user.username), baseUrl),
|
|
62
|
-
},
|
|
63
|
-
],
|
|
64
|
-
}, 200, {
|
|
65
|
-
// The media type RFC 7033 defines, and the header that lets a browser
|
|
66
|
-
// application read the answer, which is what every other WebFinger
|
|
67
|
-
// server sends.
|
|
68
|
-
'content-type': 'application/jrd+json; charset=utf-8',
|
|
69
|
-
'access-control-allow-origin': '*',
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
// `/@ada`, the short URL WordPress publishes beside the author archive and
|
|
73
|
-
// the one a person is most likely to type. It is an alias rather than a
|
|
74
|
-
// second identity, so it goes where the identity is.
|
|
75
|
-
app.get('/:handle{@.+}', async (c, next) => {
|
|
76
|
-
// The pattern is a regex rather than `/@:username`, because Hono's path
|
|
77
|
-
// parameters are whole segments: the `@` has to be matched inside one.
|
|
78
|
-
const handle = (c.req.param('handle') ?? '').slice(1);
|
|
79
|
-
// An alias is only an alias of somebody. The route used to send every
|
|
80
|
-
// handle to `/author/<whatever was typed>/`, so a profile link with a
|
|
81
|
-
// menu item's flag on the end of it — `https://shll.me/@a | me` — landed a
|
|
82
|
-
// reader on `/author/a%20%7C%20me/` instead of saying there is no such
|
|
83
|
-
// person (TASK-112). Spelled exactly, the way WebFinger matches: `Ada` and
|
|
84
|
-
// `ada` are two accounts on a screen that can tell them apart, and only
|
|
85
|
-
// one of them exists.
|
|
86
|
-
const user = listUsers(c.var.config.dataDir).find((account) => account.username === handle);
|
|
87
|
-
// The site's own not-found handler answers rather than a bare 404 here, so
|
|
88
|
-
// a handle nobody has gets the theme's 404 page like any other URL that is
|
|
89
|
-
// not there.
|
|
90
|
-
if (user === undefined)
|
|
91
|
-
return await next();
|
|
92
|
-
return c.redirect(authorHref(user.username), 301);
|
|
93
|
-
});
|
|
94
|
-
// `@fedify/hono` types its context as the two properties it actually reads,
|
|
95
|
-
// which is looser than Hono's own; the cast is what puts `c.var` back.
|
|
96
|
-
const fedify = federationMiddleware(federation, (context) => {
|
|
97
|
-
const c = context;
|
|
98
|
-
return contextData(c);
|
|
99
|
-
});
|
|
100
|
-
// The one path where Fedify and the public site both have a claim: a user's
|
|
101
|
-
// author archive is their actor id (decision-14), and Fedify answers a bare
|
|
102
|
-
// `Accept: application/json` as an ActivityStreams request while doc-3 gives
|
|
103
|
-
// that spelling the listing's own JSON. The CMS's rule decides, so a peer
|
|
104
|
-
// asking for `activity+json` or `ld+json` gets the actor and everything else
|
|
105
|
-
// — a browser, a reader, a feed tool — reaches the archive it asked for.
|
|
106
|
-
// Every other Fedify path is left exactly as it was.
|
|
107
|
-
const federationGate = async (c, next) => {
|
|
108
|
-
const isArchive = parseAuthorPath(requestPath(c)) !== undefined;
|
|
109
|
-
if (isArchive && !prefersActivityStreams(c.req.header('accept')))
|
|
110
|
-
return await next();
|
|
111
|
-
return await fedify(c, next);
|
|
112
|
-
};
|
|
113
|
-
app.use('*', federationGate);
|
|
114
|
-
if (options.plugins !== undefined)
|
|
115
|
-
app.use('*', options.plugins);
|
|
116
|
-
// Named, and typed as a middleware, so the Hono context arrives with its
|
|
117
|
-
// path parameters resolved rather than as `any`.
|
|
118
|
-
const activityStreams = async (c, next) => {
|
|
119
|
-
const response = (await activityStreamsActor(c, federation)) ?? (await activityStreamsDocument(c, federation));
|
|
120
|
-
if (response !== undefined)
|
|
121
|
-
return response;
|
|
122
|
-
await next();
|
|
123
|
-
};
|
|
124
|
-
app.use('*', activityStreams);
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* The person this request is about, when it asks at the id they were published
|
|
128
|
-
* under somewhere else: the `Person` for a peer, a redirect to the author
|
|
129
|
-
* archive for a browser, and `undefined` for everything else.
|
|
130
|
-
*
|
|
131
|
-
* The twin of {@link activityStreamsDocument}, and for the same reason
|
|
132
|
-
* (decision-14): a stored actor id is identity. A follower's server keys the
|
|
133
|
-
* account by the URL it first saw, so that URL has to keep answering with this
|
|
134
|
-
* person's actor for as long as the account exists, or every follow out there
|
|
135
|
-
* points at nothing.
|
|
136
|
-
*
|
|
137
|
-
* Fedify cannot serve it — its router matches paths, and a stored id is
|
|
138
|
-
* commonly a query string on the site root (doc-8) — so it is served here,
|
|
139
|
-
* ahead of the public site, exactly as a post's stored `activitypub.id` is.
|
|
140
|
-
*/
|
|
141
|
-
async function activityStreamsActor(c, federation) {
|
|
142
|
-
const user = storedActorAt(c);
|
|
143
|
-
if (user === undefined)
|
|
144
|
-
return undefined;
|
|
145
|
-
if (!prefersActivityStreams(c.req.header('accept'))) {
|
|
146
|
-
return c.redirect(authorHref(user.username), 301);
|
|
147
|
-
}
|
|
148
|
-
const context = federation.createContext(c.req.raw, contextData(c));
|
|
149
|
-
const actor = await userActor(context, user, { baseUrl: c.var.config.baseUrl });
|
|
150
|
-
return await respondWithObject(actor, { contextLoader: context.contextLoader });
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* The user whose stored actor id is the URL this request asks for, or
|
|
154
|
-
* `undefined`.
|
|
155
|
-
*
|
|
156
|
-
* Built the way {@link storedObjectAt} builds a post's candidate — the
|
|
157
|
-
* request's path and query on the site's base URL, rather than `request.url`,
|
|
158
|
-
* which behind a proxy is the internal address — and matched on the whole URL,
|
|
159
|
-
* query string and all, which is what decision-14 asks for.
|
|
160
|
-
*
|
|
161
|
-
* A user whose stored id happens to be their author URL is not one of these:
|
|
162
|
-
* the actor dispatcher has already answered for that URL, and answering again
|
|
163
|
-
* here would only redirect a browser to where it already is.
|
|
164
|
-
*/
|
|
165
|
-
function storedActorAt(c) {
|
|
166
|
-
const { search } = new URL(c.req.url);
|
|
167
|
-
const candidate = `${absoluteUrl(requestPath(c), c.var.config.baseUrl)}${search}`;
|
|
168
|
-
const user = listUsers(c.var.config.dataDir).find((entry) => entry.actorId === candidate);
|
|
169
|
-
if (user === undefined)
|
|
170
|
-
return undefined;
|
|
171
|
-
if (absoluteUrl(authorHref(user.username), c.var.config.baseUrl) === candidate)
|
|
172
|
-
return undefined;
|
|
173
|
-
return user;
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
|
-
* The post this request is about, when it is about one: the `Article` for a
|
|
177
|
-
* peer, a redirect to the permalink for a browser at a stored id, and
|
|
178
|
-
* `undefined` for everything else.
|
|
179
|
-
*
|
|
180
|
-
* Two URLs can name a post. Its permalink always does — that is the whole of
|
|
181
|
-
* decision-13, and a peer that dereferences a link somebody shared lands on
|
|
182
|
-
* the object rather than on a page it cannot read. The other is the
|
|
183
|
-
* `activitypub.id` a migrated post's file carries: the name its followers,
|
|
184
|
-
* its replies and, unless it sets a `guid`, its RSS subscribers already hold,
|
|
185
|
-
* which has to keep answering or every copy out there points at nothing. A
|
|
186
|
-
* browser that follows one of those old links is sent on to the permalink,
|
|
187
|
-
* because that is the URL a person should end up at.
|
|
188
|
-
*
|
|
189
|
-
* Anything else — a browser at a permalink, a `.md` or `.json` request, a
|
|
190
|
-
* page, a listing — gets `undefined` and falls through to the public site
|
|
191
|
-
* untouched.
|
|
192
|
-
*/
|
|
193
|
-
async function activityStreamsDocument(c, federation) {
|
|
194
|
-
const wantsObject = prefersActivityStreams(c.req.header('accept'));
|
|
195
|
-
if (wantsObject) {
|
|
196
|
-
const atPermalink = publicDocumentAt(c.var.store, requestPath(c));
|
|
197
|
-
if (atPermalink !== undefined && isFederatedDocument(atPermalink, c.var.store.now())) {
|
|
198
|
-
return await article(c, federation, atPermalink);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
const stored = storedObjectAt(c);
|
|
202
|
-
if (wantsObject) {
|
|
203
|
-
const trashed = stored ?? goneDocumentAt(c.var.store, requestPath(c));
|
|
204
|
-
if (trashed?.type === 'post' && isTrashedPath(trashed.path)) {
|
|
205
|
-
return isGone(trashed, c.var.store.now())
|
|
206
|
-
? await tombstone(c, federation, trashed)
|
|
207
|
-
: undefined;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
if (stored === undefined)
|
|
211
|
-
return undefined;
|
|
212
|
-
const now = c.var.store.now();
|
|
213
|
-
if (!isFederatedDocument(stored, now) && !isGone(stored, now)) {
|
|
214
|
-
return wantsObject ? notFound(c) : undefined;
|
|
215
|
-
}
|
|
216
|
-
if (wantsObject)
|
|
217
|
-
return await article(c, federation, stored);
|
|
218
|
-
// A renamed post's old URL is its stored id (decision-20). Once a new
|
|
219
|
-
// document takes that URL over, a browser there is reading the new one; the
|
|
220
|
-
// id keeps answering peers, who hold it as a name rather than a page.
|
|
221
|
-
if (publicDocumentAt(c.var.store, requestPath(c)) !== undefined)
|
|
222
|
-
return undefined;
|
|
223
|
-
return c.redirect(stored.permalink, 301);
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* The post whose `activitypub.id` is the URL this request asks for, or
|
|
227
|
-
* `undefined`.
|
|
228
|
-
*
|
|
229
|
-
* The candidate is built the way the ids themselves are — the request's path
|
|
230
|
-
* and query on the site's base URL — rather than taken from `request.url`,
|
|
231
|
-
* which behind a proxy is the internal address. A post whose stored id is its
|
|
232
|
-
* permalink is not one of these: the permalink lookup has already answered for
|
|
233
|
-
* it, and answering again here would only invite a redirect to itself.
|
|
234
|
-
*/
|
|
235
|
-
function storedObjectAt(c) {
|
|
236
|
-
const { search } = new URL(c.req.url);
|
|
237
|
-
const candidate = `${absoluteUrl(requestPath(c), c.var.config.baseUrl)}${search}`;
|
|
238
|
-
const document = c.var.store.getByStoredObjectId(candidate);
|
|
239
|
-
if (document === undefined || document.type !== 'post')
|
|
240
|
-
return undefined;
|
|
241
|
-
if (absoluteUrl(document.permalink, c.var.config.baseUrl) === candidate)
|
|
242
|
-
return undefined;
|
|
243
|
-
return document;
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* One post as the ActivityStreams response a peer asked for.
|
|
247
|
-
*
|
|
248
|
-
* The object is built through the same {@link postObject} the outbox uses,
|
|
249
|
-
* off a context Fedify makes for this request, so the object a peer fetches
|
|
250
|
-
* and the one it is delivered cannot drift apart.
|
|
251
|
-
*/
|
|
252
|
-
async function article(c, federation, document) {
|
|
253
|
-
const context = federation.createContext(c.req.raw, contextData(c));
|
|
254
|
-
if (listUsers(c.var.config.dataDir).length === 0)
|
|
255
|
-
return notFound(c);
|
|
256
|
-
return await respondWithObject(postObject(context, document), {
|
|
257
|
-
contextLoader: context.contextLoader,
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
async function tombstone(c, federation, document) {
|
|
261
|
-
const context = federation.createContext(c.req.raw, contextData(c));
|
|
262
|
-
const response = await respondWithObject(postTombstone(context, document), {
|
|
263
|
-
contextLoader: context.contextLoader,
|
|
264
|
-
});
|
|
265
|
-
return new Response(response.body, { status: 410, headers: response.headers });
|
|
266
|
-
}
|
|
267
|
-
/** Where WebFinger lives, which is defined on the host rather than under a site. */
|
|
268
|
-
export const WEBFINGER_PATH = '/.well-known/webfinger';
|
|
269
|
-
/** `acct:{username}@{host}`, the handle a person types into a search box. */
|
|
270
|
-
export function acctOf(username, baseUrl) {
|
|
271
|
-
return `acct:${accountOf(username, baseUrl)}`;
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
* The user a WebFinger `resource` asks about, or `undefined` for one this site
|
|
275
|
-
* answers for nobody.
|
|
276
|
-
*
|
|
277
|
-
* Every spelling of a person resolves, and they are the ones decision-14 lists
|
|
278
|
-
* as their aliases: the `acct:` handle, the author archive, `/@{username}` and
|
|
279
|
-
* — for somebody who was published elsewhere first — the id they were
|
|
280
|
-
* published under. Matching every one of them is what lets a peer that holds
|
|
281
|
-
* any one URL for this person find the others, which is the whole job of
|
|
282
|
-
* WebFinger, and it is how a server holding only `?author=2` discovers that
|
|
283
|
-
* the account it follows is still here.
|
|
284
|
-
*
|
|
285
|
-
* Both sides of the comparison go through {@link canonicalResource} first, so
|
|
286
|
-
* the spellings that differ only in how they were typed are one spelling by
|
|
287
|
-
* the time they are matched, and no spelling needs a branch of its own.
|
|
288
|
-
*/
|
|
289
|
-
export function webFingerSubject(c, resource) {
|
|
290
|
-
const wanted = canonicalResource(resource);
|
|
291
|
-
if (wanted === '')
|
|
292
|
-
return undefined;
|
|
293
|
-
const { baseUrl } = c.var.config;
|
|
294
|
-
return listUsers(c.var.config.dataDir).find((user) => [
|
|
295
|
-
acctOf(user.username, baseUrl),
|
|
296
|
-
absoluteUrl(authorHref(user.username), baseUrl),
|
|
297
|
-
absoluteUrl(handleHref(user.username), baseUrl),
|
|
298
|
-
...(user.actorId === undefined ? [] : [user.actorId]),
|
|
299
|
-
].some((spelling) => canonicalResource(spelling) === wanted));
|
|
300
|
-
}
|
|
301
|
-
/**
|
|
302
|
-
* One resource in the spelling every equivalent one reduces to.
|
|
303
|
-
*
|
|
304
|
-
* A host is case-insensitive — in DNS, in RFC 3986 and in RFC 7033 — so
|
|
305
|
-
* `acct:ada@EXAMPLE.COM` names the same person as `acct:ada@example.com` and
|
|
306
|
-
* has to find them. A username is not: Geekity compares one case sensitively
|
|
307
|
-
* (see {@link User.username}), so the case is left exactly as it was asked
|
|
308
|
-
* for and `acct:Ada@example.com` stays somebody this site does not have.
|
|
309
|
-
*
|
|
310
|
-
* A bare `user@host` is not what RFC 7033 asks for, but it is what enough
|
|
311
|
-
* clients send that refusing it would only look like a missing account, and
|
|
312
|
-
* the same goes for the leading `@` of `@ada@example.com`, which is how the
|
|
313
|
-
* handle is written everywhere a person reads it. Both are spelled back out
|
|
314
|
-
* as the `acct:` URI they meant.
|
|
315
|
-
*/
|
|
316
|
-
function canonicalResource(resource) {
|
|
317
|
-
const trimmed = resource.trim();
|
|
318
|
-
// A URL carries its own rules, and `URL` applies them: the scheme and the
|
|
319
|
-
// host come back lower-cased, the path untouched.
|
|
320
|
-
if (/^[a-z][a-z\d+.-]*:\/\//i.test(trimmed)) {
|
|
321
|
-
try {
|
|
322
|
-
return new URL(trimmed).href;
|
|
323
|
-
}
|
|
324
|
-
catch {
|
|
325
|
-
return trimmed;
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
const handle = trimmed.replace(/^acct:/i, '').replace(/^@/, '');
|
|
329
|
-
const at = handle.lastIndexOf('@');
|
|
330
|
-
if (at <= 0)
|
|
331
|
-
return handle;
|
|
332
|
-
return `acct:${handle.slice(0, at)}@${handle.slice(at + 1).toLowerCase()}`;
|
|
333
|
-
}
|
|
334
|
-
/** What the dispatchers are handed, off the Hono context. */
|
|
335
|
-
export function contextData(c) {
|
|
336
|
-
return {
|
|
337
|
-
admin: c.var.admin,
|
|
338
|
-
store: c.var.store,
|
|
339
|
-
config: c.var.config,
|
|
340
|
-
actorProfiles: c.var.actorProfiles,
|
|
341
|
-
cited: (url) => c.var.replyContexts.read(url),
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
//# sourceMappingURL=mount.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mount.js","sourceRoot":"","sources":["../../src/federation/mount.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What a site needs to prove it may send: `data/mail.json`.
|
|
3
|
-
*
|
|
4
|
-
* A credential, not a setting, so it lives where the Akismet key and the
|
|
5
|
-
* password hashes live — under `data/` at mode `0600` — and never in
|
|
6
|
-
* `content/_data/site.json`, which is public, in git and published with the
|
|
7
|
-
* site. Which provider is in use, who mail is from and where a reply goes are
|
|
8
|
-
* settings and are in `site.json`; the key and the SMTP password are here.
|
|
9
|
-
*
|
|
10
|
-
* Read on every send, like the Akismet key, so a credential pasted into the
|
|
11
|
-
* settings screen sends the next message and one removed stops sending at
|
|
12
|
-
* once, neither of them needing a restart.
|
|
13
|
-
*/
|
|
14
|
-
/** Where the credentials live, under `dataDir`. */
|
|
15
|
-
export declare const MAIL_CREDENTIALS_FILE = "mail.json";
|
|
16
|
-
/** Brevo's half: one API key. */
|
|
17
|
-
export interface BrevoCredential {
|
|
18
|
-
/** The account's API key, `xkeysib-…`. */
|
|
19
|
-
readonly apiKey: string;
|
|
20
|
-
}
|
|
21
|
-
/** SMTP's half: the whole connection, because all of it is a credential. */
|
|
22
|
-
export interface SmtpCredential {
|
|
23
|
-
/** The server's hostname. */
|
|
24
|
-
readonly host: string;
|
|
25
|
-
/** The port: 587 for submission with STARTTLS, 465 for implicit TLS. */
|
|
26
|
-
readonly port: number;
|
|
27
|
-
/** Whether the connection is TLS from the first byte, which is port 465. */
|
|
28
|
-
readonly secure: boolean;
|
|
29
|
-
/** The username. Empty for a server that wants no credentials. */
|
|
30
|
-
readonly user: string;
|
|
31
|
-
/** The password. */
|
|
32
|
-
readonly password: string;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* The file's whole contents: at most one entry per provider.
|
|
36
|
-
*
|
|
37
|
-
* Both may be present at once, and that is deliberate — a site trying SMTP
|
|
38
|
-
* after Brevo should be able to switch the `mailProvider` setting back without
|
|
39
|
-
* having to paste a key in again.
|
|
40
|
-
*/
|
|
41
|
-
export interface MailCredentials {
|
|
42
|
-
/** Brevo's key, when the site has one. */
|
|
43
|
-
readonly brevo?: BrevoCredential | undefined;
|
|
44
|
-
/** The SMTP connection, when the site has one. */
|
|
45
|
-
readonly smtp?: SmtpCredential | undefined;
|
|
46
|
-
}
|
|
47
|
-
/** Where one site's credential file is. */
|
|
48
|
-
export declare function mailCredentialsPath(dataDir: string): string;
|
|
49
|
-
/**
|
|
50
|
-
* The stored credentials, or an empty object when the site has none.
|
|
51
|
-
*
|
|
52
|
-
* Read tolerantly and synchronously, like every other file this CMS treats as
|
|
53
|
-
* truth: a file that will not parse, or an entry missing the one field that
|
|
54
|
-
* makes it usable, is a site with no mail rather than a site that will not
|
|
55
|
-
* boot.
|
|
56
|
-
*/
|
|
57
|
-
export declare function readMailCredentials(dataDir: string): MailCredentials;
|
|
58
|
-
/** Write the credentials, private to the account the site runs as. */
|
|
59
|
-
export declare function writeMailCredentials(dataDir: string, credentials: MailCredentials): Promise<void>;
|
|
60
|
-
/** Forget them, which is how a site stops sending mail entirely. */
|
|
61
|
-
export declare function removeMailCredentials(dataDir: string): Promise<void>;
|
|
62
|
-
//# sourceMappingURL=credentials.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/mail/credentials.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;GAYG;AAEH,mDAAmD;AACnD,eAAO,MAAM,qBAAqB,cAAc,CAAC;AAEjD,iCAAiC;AACjC,MAAM,WAAW,eAAe;IAC9B,0CAA0C;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC7B,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oBAAoB;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,0CAA0C;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IAC7C,kDAAkD;IAClD,QAAQ,CAAC,IAAI,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;CAC5C;AAED,2CAA2C;AAC3C,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAkBpE;AAED,sEAAsE;AACtE,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,eAAe,GAC3B,OAAO,CAAC,IAAI,CAAC,CAMf;AAED,oEAAoE;AACpE,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1E"}
|
package/dist/mail/credentials.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { rm } from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { readFileIfPresentSync, writeFileAtomically } from '../files/atomic.js';
|
|
4
|
-
/**
|
|
5
|
-
* What a site needs to prove it may send: `data/mail.json`.
|
|
6
|
-
*
|
|
7
|
-
* A credential, not a setting, so it lives where the Akismet key and the
|
|
8
|
-
* password hashes live — under `data/` at mode `0600` — and never in
|
|
9
|
-
* `content/_data/site.json`, which is public, in git and published with the
|
|
10
|
-
* site. Which provider is in use, who mail is from and where a reply goes are
|
|
11
|
-
* settings and are in `site.json`; the key and the SMTP password are here.
|
|
12
|
-
*
|
|
13
|
-
* Read on every send, like the Akismet key, so a credential pasted into the
|
|
14
|
-
* settings screen sends the next message and one removed stops sending at
|
|
15
|
-
* once, neither of them needing a restart.
|
|
16
|
-
*/
|
|
17
|
-
/** Where the credentials live, under `dataDir`. */
|
|
18
|
-
export const MAIL_CREDENTIALS_FILE = 'mail.json';
|
|
19
|
-
/** Where one site's credential file is. */
|
|
20
|
-
export function mailCredentialsPath(dataDir) {
|
|
21
|
-
return path.join(dataDir, MAIL_CREDENTIALS_FILE);
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* The stored credentials, or an empty object when the site has none.
|
|
25
|
-
*
|
|
26
|
-
* Read tolerantly and synchronously, like every other file this CMS treats as
|
|
27
|
-
* truth: a file that will not parse, or an entry missing the one field that
|
|
28
|
-
* makes it usable, is a site with no mail rather than a site that will not
|
|
29
|
-
* boot.
|
|
30
|
-
*/
|
|
31
|
-
export function readMailCredentials(dataDir) {
|
|
32
|
-
const raw = readFileIfPresentSync(mailCredentialsPath(dataDir));
|
|
33
|
-
if (raw === undefined)
|
|
34
|
-
return {};
|
|
35
|
-
let parsed;
|
|
36
|
-
try {
|
|
37
|
-
parsed = JSON.parse(raw);
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
return {};
|
|
41
|
-
}
|
|
42
|
-
if (typeof parsed !== 'object' || parsed === null)
|
|
43
|
-
return {};
|
|
44
|
-
const file = parsed;
|
|
45
|
-
return {
|
|
46
|
-
...(brevoIn(file['brevo']) === undefined ? {} : { brevo: brevoIn(file['brevo']) }),
|
|
47
|
-
...(smtpIn(file['smtp']) === undefined ? {} : { smtp: smtpIn(file['smtp']) }),
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
/** Write the credentials, private to the account the site runs as. */
|
|
51
|
-
export async function writeMailCredentials(dataDir, credentials) {
|
|
52
|
-
await writeFileAtomically(mailCredentialsPath(dataDir), `${JSON.stringify(credentials, null, 2)}\n`, { mode: 0o600 });
|
|
53
|
-
}
|
|
54
|
-
/** Forget them, which is how a site stops sending mail entirely. */
|
|
55
|
-
export async function removeMailCredentials(dataDir) {
|
|
56
|
-
await rm(mailCredentialsPath(dataDir), { force: true });
|
|
57
|
-
}
|
|
58
|
-
/** One Brevo entry, or nothing when it carries no key. */
|
|
59
|
-
function brevoIn(value) {
|
|
60
|
-
if (typeof value !== 'object' || value === null)
|
|
61
|
-
return undefined;
|
|
62
|
-
const entry = value;
|
|
63
|
-
const apiKey = typeof entry['apiKey'] === 'string' ? entry['apiKey'].trim() : '';
|
|
64
|
-
return apiKey === '' ? undefined : { apiKey };
|
|
65
|
-
}
|
|
66
|
-
/** One SMTP entry, or nothing when it names no host to connect to. */
|
|
67
|
-
function smtpIn(value) {
|
|
68
|
-
if (typeof value !== 'object' || value === null)
|
|
69
|
-
return undefined;
|
|
70
|
-
const entry = value;
|
|
71
|
-
const host = typeof entry['host'] === 'string' ? entry['host'].trim() : '';
|
|
72
|
-
if (host === '')
|
|
73
|
-
return undefined;
|
|
74
|
-
const port = Number(entry['port']);
|
|
75
|
-
const secure = entry['secure'] === true;
|
|
76
|
-
return {
|
|
77
|
-
host,
|
|
78
|
-
// 465 when the connection is TLS from the first byte, 587 otherwise:
|
|
79
|
-
// the two submission ports, so a file that lost its port still connects.
|
|
80
|
-
port: Number.isInteger(port) && port > 0 && port < 65536 ? port : secure ? 465 : 587,
|
|
81
|
-
secure,
|
|
82
|
-
user: typeof entry['user'] === 'string' ? entry['user'] : '',
|
|
83
|
-
password: typeof entry['password'] === 'string' ? entry['password'] : '',
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
//# sourceMappingURL=credentials.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/mail/credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type { SiteLicense, SiteSettings } from './settings.ts';
|
|
2
|
-
export type CarriedField = 'taxonomy_redirects' | 'menus' | 'index_now_key' | 'clients_without_pkce' | 'avatar';
|
|
3
|
-
type FormKey = Exclude<keyof SiteSettings, CarriedField>;
|
|
4
|
-
export type SettingsField = FormKey | 'license_url' | 'license_name';
|
|
5
|
-
export type CarriedSettings = Partial<Pick<SiteSettings, CarriedField>>;
|
|
6
|
-
/** A submitted settings form, before it is known to be valid. */
|
|
7
|
-
export type SettingsForm = Record<SettingsField, string>;
|
|
8
|
-
export interface SettingsDirs {
|
|
9
|
-
readonly themesDir: string;
|
|
10
|
-
readonly contentDir: string;
|
|
11
|
-
}
|
|
12
|
-
export type SettingsContext = {
|
|
13
|
-
readonly [D in keyof SettingsDirs]?: string | undefined;
|
|
14
|
-
};
|
|
15
|
-
export interface OnDiskCheck {
|
|
16
|
-
readonly dir: keyof SettingsDirs;
|
|
17
|
-
readonly problem: (value: string, dir: string) => string | undefined;
|
|
18
|
-
}
|
|
19
|
-
export interface SettingRow<V> {
|
|
20
|
-
readonly submitted: (form: SettingsForm, onFile: CarriedSettings) => V;
|
|
21
|
-
}
|
|
22
|
-
export interface FieldRow<V> {
|
|
23
|
-
readonly field: string;
|
|
24
|
-
readonly shown: (value: V) => string;
|
|
25
|
-
readonly check: (form: SettingsForm) => string | undefined;
|
|
26
|
-
readonly onDisk?: OnDiskCheck;
|
|
27
|
-
}
|
|
28
|
-
export type FormSettingRow<V> = SettingRow<V> & FieldRow<V>;
|
|
29
|
-
export type FieldValue<F extends SettingsField> = F extends keyof SiteSettings ? SiteSettings[F] : SiteLicense;
|
|
30
|
-
export declare function requiredWholeDays(typed: string): number | undefined;
|
|
31
|
-
export type FrontPage = Pick<SiteSettings, 'homepage' | 'posts_page'>;
|
|
32
|
-
export declare function frontPageOf(form: SettingsForm): FrontPage;
|
|
33
|
-
export declare function frontPageProblems(form: SettingsForm): {
|
|
34
|
-
readonly [K in keyof FrontPage]?: string | undefined;
|
|
35
|
-
};
|
|
36
|
-
export declare const ROWS: {
|
|
37
|
-
readonly [K in keyof SiteSettings]: SettingRow<SiteSettings[K]>;
|
|
38
|
-
};
|
|
39
|
-
export declare const FORM_ROWS: {
|
|
40
|
-
readonly [F in SettingsField]: FieldRow<FieldValue<F>>;
|
|
41
|
-
};
|
|
42
|
-
export declare const SETTING_KEYS: readonly (keyof SiteSettings)[];
|
|
43
|
-
export declare const SETTINGS_FIELD_NAMES: readonly SettingsField[];
|
|
44
|
-
export {};
|
|
45
|
-
//# sourceMappingURL=setting-rows.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"setting-rows.d.ts","sourceRoot":"","sources":["../../src/site/setting-rows.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE/D,MAAM,MAAM,YAAY,GACtB,oBAAoB,GAAG,OAAO,GAAG,eAAe,GAAG,sBAAsB,GAAG,QAAQ,CAAC;AAEvF,KAAK,OAAO,GAAG,OAAO,CAAC,MAAM,YAAY,EAAE,YAAY,CAAC,CAAC;AAEzD,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,aAAa,GAAG,cAAc,CAAC;AAErE,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;AAExE,iEAAiE;AACjE,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;AAEzD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,eAAe,GAAG;IAAE,QAAQ,EAAE,CAAC,IAAI,MAAM,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS;CAAE,CAAC;AAE1F,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,YAAY,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;CACtE;AAED,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,eAAe,KAAK,CAAC,CAAC;CACxE;AAED,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,MAAM,GAAG,SAAS,CAAC;IAC3D,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;AAE5D,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,aAAa,IAAI,CAAC,SAAS,MAAM,YAAY,GAC1E,YAAY,CAAC,CAAC,CAAC,GACf,WAAW,CAAC;AAqEhB,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKnE;AAqED,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE,UAAU,GAAG,YAAY,CAAC,CAAC;AAEtE,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,SAAS,CAGzD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG;IACrD,QAAQ,EAAE,CAAC,IAAI,MAAM,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS;CACrD,CAMA;AA0VD,eAAO,MAAM,IAAI,EAAE;IAAE,QAAQ,EAAE,CAAC,IAAI,MAAM,YAAY,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;CACtE,CAAC;AAEf,eAAO,MAAM,SAAS,EAAE;IAAE,QAAQ,EAAE,CAAC,IAAI,aAAa,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;CAG/E,CAAC;AAEF,eAAO,MAAM,YAAY,EAAgC,SAAS,CAAC,MAAM,YAAY,CAAC,EAAE,CAAC;AAMzF,eAAO,MAAM,oBAAoB,EAAE,SAAS,aAAa,EAIxD,CAAC"}
|