iceshrimp-161sh/packages/backend/src/remote/resolve-user.ts

140 lines
3.5 KiB
TypeScript
Raw Normal View History

2023-01-13 05:40:33 +01:00
import { URL } from "node:url";
import chalk from "chalk";
import { IsNull } from "typeorm";
import config from "@/config/index.js";
import type { User, IRemoteUser } from "@/models/entities/user.js";
import { Users } from "@/models/index.js";
import { toPuny } from "@/misc/convert-host.js";
import webFinger from "./webfinger.js";
import { createPerson, updatePerson } from "./activitypub/models/person.js";
import { remoteLogger } from "./logger.js";
const logger = remoteLogger.createSubLogger("resolve-user");
export async function resolveUser(
username: string,
host: string | null,
): Promise<User> {
2018-03-31 12:55:00 +02:00
const usernameLower = username.toLowerCase();
2018-05-06 21:26:45 +02:00
2019-04-09 17:59:41 +02:00
if (host == null) {
2019-02-02 20:04:57 +01:00
logger.info(`return local user: ${usernameLower}`);
2023-01-13 05:40:33 +01:00
return await Users.findOneBy({ usernameLower, host: IsNull() }).then(
(u) => {
if (u == null) {
throw new Error("user not found");
} else {
return u;
}
},
);
2018-05-06 21:26:45 +02:00
}
host = toPuny(host);
2022-02-28 17:24:50 +01:00
if (config.host === host) {
2019-02-02 20:04:57 +01:00
logger.info(`return local user: ${usernameLower}`);
2023-01-13 05:40:33 +01:00
return await Users.findOneBy({ usernameLower, host: IsNull() }).then(
(u) => {
if (u == null) {
throw new Error("user not found");
} else {
return u;
}
},
);
2018-04-08 08:25:17 +02:00
}
2023-01-13 05:40:33 +01:00
const user = (await Users.findOneBy({
usernameLower,
host,
})) as IRemoteUser | null;
2019-04-09 17:59:41 +02:00
const acctLower = `${usernameLower}@${host}`;
2018-03-31 12:55:00 +02:00
Use PostgreSQL instead of MongoDB (#4572) * wip * Update note.ts * Update timeline.ts * Update core.ts * wip * Update generate-visibility-query.ts * wip * wip * wip * wip * wip * Update global-timeline.ts * wip * wip * wip * Update vote.ts * wip * wip * Update create.ts * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * Update files.ts * wip * wip * Update CONTRIBUTING.md * wip * wip * wip * wip * wip * wip * wip * wip * Update read-notification.ts * wip * wip * wip * wip * wip * wip * wip * Update cancel.ts * wip * wip * wip * Update show.ts * wip * wip * Update gen-id.ts * Update create.ts * Update id.ts * wip * wip * wip * wip * wip * wip * wip * Docker: Update files about Docker (#4599) * Docker: Use cache if files used by `yarn install` was not updated This patch reduces the number of times to installing node_modules. For example, `yarn install` step will be skipped when only ".config/default.yml" is updated. * Docker: Migrate MongoDB to Postgresql Misskey uses Postgresql as a database instead of Mongodb since version 11. * Docker: Uncomment about data persistence This patch will save a lot of databases. * wip * wip * wip * Update activitypub.ts * wip * wip * wip * Update logs.ts * wip * Update drive-file.ts * Update register.ts * wip * wip * Update mentions.ts * wip * wip * wip * Update recommendation.ts * wip * Update index.ts * wip * Update recommendation.ts * Doc: Update docker.ja.md and docker.en.md (#1) (#4608) Update how to set up misskey. * wip * :v: * wip * Update note.ts * Update postgre.ts * wip * wip * wip * wip * Update add-file.ts * wip * wip * wip * Clean up * Update logs.ts * wip * :pizza: * wip * Ad notes * wip * Update api-visibility.ts * Update note.ts * Update add-file.ts * tests * tests * Update postgre.ts * Update utils.ts * wip * wip * Refactor * wip * Refactor * wip * wip * Update show-users.ts * Update update-instance.ts * wip * Update feed.ts * Update outbox.ts * Update outbox.ts * Update user.ts * wip * Update list.ts * Update update-hashtag.ts * wip * Update update-hashtag.ts * Refactor * Update update.ts * wip * wip * :v: * clean up * docs * Update push.ts * wip * Update api.ts * wip * :v: * Update make-pagination-query.ts * :v: * Delete hashtags.ts * Update instances.ts * Update instances.ts * Update create.ts * Update search.ts * Update reversi-game.ts * Update signup.ts * Update user.ts * id * Update example.yml * :art: * objectid * fix * reversi * reversi * Fix bug of chart engine * Add test of chart engine * Improve test * Better testing * Improve chart engine * Refactor * Add test of chart engine * Refactor * Add chart test * Fix bug * コミットし忘れ * Refactoring * :v: * Add tests * Add test * Extarct note tests * Refactor * 存在しないユーザーにメンションできなくなっていた問題を修正 * Fix bug * Update update-meta.ts * Fix bug * Update mention.vue * Fix bug * Update meta.ts * Update CONTRIBUTING.md * Fix bug * Fix bug * Fix bug * Clean up * Clean up * Update notification.ts * Clean up * Add mute tests * Add test * Refactor * Add test * Fix test * Refactor * Refactor * Add tests * Update utils.ts * Update utils.ts * Fix test * Update package.json * Update update.ts * Update manifest.ts * Fix bug * Fix bug * Add test * :art: * Update endpoint permissions * Updaye permisison * Update person.ts #4299 * データベースと同期しないように * Fix bug * Fix bug * Update reversi-game.ts * Use a feature of Node v11.7.0 to extract a public key (#4644) * wip * wip * :v: * Refactoring #1540 * test * test * test * test * test * test * test * Fix bug * Fix test * :sushi: * wip * #4471 * Add test for #4335 * Refactor * Fix test * Add tests * :clock4: * Fix bug * Add test * Add test * rename * Fix bug
2019-04-07 14:50:36 +02:00
if (user == null) {
const self = await resolveSelf(acctLower);
2019-02-02 20:43:43 +01:00
logger.succ(`return new remote user: ${chalk.magenta(acctLower)}`);
return await createPerson(self.href);
}
// If user information is out of date, return it by starting over from WebFilger
2023-01-13 05:40:33 +01:00
if (
user.lastFetchedAt == null ||
Date.now() - user.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24
) {
// Prevent multiple attempts to connect to unconnected instances, update before each attempt to prevent subsequent similar attempts
await Users.update(user.id, {
lastFetchedAt: new Date(),
});
2019-02-02 20:04:57 +01:00
logger.info(`try resync: ${acctLower}`);
const self = await resolveSelf(acctLower);
if (user.uri !== self.href) {
// if uri mismatch, Fix (user@host <=> AP's Person id(IRemoteUser.uri)) mapping.
2019-02-02 20:04:57 +01:00
logger.info(`uri missmatch: ${acctLower}`);
2023-01-13 05:40:33 +01:00
logger.info(
`recovery missmatch uri for (username=${username}, host=${host}) from ${user.uri} to ${self.href}`,
);
2018-03-31 12:55:00 +02:00
// validate uri
const uri = new URL(self.href);
2019-04-09 17:59:41 +02:00
if (uri.hostname !== host) {
2023-01-13 05:40:33 +01:00
throw new Error("Invalid uri");
}
2023-01-13 05:40:33 +01:00
await Users.update(
{
usernameLower,
host: host,
},
{
uri: self.href,
},
);
} else {
2019-02-02 20:04:57 +01:00
logger.info(`uri is fine: ${acctLower}`);
2018-03-31 12:55:00 +02:00
}
await updatePerson(self.href);
2019-02-02 20:04:57 +01:00
logger.info(`return resynced remote user: ${acctLower}`);
2023-01-13 05:40:33 +01:00
return await Users.findOneBy({ uri: self.href }).then((u) => {
if (u == null) {
2023-01-13 05:40:33 +01:00
throw new Error("user not found");
} else {
return u;
}
});
2019-02-02 20:43:43 +01:00
}
2018-03-31 12:55:00 +02:00
2019-02-02 20:43:43 +01:00
logger.info(`return existing remote user: ${acctLower}`);
2018-03-31 12:55:00 +02:00
return user;
2019-04-07 16:06:07 +02:00
}
async function resolveSelf(acctLower: string) {
2019-02-02 20:43:43 +01:00
logger.info(`WebFinger for ${chalk.yellow(acctLower)}`);
2023-01-13 05:40:33 +01:00
const finger = await webFinger(acctLower).catch((e) => {
logger.error(
`Failed to WebFinger for ${chalk.yellow(acctLower)}: ${
e.statusCode || e.message
}`,
);
throw new Error(
`Failed to WebFinger for ${acctLower}: ${e.statusCode || e.message}`,
);
2019-02-04 01:02:23 +01:00
});
2023-01-13 05:40:33 +01:00
const self = finger.links.find(
(link) => link.rel != null && link.rel.toLowerCase() === "self",
);
if (!self) {
2023-01-13 05:40:33 +01:00
logger.error(
`Failed to WebFinger for ${chalk.yellow(acctLower)}: self link not found`,
);
throw new Error("self link not found");
}
return self;
}