Merge pull request 'fix: followers transfer via account migration' (#9822) from nmkj/calckey:fix-move into develop

Reviewed-on: https://codeberg.org/calckey/calckey/pulls/9822
This commit is contained in:
Kainoa Kanter 2023-04-08 00:06:08 +00:00
commit 49c44771e5
2 changed files with 40 additions and 68 deletions

View File

@ -1,19 +1,14 @@
import type { CacheableRemoteUser } from "@/models/entities/user.js"; import type { CacheableRemoteUser } from "@/models/entities/user.js";
import { IRemoteUser, User } from "@/models/entities/user.js";
import DbResolver from "@/remote/activitypub/db-resolver.js";
import { getRemoteUser } from "@/server/api/common/getters.js";
import { updatePerson } from "@/remote/activitypub/models/person.js";
import { Followings, Users } from "@/models/index.js"; import { Followings, Users } from "@/models/index.js";
import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js"; import {
import deleteFollowing from "@/services/following/delete.js"; resolvePerson,
updatePerson,
} from "@/remote/activitypub/models/person.js";
import create from "@/services/following/create.js"; import create from "@/services/following/create.js";
import { getUser } from "@/server/api/common/getters.js"; import deleteFollowing from "@/services/following/delete.js";
import { IdentifiableError } from "@/misc/identifiable-error.js";
import { ApiError } from "@/server/api/error.js"; import type { IMove } from "../../type.js";
import { meta } from "@/server/api/endpoints/following/create.js"; import { getApHrefNullable } from "../../type.js";
import { IObject } from "../../type.js";
import type { IMove, IActor } from "../../type.js";
import Resolver from "@/remote/activitypub/resolver.js";
export default async ( export default async (
actor: CacheableRemoteUser, actor: CacheableRemoteUser,
@ -21,68 +16,46 @@ export default async (
): Promise<string> => { ): Promise<string> => {
// ※ There is a block target in activity.object, which should be a local user that exists. // ※ There is a block target in activity.object, which should be a local user that exists.
const dbResolver = new DbResolver(); // fetch the new and old accounts
const resolver = new Resolver(); const targetUri = getApHrefNullable(activity.target);
let new_acc = await dbResolver.getUserFromApId(activity.target); if (!targetUri) return "move: target uri is null";
let actor_new; const new_acc = await resolvePerson(targetUri);
if (!new_acc) if (!actor.uri) return "move: actor uri is null";
actor_new = (await resolver.resolve(<string>activity.target)) as IActor; const old_acc = await resolvePerson(actor.uri);
if ( // update them if they're remote
(!new_acc || new_acc.uri === null) && if (new_acc.uri) await updatePerson(new_acc.uri);
(!actor_new || actor_new.id === null) if (old_acc.uri) await updatePerson(old_acc.uri);
) {
return "move: new acc not found"; // check if alsoKnownAs of the new account is valid
let isValidMove = true;
if (old_acc.uri) {
if (!new_acc.alsoKnownAs?.includes(old_acc.uri)) {
isValidMove = false;
}
} else if (!new_acc.alsoKnownAs?.includes(old_acc.id)) {
isValidMove = false;
}
if (!isValidMove) {
return "skip: accounts invalid";
} }
const newUri = new_acc ? new_acc.uri : actor_new?.url?.toString(); // add target uri to movedToUri in order to indicate that the user has moved
await Users.update(old_acc.id, { movedToUri: targetUri });
if (newUri === null || newUri === undefined)
return "move: new acc not found #2";
await updatePerson(newUri);
await updatePerson(actor.uri!);
new_acc = await dbResolver.getUserFromApId(newUri);
const old = await dbResolver.getUserFromApId(actor.uri!);
if (
old === null ||
old.uri === null ||
!new_acc?.alsoKnownAs?.includes(old.uri)
)
return "move: accounts invalid";
old.movedToUri = new_acc.uri;
const followee = await getUser(actor.id).catch((e) => {
if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff")
throw new ApiError(meta.errors.noSuchUser);
throw e;
});
const followeeNew = await getUser(new_acc.id).catch((e) => {
if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff")
throw new ApiError(meta.errors.noSuchUser);
throw e;
});
// follow the new account and unfollow the old one
const followings = await Followings.findBy({ const followings = await Followings.findBy({
followeeId: followee.id, followeeId: old_acc.id,
}); });
followings.forEach(async (following) => { followings.forEach(async (following) => {
//if follower is local // If follower is local
if (!following.followerHost) { if (!following.followerHost) {
const follower = await getUser(following.followerId).catch((e) => {
if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff")
throw new ApiError(meta.errors.noSuchUser);
throw e;
});
await deleteFollowing(follower!, followee);
try { try {
await create(follower!, followeeNew); const follower = await Users.findOneBy({ id: following.followerId });
} catch (e) { if (!follower) return;
await create(follower, new_acc);
await deleteFollowing(follower, old_acc);
} catch {
/* empty */ /* empty */
} }
} }

View File

@ -3,7 +3,6 @@ import { resolveUser } from "@/remote/resolve-user.js";
import { DAY } from "@/const.js"; import { DAY } from "@/const.js";
import DeliverManager from "@/remote/activitypub/deliver-manager.js"; import DeliverManager from "@/remote/activitypub/deliver-manager.js";
import { renderActivity } from "@/remote/activitypub/renderer/index.js"; import { renderActivity } from "@/remote/activitypub/renderer/index.js";
import { genId } from "@/misc/gen-id.js";
import define from "../../define.js"; import define from "../../define.js";
import { ApiError } from "../../error.js"; import { ApiError } from "../../error.js";
import { apiLogger } from "../../logger.js"; import { apiLogger } from "../../logger.js";
@ -81,7 +80,7 @@ export const paramDef = {
function moveActivity(toUrl: string, fromUrl: string) { function moveActivity(toUrl: string, fromUrl: string) {
const activity = { const activity = {
id: genId(), id: null,
actor: fromUrl, actor: fromUrl,
type: "Move", type: "Move",
object: fromUrl, object: fromUrl,