* Create xml.ts * Update well-known.ts * Update well-known.ts * Fix typo * Update well-known.ts * Update well-known.ts
This commit is contained in:
parent
5aadd80243
commit
81aa21915b
2 changed files with 89 additions and 22 deletions
41
src/prelude/xml.ts
Normal file
41
src/prelude/xml.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
const map: Record<string, string> = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
'\'': '''
|
||||
};
|
||||
|
||||
const beginingOfCDATA = '<![CDATA[';
|
||||
const endOfCDATA = ']]>';
|
||||
|
||||
export function escapeValue(x: string): string {
|
||||
let insideOfCDATA = false;
|
||||
let builder = '';
|
||||
for (
|
||||
let i = 0;
|
||||
i < x.length;
|
||||
) {
|
||||
if (insideOfCDATA) {
|
||||
if (x.slice(i, i + beginingOfCDATA.length) === beginingOfCDATA) {
|
||||
insideOfCDATA = true;
|
||||
i += beginingOfCDATA.length;
|
||||
} else {
|
||||
builder += x[i++];
|
||||
}
|
||||
} else {
|
||||
if (x.slice(i, i + endOfCDATA.length) === endOfCDATA) {
|
||||
insideOfCDATA = false;
|
||||
i += endOfCDATA.length;
|
||||
} else {
|
||||
const b = x[i++];
|
||||
builder += map[b] || b;
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
export function escapeAttribute(x: string): string {
|
||||
return Object.entries(map).reduce((a, [k, v]) => a.replace(k, v), x);
|
||||
}
|
|
@ -6,27 +6,37 @@ import parseAcct from '../misc/acct/parse';
|
|||
import User from '../models/user';
|
||||
import Acct from '../misc/acct/type';
|
||||
import { links } from './nodeinfo';
|
||||
import { escapeAttribute, escapeValue } from '../prelude/xml';
|
||||
|
||||
// Init router
|
||||
const router = new Router();
|
||||
|
||||
const XRD = (...x: { element: string, value?: string, attributes?: Record<string, string> }[]) =>
|
||||
`<?xml version="1.0" encoding="UTF-8"?><XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">${x.map(({ element, value, attributes }) =>
|
||||
`<${
|
||||
Object.entries(typeof attributes === 'object' && attributes || {}).reduce((a, [k, v]) => `${a} ${k}="${escapeAttribute(v)}"`, element)
|
||||
}${
|
||||
typeof value === 'string' ? `>${escapeValue(value)}</${element}` : '/'
|
||||
}>`).reduce((a, c) => a + c, '')}</XRD>`;
|
||||
|
||||
const webFingerPath = '/.well-known/webfinger';
|
||||
const jrd = 'application/jrd+json';
|
||||
const xrd = 'application/xrd+xml';
|
||||
|
||||
router.get('/.well-known/host-meta', async ctx => {
|
||||
ctx.set('Content-Type', 'application/xrd+xml');
|
||||
ctx.body = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
|
||||
<Link rel="lrdd" type="application/xrd+xml" template="${config.url}${webFingerPath}?resource={uri}"/>
|
||||
</XRD>
|
||||
`;
|
||||
ctx.set('Content-Type', xrd);
|
||||
ctx.body = XRD({ element: 'Link', attributes: {
|
||||
type: xrd,
|
||||
template: `${config.url}${webFingerPath}?resource={uri}`
|
||||
}});
|
||||
});
|
||||
|
||||
router.get('/.well-known/host-meta.json', async ctx => {
|
||||
ctx.set('Content-Type', 'application/jrd+json');
|
||||
ctx.set('Content-Type', jrd);
|
||||
ctx.body = {
|
||||
links: [{
|
||||
rel: 'lrdd',
|
||||
type: 'application/xrd+xml',
|
||||
type: jrd,
|
||||
template: `${config.url}${webFingerPath}?resource={uri}`
|
||||
}]
|
||||
};
|
||||
|
@ -75,22 +85,38 @@ router.get(webFingerPath, async ctx => {
|
|||
return;
|
||||
}
|
||||
|
||||
ctx.body = {
|
||||
subject: `acct:${user.username}@${config.host}`,
|
||||
links: [{
|
||||
rel: 'self',
|
||||
type: 'application/activity+json',
|
||||
href: `${config.url}/users/${user._id}`
|
||||
}, {
|
||||
rel: 'http://webfinger.net/rel/profile-page',
|
||||
type: 'text/html',
|
||||
href: `${config.url}/@${user.username}`
|
||||
}, {
|
||||
rel: 'http://ostatus.org/schema/1.0/subscribe',
|
||||
template: `${config.url}/authorize-follow?acct={uri}`
|
||||
}]
|
||||
const subject = `acct:${user.username}@${config.host}`;
|
||||
const self = {
|
||||
rel: 'self',
|
||||
type: 'application/activity+json',
|
||||
href: `${config.url}/users/${user._id}`
|
||||
};
|
||||
const profilePage = {
|
||||
rel: 'http://webfinger.net/rel/profile-page',
|
||||
type: 'text/html',
|
||||
href: `${config.url}/@${user.username}`
|
||||
};
|
||||
const subscribe = {
|
||||
rel: 'http://ostatus.org/schema/1.0/subscribe',
|
||||
template: `${config.url}/authorize-follow?acct={uri}`
|
||||
};
|
||||
|
||||
if (ctx.accepts(jrd, xrd) === xrd) {
|
||||
ctx.body = XRD(
|
||||
{ element: 'Subject', value: subject },
|
||||
{ element: 'Link', attributes: self },
|
||||
{ element: 'Link', attributes: profilePage },
|
||||
{ element: 'Link', attributes: subscribe });
|
||||
ctx.type = xrd;
|
||||
} else {
|
||||
ctx.body = {
|
||||
subject,
|
||||
links: [self, profilePage, subscribe]
|
||||
};
|
||||
ctx.type = jrd;
|
||||
}
|
||||
|
||||
ctx.vary('Accept');
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue