summaryrefslogtreecommitdiff
path: root/packages/backend/src/core/WebfingerService.ts
diff options
context:
space:
mode:
authorslonkazoid <slonkazoid@slonk.ing>2024-07-09 05:31:25 +0300
committerslonkazoid <slonkazoid@slonk.ing>2024-07-09 05:45:41 +0300
commit7a62e1be31a954e395241609a06413da09ecbab8 (patch)
tree9063ad93edeff7cdedc4c10fd137392eec0f2cdf /packages/backend/src/core/WebfingerService.ts
parentmerge: cache URL previews on the server (!565) (diff)
downloadsharkey-7a62e1be31a954e395241609a06413da09ecbab8.tar.gz
sharkey-7a62e1be31a954e395241609a06413da09ecbab8.tar.bz2
sharkey-7a62e1be31a954e395241609a06413da09ecbab8.zip
implement fetching host-meta before the webfinger endpoint
code ported from iceshrimp: https://iceshrimp.dev/iceshrimp/iceshrimp/src/commit/c3e685a925a89b4abc19684263e87691dd9f0c6d/packages/backend/src/remote/webfinger.ts
Diffstat (limited to 'packages/backend/src/core/WebfingerService.ts')
-rw-r--r--packages/backend/src/core/WebfingerService.ts63
1 files changed, 57 insertions, 6 deletions
diff --git a/packages/backend/src/core/WebfingerService.ts b/packages/backend/src/core/WebfingerService.ts
index 374536a741..ec03f9124a 100644
--- a/packages/backend/src/core/WebfingerService.ts
+++ b/packages/backend/src/core/WebfingerService.ts
@@ -5,7 +5,7 @@
import { URL } from 'node:url';
import { Injectable } from '@nestjs/common';
-import { query as urlQuery } from '@/misc/prelude/url.js';
+import { XMLParser } from 'fast-xml-parser';
import { HttpRequestService } from '@/core/HttpRequestService.js';
import { bindThis } from '@/decorators.js';
@@ -31,25 +31,76 @@ export class WebfingerService {
@bindThis
public async webfinger(query: string): Promise<IWebFinger> {
- const url = this.genUrl(query);
+ const hostMetaUrl = this.queryToHostMetaUrl(query);
+ const template = await this.fetchHostMeta(hostMetaUrl) ?? this.queryToWebFingerTemplate(query);
+ const url = this.genUrl(query, template);
return await this.httpRequestService.getJson<IWebFinger>(url, 'application/jrd+json, application/json');
}
@bindThis
- private genUrl(query: string): string {
+ private genUrl(query: string, template: string): string {
+ if (template.indexOf('{uri}') < 0) throw new Error(`Invalid webFingerUrl: ${template}`);
+
+ if (query.match(/^https?:\/\//)) {
+ return template.replace('{uri}', encodeURIComponent(query));
+ }
+
+ const m = query.match(/^([^@]+)@(.*)/);
+ if (m) {
+ return template.replace('{uri}', encodeURIComponent(`acct:${query}`));
+ }
+
+ throw new Error(`Invalid query (${query})`);
+ }
+
+ @bindThis
+ private queryToWebFingerTemplate(query: string): string {
+ if (query.match(/^https?:\/\//)) {
+ const u = new URL(query);
+ return `${u.protocol}//${u.hostname}/.well-known/webfinger?resource={uri}`;
+ }
+
+ const m = query.match(/^([^@]+)@(.*)/);
+ if (m) {
+ const hostname = m[2];
+ return `https://${hostname}/.well-known/webfinger?resource={uri}`;
+ }
+
+ throw new Error(`Invalid query (${query})`);
+ }
+
+ @bindThis
+ private queryToHostMetaUrl(query: string): string {
if (query.match(urlRegex)) {
const u = new URL(query);
- return `${u.protocol}//${u.hostname}/.well-known/webfinger?` + urlQuery({ resource: query });
+ return `${u.protocol}//${u.hostname}/.well-known/host-meta`;
}
const m = query.match(mRegex);
if (m) {
const hostname = m[2];
- const useHttp = process.env.MISSKEY_WEBFINGER_USE_HTTP && process.env.MISSKEY_WEBFINGER_USE_HTTP.toLowerCase() === 'true';
- return `http${useHttp ? '' : 's'}://${hostname}/.well-known/webfinger?${urlQuery({ resource: `acct:${query}` })}`;
+ return `https://${hostname}/.well-known/host-meta`;
}
throw new Error(`Invalid query (${query})`);
}
+
+ @bindThis
+ private async fetchHostMeta(url: string): Promise<string | null> {
+ try {
+ const res = await this.httpRequestService.getHtml(url, 'application/xrd+xml');
+ const options = {
+ ignoreAttributes: false,
+ isArray: (_name: string, jpath: string) => jpath === 'XRD.Link',
+ };
+ const parser = new XMLParser(options);
+ const hostMeta = parser.parse(res);
+ const template = (hostMeta['XRD']['Link'] as Array<any>).filter(p => p['@_rel'] === 'lrdd')[0]['@_template'];
+ return template.indexOf('{uri}') < 0 ? null : template;
+ } catch (err) {
+ console.error(`error while request host-meta for ${url}`);
+ return null;
+ }
+ }
}