From 139a273e6e722073aded9ffcb3a58bc8c7ca5d55 Mon Sep 17 00:00:00 2001
From: ThatOneCalculator <kainoa@t1c.dev>
Date: Sun, 16 Jul 2023 21:03:38 -0700
Subject: [PATCH] refactor: :recycle: export verifyLink, use ReGeX to validate

---
 .../queue/processors/system/verify-links.ts   | 36 ++++++-------------
 .../src/server/api/endpoints/i/update.ts      | 14 +-------
 packages/backend/src/services/fetch-rel-me.ts | 19 +++++++++-
 3 files changed, 30 insertions(+), 39 deletions(-)

diff --git a/packages/backend/src/queue/processors/system/verify-links.ts b/packages/backend/src/queue/processors/system/verify-links.ts
index 71362b1f63..3ddda9baf4 100644
--- a/packages/backend/src/queue/processors/system/verify-links.ts
+++ b/packages/backend/src/queue/processors/system/verify-links.ts
@@ -3,7 +3,7 @@ import type Bull from "bull";
 import { UserProfiles } from "@/models/index.js";
 import { Not } from "typeorm";
 import { queueLogger } from "../../logger.js";
-import { getRelMeLinks } from "@/services/fetch-rel-me.js";
+import { verifyLink } from "@/services/fetch-rel-me.js";
 import config from "@/config/index.js";
 
 const logger = queueLogger.createSubLogger("verify-links");
@@ -19,36 +19,22 @@ export async function verifyLinks(
 		userHost: "",
 	});
 	for (const user of usersToVerify) {
-		const fields = user.fields
-			.filter(
-				(x) =>
-					typeof x.name === "string" &&
-					x.name !== "" &&
-					typeof x.value === "string" &&
-					x.value !== "" &&
-					x.value.startsWith("http")
-			)
-			.map(async (x) => {
-				const relMeLinks = await getRelMeLinks(x.value);
-				const verified = relMeLinks.some((link) =>
-					link.includes(`${config.host}/@${user.user?.host}`),
-				);
-				return {
-					name: x.name,
-					value: x.value,
-					verified: verified,
-				};
-			});
-		if (fields.length > 0) {
-			const fieldsFinal = await Promise.all(fields);
+		for (const field of user.fields) {
+			if (!field || field.name === "" || field.value === "") {
+				continue;
+			}
+			if (field.value.startsWith("http") && user.user?.username) {
+				field.verified = await verifyLink(field.value, user.user.username);
+			}
+		}
+		if (user.fields.length > 0) {
 			try {
 				await UserProfiles.update(user.userId, {
-					fields: fieldsFinal,
+					fields: user.fields,
 				});
 			} catch (e) {
 				logger.error(`Failed to update user ${user.userId} ${e}`);
 				done(e);
-				break;
 			}
 		}
 	}
diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts
index d1d2f672df..6d3bde2b8d 100644
--- a/packages/backend/src/server/api/endpoints/i/update.ts
+++ b/packages/backend/src/server/api/endpoints/i/update.ts
@@ -12,7 +12,7 @@ import type { UserProfile } from "@/models/entities/user-profile.js";
 import { notificationTypes } from "@/types.js";
 import { normalizeForSearch } from "@/misc/normalize-for-search.js";
 import { langmap } from "@/misc/langmap.js";
-import { getRelMeLinks } from "@/services/fetch-rel-me.js";
+import { verifyLink } from "@/services/fetch-rel-me.js";
 import { ApiError } from "../../error.js";
 import config from "@/config/index.js";
 import define from "../../define.js";
@@ -149,17 +149,6 @@ export const paramDef = {
 	},
 } as const;
 
-async function verifyLink(link: string, username: string): Promise<boolean> {
-	let verified = false;
-	if (link.startsWith("http")) {
-		const relMeLinks = await getRelMeLinks(link);
-		verified = relMeLinks.some((href) =>
-			href.includes(`${config.host}/@${username}`),
-		);
-	}
-	return verified;
-}
-
 export default define(meta, paramDef, async (ps, _user, token) => {
 	const user = await Users.findOneByOrFail({ id: _user.id });
 	const isSecure = token == null;
@@ -261,7 +250,6 @@ export default define(meta, paramDef, async (ps, _user, token) => {
 	if (ps.fields) {
 		for (const field of ps.fields) {
 			if (!field || field.name === "" || field.value === "") {
-				ps.fields.remove(field);
 				continue;
 			}
 			if (typeof field.name !== "string" || field.name === "") {
diff --git a/packages/backend/src/services/fetch-rel-me.ts b/packages/backend/src/services/fetch-rel-me.ts
index f6422c22ac..9e1d8f9b6f 100644
--- a/packages/backend/src/services/fetch-rel-me.ts
+++ b/packages/backend/src/services/fetch-rel-me.ts
@@ -1,7 +1,8 @@
 import { getHtml } from "@/misc/fetch.js";
 import { JSDOM } from "jsdom";
+import config from "@/config";
 
-export async function getRelMeLinks(url: string): Promise<string[]> {
+async function getRelMeLinks(url: string): Promise<string[]> {
 	try {
 		const html = await getHtml(url);
 		const dom = new JSDOM(html);
@@ -14,3 +15,19 @@ export async function getRelMeLinks(url: string): Promise<string[]> {
 		return [];
 	}
 }
+
+export async function verifyLink(link: string, username: string): Promise<boolean> {
+	let verified = false;
+	if (link.startsWith("http")) {
+		const relMeLinks = await getRelMeLinks(link);
+		verified = relMeLinks.some((href) =>
+			new RegExp(
+				`^https?:\/\/${config.host.replace(
+					/[.*+\-?^${}()|[\]\\]/g,
+					"\\$&",
+				)}\/@${username.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&")}$`,
+			).test(href),
+		);
+	}
+	return verified;
+}