Skip to content
Snippets Groups Projects
Unverified Commit 7a62e1be authored by Slonk A. Zoid's avatar Slonk A. Zoid
Browse files
parent c4f4041c
No related branches found
No related tags found
Loading
......@@ -112,6 +112,7 @@
"content-disposition": "0.5.4",
"date-fns": "2.30.0",
"deep-email-validator": "0.1.21",
"fast-xml-parser": "^4.4.0",
"fastify": "4.26.2",
"fastify-multer": "^2.0.3",
"fastify-raw-body": "4.3.0",
......
......@@ -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;
}
}
}
......@@ -220,6 +220,9 @@ importers:
deep-email-validator:
specifier: 0.1.21
version: 0.1.21
fast-xml-parser:
specifier: ^4.4.0
version: 4.4.0
fastify:
specifier: 4.26.2
version: 4.26.2
......@@ -6821,6 +6824,10 @@ packages:
resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==}
hasBin: true
 
fast-xml-parser@4.4.0:
resolution: {integrity: sha512-kLY3jFlwIYwBNDojclKsNAC12sfD6NwW74QB2CoNGPvtVxjliYehVunB3HYyNi+n4Tt1dAcgwYvmKF/Z18flqg==}
hasBin: true
fastify-multer@2.0.3:
resolution: {integrity: sha512-QnFqrRgxmUwWHTgX9uyQSu0C/hmVCfcxopqjApZ4uaZD5W9MJ+nHUlW4+9q7Yd3BRxDIuHvgiM5mjrh6XG8cAA==}
engines: {node: '>=10.17.0'}
......@@ -11105,8 +11112,8 @@ packages:
vue-component-type-helpers@2.0.16:
resolution: {integrity: sha512-qisL/iAfdO++7w+SsfYQJVPj6QKvxp4i1MMxvsNO41z/8zu3KuAw9LkhKUfP/kcOWGDxESp+pQObWppXusejCA==}
 
vue-component-type-helpers@2.0.19:
resolution: {integrity: sha512-cN3f1aTxxKo4lzNeQAkVopswuImUrb5Iurll9Gaw5cqpnbTAxtEMM1mgi6ou4X79OCyqYv1U1mzBHJkzmiK82w==}
vue-component-type-helpers@2.0.26:
resolution: {integrity: sha512-sO9qQ8oC520SW6kqlls0iqDak53gsTVSrYylajgjmkt1c0vcgjsGSy1KzlDrbEx8pm02IEYhlUkU5hCYf8rwtg==}
 
vue-demi@0.14.7:
resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
......@@ -15449,7 +15456,7 @@ snapshots:
ts-dedent: 2.2.0
type-fest: 2.19.0
vue: 3.4.26(typescript@5.4.5)
vue-component-type-helpers: 2.0.19
vue-component-type-helpers: 2.0.26
transitivePeerDependencies:
- encoding
- supports-color
......@@ -18827,6 +18834,10 @@ snapshots:
dependencies:
strnum: 1.0.5
 
fast-xml-parser@4.4.0:
dependencies:
strnum: 1.0.5
fastify-multer@2.0.3:
dependencies:
'@fastify/busboy': 1.2.1
......@@ -19708,7 +19719,7 @@ snapshots:
 
is-svg@5.0.0:
dependencies:
fast-xml-parser: 4.2.5
fast-xml-parser: 4.4.0
 
is-symbol@1.0.4:
dependencies:
......@@ -23644,7 +23655,7 @@ snapshots:
 
vue-component-type-helpers@2.0.16: {}
 
vue-component-type-helpers@2.0.19: {}
vue-component-type-helpers@2.0.26: {}
 
vue-demi@0.14.7(vue@3.4.26(typescript@5.4.5)):
dependencies:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment