From 84867f1c130e9fda454104c7c144dd04ba3498fb Mon Sep 17 00:00:00 2001
From: Laura Hausmann <laura@hausmann.dev>
Date: Tue, 5 Sep 2023 21:04:30 +0200
Subject: [PATCH] Finish up support for local split domain configurations

---
 .../backend/native-utils/migration/src/lib.rs |  2 +
 ...905_210205_drop_instance_account_domain.rs | 37 +++++++++++++++++++
 .../native-utils/src/model/entity/instance.rs |  1 -
 packages/backend/src/boot/master.ts           |  2 +-
 packages/backend/src/config/load.ts           |  3 +-
 packages/backend/src/config/types.ts          |  1 +
 packages/backend/src/db/meilisearch.ts        |  2 +-
 packages/backend/src/misc/convert-host.ts     |  4 +-
 .../backend/src/models/entities/instance.ts   |  6 ---
 .../src/models/repositories/instance.ts       |  1 -
 .../src/models/schema/federation-instance.ts  |  6 ---
 .../src/remote/activitypub/check-fetch.ts     |  1 +
 .../src/remote/activitypub/resolver.ts        |  1 +
 packages/backend/src/remote/resolve-user.ts   |  2 +-
 .../backend/src/server/api/endpoints/meta.ts  |  8 ++++
 .../src/server/api/mastodon/endpoints/meta.ts |  1 -
 packages/backend/src/server/index.ts          |  2 +-
 packages/backend/src/server/web/feed.ts       |  4 +-
 packages/backend/src/server/well-known.ts     |  4 +-
 packages/backend/src/services/send-email.ts   |  2 +-
 packages/client/src/init.ts                   |  2 +-
 packages/megalodon/src/misskey/api_client.ts  |  2 +-
 .../megalodon/src/misskey/entities/meta.ts    |  1 +
 23 files changed, 65 insertions(+), 30 deletions(-)
 create mode 100644 packages/backend/native-utils/migration/src/m20230905_210205_drop_instance_account_domain.rs

diff --git a/packages/backend/native-utils/migration/src/lib.rs b/packages/backend/native-utils/migration/src/lib.rs
index a18c1e5dc..14f4bee30 100644
--- a/packages/backend/native-utils/migration/src/lib.rs
+++ b/packages/backend/native-utils/migration/src/lib.rs
@@ -6,6 +6,7 @@ mod m20230709_000510_move_antenna_to_cache;
 mod m20230726_213530_drop_ads;
 mod m20230801_160334_add_instance_account_domain;
 mod m20230802_190415_fix_instance_account_domain;
+mod m20230905_210205_drop_instance_account_domain;
 
 pub struct Migrator;
 
@@ -19,6 +20,7 @@ impl MigratorTrait for Migrator {
             Box::new(m20230726_213530_drop_ads::Migration),
             Box::new(m20230801_160334_add_instance_account_domain::Migration),
             Box::new(m20230802_190415_fix_instance_account_domain::Migration),
+            Box::new(m20230905_210205_drop_instance_account_domain::Migration),
         ]
     }
 }
diff --git a/packages/backend/native-utils/migration/src/m20230905_210205_drop_instance_account_domain.rs b/packages/backend/native-utils/migration/src/m20230905_210205_drop_instance_account_domain.rs
new file mode 100644
index 000000000..7ab75800b
--- /dev/null
+++ b/packages/backend/native-utils/migration/src/m20230905_210205_drop_instance_account_domain.rs
@@ -0,0 +1,37 @@
+use sea_orm_migration::prelude::*;
+
+#[derive(DeriveMigrationName)]
+pub struct Migration;
+
+#[async_trait::async_trait]
+impl MigrationTrait for Migration {
+    async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
+        manager
+            .alter_table(
+                Table::alter()
+                    .table(Instance::Table)
+                    .drop_column(Instance::AccountDomain)
+                    .to_owned(),
+            )
+            .await
+    }
+
+    async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
+        manager
+            .alter_table(
+                Table::alter()
+                    .table(Instance::Table)
+                    .add_column(ColumnDef::new(Instance::AccountDomain).string())
+                    .to_owned(),
+            )
+            .await
+    }
+}
+
+/// Learn more at https://docs.rs/sea-query#iden
+#[derive(Iden)]
+enum Instance {
+    Table,
+    #[iden = "accountDomain"]
+    AccountDomain,
+}
diff --git a/packages/backend/native-utils/src/model/entity/instance.rs b/packages/backend/native-utils/src/model/entity/instance.rs
index c79b2c757..fc9c5bf8b 100644
--- a/packages/backend/native-utils/src/model/entity/instance.rs
+++ b/packages/backend/native-utils/src/model/entity/instance.rs
@@ -10,7 +10,6 @@ pub struct Model {
     #[sea_orm(column_name = "caughtAt")]
     pub caught_at: DateTimeWithTimeZone,
     pub host: String,
-    pub account_domain: Option<String>,
     #[sea_orm(column_name = "usersCount")]
     pub users_count: i32,
     #[sea_orm(column_name = "notesCount")]
diff --git a/packages/backend/src/boot/master.ts b/packages/backend/src/boot/master.ts
index 824f03f5d..61cf95012 100644
--- a/packages/backend/src/boot/master.ts
+++ b/packages/backend/src/boot/master.ts
@@ -63,7 +63,7 @@ export async function masterMain() {
 	}
 
 	bootLogger.succ(
-		`Now listening on port ${config.port} on ${config.url} - using ${config.accountDomain}`,
+		`Now listening on port ${config.port} on ${config.url} - using ${config.domain}`,
 		null,
 		true,
 	);
diff --git a/packages/backend/src/config/load.ts b/packages/backend/src/config/load.ts
index 76e2153ba..31ca4242e 100644
--- a/packages/backend/src/config/load.ts
+++ b/packages/backend/src/config/load.ts
@@ -40,8 +40,6 @@ export default function load() {
 
 	config.url = url.origin;
 
-	if (!config.accountDomain) config.accountDomain = url.hostname
-
 	config.port = config.port || parseInt(process.env.PORT || "", 10);
 
 	config.images = {
@@ -54,6 +52,7 @@ export default function load() {
 	mixin.version = meta.version;
 	mixin.host = url.host;
 	mixin.hostname = url.hostname;
+	mixin.domain = config.accountDomain ?? url.host;
 	mixin.scheme = url.protocol.replace(/:$/, "");
 	mixin.wsScheme = mixin.scheme.replace("http", "ws");
 	mixin.wsUrl = `${mixin.wsScheme}://${mixin.host}`;
diff --git a/packages/backend/src/config/types.ts b/packages/backend/src/config/types.ts
index 86167acf1..a53a54651 100644
--- a/packages/backend/src/config/types.ts
+++ b/packages/backend/src/config/types.ts
@@ -164,6 +164,7 @@ export type Mixin = {
 	version: string;
 	host: string;
 	hostname: string;
+	domain: string;
 	scheme: string;
 	wsScheme: string;
 	apiUrl: string;
diff --git a/packages/backend/src/db/meilisearch.ts b/packages/backend/src/db/meilisearch.ts
index 4a8985d08..9752e1ba1 100644
--- a/packages/backend/src/db/meilisearch.ts
+++ b/packages/backend/src/db/meilisearch.ts
@@ -345,7 +345,7 @@ export default hasConfig
 						userHost:
 							note.userHost !== ""
 								? note.userHost
-								: url.parse(config.host).host,
+								: config.domain,
 						channelId: note.channelId ? note.channelId : "",
 						mediaAttachment: attachmentType,
 						userName: note.user?.username ?? "UNKNOWN",
diff --git a/packages/backend/src/misc/convert-host.ts b/packages/backend/src/misc/convert-host.ts
index 856ce3c12..95b6da539 100644
--- a/packages/backend/src/misc/convert-host.ts
+++ b/packages/backend/src/misc/convert-host.ts
@@ -5,12 +5,12 @@ import { toASCII } from "punycode";
 export function getFullApAccount(username: string, host: string | null) {
 	return host
 		? `${username}@${toPuny(host)}`
-		: `${username}@${toPuny(config.host)}`;
+		: `${username}@${toPuny(config.domain)}`;
 }
 
 export function isSelfHost(host: string) {
 	if (host == null) return true;
-	return toPuny(config.host) === toPuny(host);
+	return toPuny(config.domain) === toPuny(host) || toPuny(config.host) === toPuny(host);
 }
 
 export function extractDbHost(uri: string) {
diff --git a/packages/backend/src/models/entities/instance.ts b/packages/backend/src/models/entities/instance.ts
index 3a46f01f5..7e0b08583 100644
--- a/packages/backend/src/models/entities/instance.ts
+++ b/packages/backend/src/models/entities/instance.ts
@@ -170,10 +170,4 @@ export class Instance {
 		nullable: true,
 	})
 	public infoUpdatedAt: Date | null;
-
-	@Column("varchar", {
-		length: 128,
-		comment: "Domain for account ATs",
-	})
-	public accountDomain: string | null;
 }
diff --git a/packages/backend/src/models/repositories/instance.ts b/packages/backend/src/models/repositories/instance.ts
index bc50836e2..667ec948d 100644
--- a/packages/backend/src/models/repositories/instance.ts
+++ b/packages/backend/src/models/repositories/instance.ts
@@ -34,7 +34,6 @@ export const InstanceRepository = db.getRepository(Instance).extend({
 			iconUrl: instance.iconUrl,
 			faviconUrl: instance.faviconUrl,
 			themeColor: instance.themeColor,
-			accountDomain: instance.accountDomain,
 			infoUpdatedAt: instance.infoUpdatedAt
 				? instance.infoUpdatedAt.toISOString()
 				: null,
diff --git a/packages/backend/src/models/schema/federation-instance.ts b/packages/backend/src/models/schema/federation-instance.ts
index a5daec819..fa675699e 100644
--- a/packages/backend/src/models/schema/federation-instance.ts
+++ b/packages/backend/src/models/schema/federation-instance.ts
@@ -21,12 +21,6 @@ export const packedFederationInstanceSchema = {
 			nullable: false,
 			example: "iceshrimp.example.com",
 		},
-		accountDomain: {
-			type: "string",
-			optional: true,
-			nullable: true,
-			example: "example.com",
-		},
 		usersCount: {
 			type: "number",
 			optional: false,
diff --git a/packages/backend/src/remote/activitypub/check-fetch.ts b/packages/backend/src/remote/activitypub/check-fetch.ts
index c885b4a19..e7d011d90 100644
--- a/packages/backend/src/remote/activitypub/check-fetch.ts
+++ b/packages/backend/src/remote/activitypub/check-fetch.ts
@@ -46,6 +46,7 @@ export async function checkFetch(req: IncomingMessage): Promise<number> {
 		if (
 			meta.privateMode &&
 			host !== config.host &&
+			host !== config.domain &&
 			!meta.allowedHosts.includes(host)
 		) {
 			return 403;
diff --git a/packages/backend/src/remote/activitypub/resolver.ts b/packages/backend/src/remote/activitypub/resolver.ts
index 608ca3e93..223350cae 100644
--- a/packages/backend/src/remote/activitypub/resolver.ts
+++ b/packages/backend/src/remote/activitypub/resolver.ts
@@ -108,6 +108,7 @@ export default class Resolver {
 		if (
 			meta.privateMode &&
 			config.host !== host &&
+			config.domain !== host &&
 			!meta.allowedHosts.includes(host)
 		) {
 			throw new Error("Instance is not allowed");
diff --git a/packages/backend/src/remote/resolve-user.ts b/packages/backend/src/remote/resolve-user.ts
index cc872ffee..e1efcd12b 100644
--- a/packages/backend/src/remote/resolve-user.ts
+++ b/packages/backend/src/remote/resolve-user.ts
@@ -36,7 +36,7 @@ export async function resolveUser(
 
 	// Also return local user if host part is specified but referencing the local instance
 
-	if (config.host === host || config.accountDomain === host) {
+	if (config.host === host || config.domain === host) {
 		logger.info(`return local user: ${usernameLower}`);
 		return await Users.findOneBy({ usernameLower, host: IsNull() }).then(
 			(u) => {
diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts
index 36950c941..964919dce 100644
--- a/packages/backend/src/server/api/endpoints/meta.ts
+++ b/packages/backend/src/server/api/endpoints/meta.ts
@@ -44,6 +44,13 @@ export const meta = {
 				format: "url",
 				example: "https://iceshrimp.example.com",
 			},
+			domain: {
+				type: "string",
+				optional: false,
+				nullable: false,
+				format: "domain",
+				example: "example.com",
+			},
 			description: {
 				type: "string",
 				optional: false,
@@ -411,6 +418,7 @@ export default define(meta, paramDef, async (ps, me) => {
 
 		name: instance.name,
 		uri: config.url,
+		domain: config.domain,
 		description: instance.description,
 		langs: instance.langs,
 		tosUrl: instance.ToSUrl,
diff --git a/packages/backend/src/server/api/mastodon/endpoints/meta.ts b/packages/backend/src/server/api/mastodon/endpoints/meta.ts
index a5ab81bf1..64439437a 100644
--- a/packages/backend/src/server/api/mastodon/endpoints/meta.ts
+++ b/packages/backend/src/server/api/mastodon/endpoints/meta.ts
@@ -18,7 +18,6 @@ export async function getInstance(
 
 	return {
 		uri: response.uri,
-		account_domain: config.accountDomain,
 		title: response.title || "Iceshrimp",
 		short_description:
 			response.description?.substring(0, 50) || "See real server website",
diff --git a/packages/backend/src/server/index.ts b/packages/backend/src/server/index.ts
index efff6dd23..ff1d8abbe 100644
--- a/packages/backend/src/server/index.ts
+++ b/packages/backend/src/server/index.ts
@@ -112,7 +112,7 @@ router.get("/avatar/@:acct", async (ctx) => {
 	const user = await Users.findOne({
 		where: {
 			usernameLower: username.toLowerCase(),
-			host: host == null || host === config.host ? IsNull() : host,
+			host: host == null || host === config.host || host === config.domain ? IsNull() : host,
 			isSuspended: false,
 		},
 		relations: ["avatar"],
diff --git a/packages/backend/src/server/web/feed.ts b/packages/backend/src/server/web/feed.ts
index 1cd95c091..f80fd5b22 100644
--- a/packages/backend/src/server/web/feed.ts
+++ b/packages/backend/src/server/web/feed.ts
@@ -14,7 +14,7 @@ export default async function (
 ) {
 	const author = {
 		link: `${config.url}/@${user.username}`,
-		email: `${user.username}@${config.host}`,
+		email: `${user.username}@${config.domain}`,
 		name: user.name || user.username,
 	};
 
@@ -41,7 +41,7 @@ export default async function (
 
 	const feed = new Feed({
 		id: author.link,
-		title: `${author.name} (@${user.username}@${config.host})`,
+		title: `${author.name} (@${user.username}@${config.domain})`,
 		updated: notes[0].createdAt,
 		generator: "Iceshrimp",
 		description: `${user.notesCount} Notes, ${
diff --git a/packages/backend/src/server/well-known.ts b/packages/backend/src/server/well-known.ts
index 5af3b2c84..1d2d3f21b 100644
--- a/packages/backend/src/server/well-known.ts
+++ b/packages/backend/src/server/well-known.ts
@@ -120,7 +120,7 @@ router.get(webFingerPath, async (ctx) => {
 			  );
 
 	const fromAcct = (acct: Acct.Acct): FindOptionsWhere<User> | number =>
-		!acct.host || acct.host === config.host.toLowerCase()
+		!acct.host || acct.host === config.host.toLowerCase() || acct.host === config.domain.toLowerCase()
 			? {
 					usernameLower: acct.username,
 					host: IsNull(),
@@ -147,7 +147,7 @@ router.get(webFingerPath, async (ctx) => {
 		return;
 	}
 
-	const subject = `acct:${user.username}@${config.host}`;
+	const subject = `acct:${user.username}@${config.domain}`;
 	const self = {
 		rel: "self",
 		type: "application/activity+json",
diff --git a/packages/backend/src/services/send-email.ts b/packages/backend/src/services/send-email.ts
index 070386588..bdd137f5b 100644
--- a/packages/backend/src/services/send-email.ts
+++ b/packages/backend/src/services/send-email.ts
@@ -59,7 +59,7 @@ export async function sendEmail(
 			</footer>
 		</main>
 		<nav style="box-sizing: border-box; max-width: 500px; margin: 16px auto 0 auto; padding: 0 32px;">
-			<a href="${config.url}" style="color: #9ccfd8 !important;">${config.host}</a>
+			<a href="${config.url}" style="color: #9ccfd8 !important;">${config.domain}</a>
 		</nav>
 	</body>
 </html>`,
diff --git a/packages/client/src/init.ts b/packages/client/src/init.ts
index fdbb119da..3b8c21a71 100644
--- a/packages/client/src/init.ts
+++ b/packages/client/src/init.ts
@@ -180,7 +180,7 @@ function checkForSplash() {
 
 	fetchInstanceMetaPromise.then(() => {
 		localStorage.setItem("v", instance.version);
-		setHost(new URL(instance.uri).host);
+		setHost(instance.domain);
 
 		// Init service worker
 		initializeSw();
diff --git a/packages/megalodon/src/misskey/api_client.ts b/packages/megalodon/src/misskey/api_client.ts
index a08968448..299c7edd3 100644
--- a/packages/megalodon/src/misskey/api_client.ts
+++ b/packages/megalodon/src/misskey/api_client.ts
@@ -527,7 +527,7 @@ namespace MisskeyAPI {
 		meta = (m: Entity.Meta, s: Entity.Stats): MegalodonEntity.Instance => {
 			const wss = m.uri.replace(/^https:\/\//, "wss://");
 			return {
-				uri: m.uri,
+				uri: m.domain,
 				title: m.name,
 				description: m.description,
 				email: m.maintainerEmail,
diff --git a/packages/megalodon/src/misskey/entities/meta.ts b/packages/megalodon/src/misskey/entities/meta.ts
index 7dd5f6400..dc539eb0f 100644
--- a/packages/megalodon/src/misskey/entities/meta.ts
+++ b/packages/megalodon/src/misskey/entities/meta.ts
@@ -7,6 +7,7 @@ namespace MisskeyEntity {
     name: string
     version: string
     uri: string
+    domain: string
     description: string
     langs: Array<string>
     disableRegistration: boolean