fedipod-server 0.19.0 → 0.20.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/dist/claims.js +3 -2
- package/lib/core/publisher/index.mjs +1 -1
- package/lib/core/wire.mjs +5 -2
- package/lib/device/admin/surface.mjs +8 -0
- package/lib/gateway/front-core.mjs +25 -3
- package/package.json +1 -1
- package/web/app/dist/sw.js +6 -3
- package/web/app/dist/sw.js.map +3 -3
- package/web/app/site/_redirects +1 -0
- package/web/app/site/sw.js +290 -72
package/dist/claims.js
CHANGED
|
@@ -19,7 +19,8 @@ function claims(input, frontHost) {
|
|
|
19
19
|
const bare = String(input.host).split(':')[0].toLowerCase();
|
|
20
20
|
if (bare !== String(frontHost).toLowerCase())
|
|
21
21
|
return false; // a pod subdomain → not ours
|
|
22
|
-
return FRONT_PATHS.has(input.pathname) || input.pathname.startsWith('/u/')
|
|
22
|
+
return FRONT_PATHS.has(input.pathname) || input.pathname.startsWith('/u/')
|
|
23
|
+
|| input.pathname.startsWith('/@'); // the short profile address
|
|
23
24
|
}
|
|
24
25
|
// What an identity answers on its own pod's origin: the protocol routes other
|
|
25
26
|
// software addresses it by, and the one path its owner's pages live under.
|
|
@@ -35,7 +36,7 @@ const AGENT_PATHS = new Set([
|
|
|
35
36
|
// at this name before, so no pod resource is displaced.
|
|
36
37
|
'/.well-known/oauth-authorization-server',
|
|
37
38
|
]);
|
|
38
|
-
const AGENT_PREFIXES = ['/api/', '/oauth/'];
|
|
39
|
+
const AGENT_PREFIXES = ['/api/', '/oauth/', '/@']; // /@handle: the short profile address
|
|
39
40
|
// An identity's inbox is the container `/<root>/ap/inbox/`, matched by shape
|
|
40
41
|
// rather than a fixed root. A POST here is a delivery, verified at the door
|
|
41
42
|
// before it is written; the handler checks the exact path per identity. The
|
|
@@ -143,7 +143,7 @@ export class Publisher {
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
await discovery.writeWebfinger(this.remote, urls,
|
|
146
|
-
wire.jrd({ handle: this.config.handle, host, actor: urls.actor }));
|
|
146
|
+
wire.jrd({ handle: this.config.handle, host, actor: urls.actor, page: urls.profileHtml }));
|
|
147
147
|
await discovery.writeHostMeta(this.remote, urls, wire.hostMeta(urls.base));
|
|
148
148
|
|
|
149
149
|
const nodeinfoDocUrl = urls.home + 'ap/nodeinfo-2.0';
|
package/lib/core/wire.mjs
CHANGED
|
@@ -52,11 +52,14 @@ export function hostMeta(base) {
|
|
|
52
52
|
return `<?xml version="1.0" encoding="UTF-8"?>\n<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">\n <Link rel="lrdd" template="${base}.well-known/webfinger?resource={uri}"/>\n</XRD>\n`;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
export function jrd({ handle, host, actor, aliases = [] }) {
|
|
55
|
+
export function jrd({ handle, host, actor, aliases = [], page = null }) {
|
|
56
56
|
return {
|
|
57
57
|
subject: `acct:${handle}@${host}`,
|
|
58
58
|
...(aliases.length ? { aliases } : {}),
|
|
59
|
-
links: [
|
|
59
|
+
links: [
|
|
60
|
+
{ rel: 'self', type: 'application/activity+json', href: actor },
|
|
61
|
+
...(page ? [{ rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: page }] : []),
|
|
62
|
+
],
|
|
60
63
|
};
|
|
61
64
|
}
|
|
62
65
|
|
|
@@ -181,6 +181,14 @@ export function buildAdminSurface({ agent, gate, allowed, log = console.log,
|
|
|
181
181
|
const scheme = req.socket.encrypted || req.headers['x-forwarded-proto'] === 'https' ? 'https' : 'http';
|
|
182
182
|
return json(res, 200, masto.authorizationServerMetadata(`${scheme}://${req.headers.host}${mount}`));
|
|
183
183
|
}
|
|
184
|
+
// The short address a person types: /@handle opens the profile page.
|
|
185
|
+
const at = /^\/@([^/]+)$/u.exec(p);
|
|
186
|
+
const ownHandle = handle || agent.store?.getConfig?.()?.handle || '';
|
|
187
|
+
if (at && ownHandle && agent.publisher?.urls?.profileHtml
|
|
188
|
+
&& decodeURIComponent(at[1]).toLowerCase() === String(ownHandle).toLowerCase()) {
|
|
189
|
+
res.writeHead(302, { location: agent.publisher.urls.profileHtml, 'cache-control': 'no-store' });
|
|
190
|
+
res.end(); return;
|
|
191
|
+
}
|
|
184
192
|
if (atDoor && gate(req, res)) return;
|
|
185
193
|
if (p === '/api/v1/streaming/health') {
|
|
186
194
|
res.writeHead(200, { 'content-type': 'text/plain' }); res.end('OK'); return;
|
|
@@ -26,11 +26,17 @@ import { podBaseOfWebId } from '../pod/urls.mjs';
|
|
|
26
26
|
// wire.mjs: wire drags the agent's whole HTML pipeline (sanitize-html and
|
|
27
27
|
// friends), which a serverless front must never carry — it crashed the
|
|
28
28
|
// deployed function before it answered its first request.
|
|
29
|
-
const jrd = ({ handle, host, actor, aliases = [] }) => ({
|
|
29
|
+
const jrd = ({ handle, host, actor, aliases = [], page = null }) => ({
|
|
30
30
|
subject: `acct:${handle}@${host}`,
|
|
31
31
|
...(aliases.length ? { aliases } : {}),
|
|
32
|
-
links: [
|
|
32
|
+
links: [
|
|
33
|
+
{ rel: 'self', type: 'application/activity+json', href: actor },
|
|
34
|
+
...(page ? [{ rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: page }] : []),
|
|
35
|
+
],
|
|
33
36
|
});
|
|
37
|
+
// The public profile page of any account the front answers for lives on
|
|
38
|
+
// its pod, whether the address is the front's or the pod's own.
|
|
39
|
+
const profilePageOf = (rec) => (rec?.podHome ? rec.podHome + 'ap/profile.html' : null);
|
|
34
40
|
|
|
35
41
|
const AP_CT = 'application/activity+json';
|
|
36
42
|
|
|
@@ -600,13 +606,29 @@ async function route(request, ctx) {
|
|
|
600
606
|
// is the alias, so a client signing in by the fronted address can find
|
|
601
607
|
// the pod (and its login) without a lookup only the host could answer.
|
|
602
608
|
const podActor = rec.inboxOnly ? [] : [rec.podHome + 'ap/actor'];
|
|
603
|
-
const out = j(200, jrd({ handle: m[1], host: ctx.host, actor: rec.actorUrl, aliases: podActor }),
|
|
609
|
+
const out = j(200, jrd({ handle: m[1], host: ctx.host, actor: rec.actorUrl, aliases: podActor, page: profilePageOf(rec) }),
|
|
604
610
|
'application/jrd+json');
|
|
605
611
|
// RFC 7033: a JRD is read from any origin.
|
|
606
612
|
out.headers['access-control-allow-origin'] = '*';
|
|
607
613
|
return out;
|
|
608
614
|
}
|
|
609
615
|
|
|
616
|
+
// The short address a person types: https://<host>/@handle opens the
|
|
617
|
+
// profile page, the way most Fediverse servers spell it. /@handle@pod-host
|
|
618
|
+
// is the same for an account whose address is its pod's, which the front
|
|
619
|
+
// holds under that full address — the form other servers use for a
|
|
620
|
+
// profile that lives elsewhere.
|
|
621
|
+
const at = /^\/@([^/@]+)(?:@([^/@]+))?$/u.exec(pathname);
|
|
622
|
+
if (at) {
|
|
623
|
+
const handle = decodeURIComponent(at[1]).toLowerCase();
|
|
624
|
+
const host = at[2] ? decodeURIComponent(at[2]).toLowerCase() : null;
|
|
625
|
+
const key = host && host !== String(ctx.host).toLowerCase() ? `${handle}@${host}` : handle;
|
|
626
|
+
const rec = await ctx.lookup(key);
|
|
627
|
+
const page = rec && profilePageOf(rec);
|
|
628
|
+
if (!page) return notFound();
|
|
629
|
+
return { status: 302, headers: { location: page, 'cache-control': 'no-store' }, body: '' };
|
|
630
|
+
}
|
|
631
|
+
|
|
610
632
|
const up = parseUserPath(pathname);
|
|
611
633
|
if (!up) return notFound();
|
|
612
634
|
const rec = await ctx.lookup(up.handle);
|
package/package.json
CHANGED
package/web/app/dist/sw.js
CHANGED
|
@@ -9664,11 +9664,14 @@ function hostMeta(base) {
|
|
|
9664
9664
|
</XRD>
|
|
9665
9665
|
`;
|
|
9666
9666
|
}
|
|
9667
|
-
function jrd({ handle: handle7, host, actor, aliases = [] }) {
|
|
9667
|
+
function jrd({ handle: handle7, host, actor, aliases = [], page: page2 = null }) {
|
|
9668
9668
|
return {
|
|
9669
9669
|
subject: `acct:${handle7}@${host}`,
|
|
9670
9670
|
...aliases.length ? { aliases } : {},
|
|
9671
|
-
links: [
|
|
9671
|
+
links: [
|
|
9672
|
+
{ rel: "self", type: "application/activity+json", href: actor },
|
|
9673
|
+
...page2 ? [{ rel: "http://webfinger.net/rel/profile-page", type: "text/html", href: page2 }] : []
|
|
9674
|
+
]
|
|
9672
9675
|
};
|
|
9673
9676
|
}
|
|
9674
9677
|
function followsNeedApproval(config = {}) {
|
|
@@ -56784,7 +56787,7 @@ var Publisher = class {
|
|
|
56784
56787
|
await writeWebfinger(
|
|
56785
56788
|
this.remote,
|
|
56786
56789
|
urls,
|
|
56787
|
-
jrd({ handle: this.config.handle, host, actor: urls.actor })
|
|
56790
|
+
jrd({ handle: this.config.handle, host, actor: urls.actor, page: urls.profileHtml })
|
|
56788
56791
|
);
|
|
56789
56792
|
await writeHostMeta(this.remote, urls, hostMeta(urls.base));
|
|
56790
56793
|
const nodeinfoDocUrl = urls.home + "ap/nodeinfo-2.0";
|