summaryrefslogtreecommitdiff
path: root/packages/backend/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/backend/src')
-rw-r--r--packages/backend/src/core/FetchInstanceMetadataService.ts44
-rw-r--r--packages/backend/src/misc/verify-field-link.ts23
-rw-r--r--packages/backend/src/server/api/endpoints/i/update.ts3
3 files changed, 35 insertions, 35 deletions
diff --git a/packages/backend/src/core/FetchInstanceMetadataService.ts b/packages/backend/src/core/FetchInstanceMetadataService.ts
index ce3af7c774..5bfcfc5c98 100644
--- a/packages/backend/src/core/FetchInstanceMetadataService.ts
+++ b/packages/backend/src/core/FetchInstanceMetadataService.ts
@@ -5,9 +5,9 @@
import { URL } from 'node:url';
import { Inject, Injectable } from '@nestjs/common';
-import { JSDOM } from 'jsdom';
import tinycolor from 'tinycolor2';
import * as Redis from 'ioredis';
+import { load as cheerio, CheerioAPI } from 'cheerio';
import type { MiInstance } from '@/models/Instance.js';
import type Logger from '@/logger.js';
import { DI } from '@/di-symbols.js';
@@ -15,7 +15,6 @@ import { LoggerService } from '@/core/LoggerService.js';
import { HttpRequestService } from '@/core/HttpRequestService.js';
import { bindThis } from '@/decorators.js';
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
-import type { DOMWindow } from 'jsdom';
type NodeInfo = {
openRegistrations?: unknown;
@@ -181,17 +180,14 @@ export class FetchInstanceMetadataService {
}
@bindThis
- private async fetchDom(instance: MiInstance): Promise<Document> {
+ private async fetchDom(instance: MiInstance): Promise<CheerioAPI> {
this.logger.info(`Fetching HTML of ${instance.host} ...`);
const url = 'https://' + instance.host;
const html = await this.httpRequestService.getHtml(url);
- const { window } = new JSDOM(html);
- const doc = window.document;
-
- return doc;
+ return cheerio(html);
}
@bindThis
@@ -206,12 +202,15 @@ export class FetchInstanceMetadataService {
}
@bindThis
- private async fetchFaviconUrl(instance: MiInstance, doc: Document | null): Promise<string | null> {
+ private async fetchFaviconUrl(instance: MiInstance, doc: CheerioAPI | null): Promise<string | null> {
const url = 'https://' + instance.host;
if (doc) {
// https://github.com/misskey-dev/misskey/pull/8220#issuecomment-1025104043
- const href = Array.from(doc.getElementsByTagName('link')).reverse().find(link => link.relList.contains('icon'))?.href;
+ const href = doc('link[rel][href]')
+ .filter((_, link) => link.attribs.rel.split(' ').includes('icon'))
+ .last()
+ .attr('href');
if (href) {
return (new URL(href, url)).href;
@@ -232,7 +231,7 @@ export class FetchInstanceMetadataService {
}
@bindThis
- private async fetchIconUrl(instance: MiInstance, doc: Document | null, manifest: Record<string, any> | null): Promise<string | null> {
+ private async fetchIconUrl(instance: MiInstance, doc: CheerioAPI | null, manifest: Record<string, any> | null): Promise<string | null> {
if (manifest && manifest.icons && manifest.icons.length > 0 && manifest.icons[0].src) {
const url = 'https://' + instance.host;
return (new URL(manifest.icons[0].src, url)).href;
@@ -242,13 +241,16 @@ export class FetchInstanceMetadataService {
const url = 'https://' + instance.host;
// https://github.com/misskey-dev/misskey/pull/8220#issuecomment-1025104043
- const links = Array.from(doc.getElementsByTagName('link')).reverse();
+ const links = Array.from(doc('link[rel][href]')).reverse().map(link => ({
+ rel: link.attribs.rel.split(' '),
+ href: link.attribs.href,
+ }));
// https://github.com/misskey-dev/misskey/pull/8220/files/0ec4eba22a914e31b86874f12448f88b3e58dd5a#r796487559
const href =
[
- links.find(link => link.relList.contains('apple-touch-icon-precomposed'))?.href,
- links.find(link => link.relList.contains('apple-touch-icon'))?.href,
- links.find(link => link.relList.contains('icon'))?.href,
+ links.find(link => link.rel.includes('apple-touch-icon-precomposed'))?.href,
+ links.find(link => link.rel.includes('apple-touch-icon'))?.href,
+ links.find(link => link.rel.includes('icon'))?.href,
]
.find(href => href);
@@ -261,8 +263,8 @@ export class FetchInstanceMetadataService {
}
@bindThis
- private async getThemeColor(info: NodeInfo | null, doc: Document | null, manifest: Record<string, any> | null): Promise<string | null> {
- const themeColor = info?.metadata?.themeColor ?? doc?.querySelector('meta[name="theme-color"]')?.getAttribute('content') ?? manifest?.theme_color;
+ private async getThemeColor(info: NodeInfo | null, doc: CheerioAPI | null, manifest: Record<string, any> | null): Promise<string | null> {
+ const themeColor = info?.metadata?.themeColor ?? doc?.('meta[name="theme-color"][content]').attr('content') ?? manifest?.theme_color;
if (themeColor) {
const color = new tinycolor(themeColor);
@@ -273,7 +275,7 @@ export class FetchInstanceMetadataService {
}
@bindThis
- private async getSiteName(info: NodeInfo | null, doc: Document | null, manifest: Record<string, any> | null): Promise<string | null> {
+ private async getSiteName(info: NodeInfo | null, doc: CheerioAPI | null, manifest: Record<string, any> | null): Promise<string | null> {
if (info && info.metadata) {
if (typeof info.metadata.nodeName === 'string') {
return info.metadata.nodeName;
@@ -283,7 +285,7 @@ export class FetchInstanceMetadataService {
}
if (doc) {
- const og = doc.querySelector('meta[property="og:title"]')?.getAttribute('content');
+ const og = doc('meta[property="og:title"][content]').attr('content');
if (og) {
return og;
@@ -298,7 +300,7 @@ export class FetchInstanceMetadataService {
}
@bindThis
- private async getDescription(info: NodeInfo | null, doc: Document | null, manifest: Record<string, any> | null): Promise<string | null> {
+ private async getDescription(info: NodeInfo | null, doc: CheerioAPI | null, manifest: Record<string, any> | null): Promise<string | null> {
if (info && info.metadata) {
if (typeof info.metadata.nodeDescription === 'string') {
return info.metadata.nodeDescription;
@@ -308,12 +310,12 @@ export class FetchInstanceMetadataService {
}
if (doc) {
- const meta = doc.querySelector('meta[name="description"]')?.getAttribute('content');
+ const meta = doc('meta[name="description"][content]').attr('content');
if (meta) {
return meta;
}
- const og = doc.querySelector('meta[property="og:description"]')?.getAttribute('content');
+ const og = doc('meta[property="og:description"][content]').attr('content');
if (og) {
return og;
}
diff --git a/packages/backend/src/misc/verify-field-link.ts b/packages/backend/src/misc/verify-field-link.ts
index f519acfba0..62542eaaa0 100644
--- a/packages/backend/src/misc/verify-field-link.ts
+++ b/packages/backend/src/misc/verify-field-link.ts
@@ -3,32 +3,29 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import { JSDOM } from 'jsdom';
+import { load as cheerio } from 'cheerio';
import type { HttpRequestService } from '@/core/HttpRequestService.js';
type Field = { name: string, value: string };
export async function verifyFieldLinks(fields: Field[], profile_url: string, httpRequestService: HttpRequestService): Promise<string[]> {
const verified_links = [];
- for (const field_url of fields
- .filter(x => URL.canParse(x.value) && ['http:', 'https:'].includes((new URL(x.value).protocol)))) {
+ for (const field_url of fields.filter(x => URL.canParse(x.value) && ['http:', 'https:'].includes((new URL(x.value).protocol)))) {
try {
const html = await httpRequestService.getHtml(field_url.value);
- const { window } = new JSDOM(html);
- const doc: Document = window.document;
+ const doc = cheerio(html);
- const aEls = Array.from(doc.getElementsByTagName('a'));
- const linkEls = Array.from(doc.getElementsByTagName('link'));
+ const links = doc('a[rel~="me"][href], link[rel~="me"][href]').toArray();
- const includesProfileLinks = [...aEls, ...linkEls].some(link => link.rel === 'me' && link.href === profile_url);
- if (includesProfileLinks) { verified_links.push(field_url.value); }
-
- window.close();
- } catch (err) {
+ const includesProfileLinks = links.some(link => link.attribs.href === profile_url);
+ if (includesProfileLinks) {
+ verified_links.push(field_url.value);
+ }
+ } catch {
// don't do anything.
- continue;
}
}
+
return verified_links;
}
diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts
index 5f93597fd7..ad8f38703b 100644
--- a/packages/backend/src/server/api/endpoints/i/update.ts
+++ b/packages/backend/src/server/api/endpoints/i/update.ts
@@ -6,7 +6,6 @@
import * as mfm from '@transfem-org/sfm-js';
import { Inject, Injectable } from '@nestjs/common';
import ms from 'ms';
-import { JSDOM } from 'jsdom';
import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js';
import { extractHashtags } from '@/misc/extract-hashtags.js';
import * as Acct from '@/misc/acct.js';
@@ -622,6 +621,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}
// this function is superseded by '@/misc/verify-field-link.ts'
+ /*
private async verifyLink(url: string, user: MiLocalUser) {
if (!safeForSql(url)) return;
@@ -653,6 +653,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
// なにもしない
}
}
+ */
// these two methods need to be kept in sync with
// `ApRendererService.renderPerson`