* 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 User from '../models/user';
 | 
				
			||||||
import Acct from '../misc/acct/type';
 | 
					import Acct from '../misc/acct/type';
 | 
				
			||||||
import { links } from './nodeinfo';
 | 
					import { links } from './nodeinfo';
 | 
				
			||||||
 | 
					import { escapeAttribute, escapeValue } from '../prelude/xml';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Init router
 | 
					// Init router
 | 
				
			||||||
const router = new 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 webFingerPath = '/.well-known/webfinger';
 | 
				
			||||||
 | 
					const jrd = 'application/jrd+json';
 | 
				
			||||||
 | 
					const xrd = 'application/xrd+xml';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
router.get('/.well-known/host-meta', async ctx => {
 | 
					router.get('/.well-known/host-meta', async ctx => {
 | 
				
			||||||
	ctx.set('Content-Type', 'application/xrd+xml');
 | 
						ctx.set('Content-Type', xrd);
 | 
				
			||||||
	ctx.body = `<?xml version="1.0" encoding="UTF-8"?>
 | 
						ctx.body = XRD({ element: 'Link', attributes: {
 | 
				
			||||||
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
 | 
							type: xrd,
 | 
				
			||||||
  <Link rel="lrdd" type="application/xrd+xml" template="${config.url}${webFingerPath}?resource={uri}"/>
 | 
							template: `${config.url}${webFingerPath}?resource={uri}`
 | 
				
			||||||
</XRD>
 | 
						}});
 | 
				
			||||||
`;
 | 
					 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
router.get('/.well-known/host-meta.json', async ctx => {
 | 
					router.get('/.well-known/host-meta.json', async ctx => {
 | 
				
			||||||
	ctx.set('Content-Type', 'application/jrd+json');
 | 
						ctx.set('Content-Type', jrd);
 | 
				
			||||||
	ctx.body = {
 | 
						ctx.body = {
 | 
				
			||||||
		links: [{
 | 
							links: [{
 | 
				
			||||||
			rel: 'lrdd',
 | 
								rel: 'lrdd',
 | 
				
			||||||
			type: 'application/xrd+xml',
 | 
								type: jrd,
 | 
				
			||||||
			template: `${config.url}${webFingerPath}?resource={uri}`
 | 
								template: `${config.url}${webFingerPath}?resource={uri}`
 | 
				
			||||||
		}]
 | 
							}]
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
| 
						 | 
					@ -75,22 +85,38 @@ router.get(webFingerPath, async ctx => {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.body = {
 | 
						const subject = `acct:${user.username}@${config.host}`;
 | 
				
			||||||
		subject: `acct:${user.username}@${config.host}`,
 | 
						const self = {
 | 
				
			||||||
		links: [{
 | 
							rel: 'self',
 | 
				
			||||||
			rel: 'self',
 | 
							type: 'application/activity+json',
 | 
				
			||||||
			type: 'application/activity+json',
 | 
							href: `${config.url}/users/${user._id}`
 | 
				
			||||||
			href: `${config.url}/users/${user._id}`
 | 
						};
 | 
				
			||||||
		}, {
 | 
						const profilePage = {
 | 
				
			||||||
			rel: 'http://webfinger.net/rel/profile-page',
 | 
							rel: 'http://webfinger.net/rel/profile-page',
 | 
				
			||||||
			type: 'text/html',
 | 
							type: 'text/html',
 | 
				
			||||||
			href: `${config.url}/@${user.username}`
 | 
							href: `${config.url}/@${user.username}`
 | 
				
			||||||
		}, {
 | 
						};
 | 
				
			||||||
			rel: 'http://ostatus.org/schema/1.0/subscribe',
 | 
						const subscribe = {
 | 
				
			||||||
			template: `${config.url}/authorize-follow?acct={uri}`
 | 
							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');
 | 
						ctx.set('Cache-Control', 'public, max-age=180');
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue