From 441ab2b5f8b815a6bce186677affce446a1bb70d Mon Sep 17 00:00:00 2001 From: MeiMei <30769358+mei23@users.noreply.github.com> Date: Wed, 31 Oct 2018 02:16:13 +0900 Subject: [PATCH] Fix: can't recognize rebirthed instance user (#3046) * resync uri from WebFinger * trigger resync on user page * allways update on resync * Revert "trigger resync on user page" This reverts commit 8ff139fb49ee61ad55e4b42c562f8a2c3f8098ac. * background resync --- src/remote/resolve-user.ts | 71 +++++++++++++++++++++----- src/server/api/endpoints/users/show.ts | 8 ++- src/tools/resync-remote-user.ts | 32 ++++++++++++ 3 files changed, 98 insertions(+), 13 deletions(-) create mode 100644 src/tools/resync-remote-user.ts diff --git a/src/remote/resolve-user.ts b/src/remote/resolve-user.ts index 15401557f5..ed259774bd 100644 --- a/src/remote/resolve-user.ts +++ b/src/remote/resolve-user.ts @@ -1,13 +1,18 @@ import { toUnicode, toASCII } from 'punycode'; -import User, { IUser } from '../models/user'; +import User, { IUser, IRemoteUser } from '../models/user'; import webFinger from './webfinger'; import config from '../config'; -import { createPerson } from './activitypub/models/person'; +import { createPerson, updatePerson } from './activitypub/models/person'; +import { URL } from 'url'; +import * as debug from 'debug'; -export default async (username: string, _host: string, option?: any): Promise => { +const log = debug('misskey:remote:resolve-user'); + +export default async (username: string, _host: string, option?: any, resync?: boolean): Promise => { const usernameLower = username.toLowerCase(); if (_host == null) { + log(`return local user: ${usernameLower}`); return await User.findOne({ usernameLower, host: null }); } @@ -15,22 +20,64 @@ export default async (username: string, _host: string, option?: any): Promise link.rel && link.rel.toLowerCase() === 'self'); - if (!self) { - throw new Error('self link not found'); - } - - user = await createPerson(self.href); + log(`return new remote user: ${acctLower}`); + return await createPerson(self.href); } + if (resync) { + log(`try resync: ${acctLower}`); + const self = await resolveSelf(acctLower); + + if ((user as IRemoteUser).uri !== self.href) { + // if uri mismatch, Fix (user@host <=> AP's Person id(IRemoteUser.uri)) mapping. + log(`uri missmatch: ${acctLower}`); + console.log(`recovery missmatch uri for (username=${username}, host=${host}) from ${(user as IRemoteUser).uri} to ${self.href}`); + + // validate uri + const uri = new URL(self.href); + if (uri.hostname !== hostAscii) { + throw new Error(`Invalied uri`); + } + + await User.update({ + usernameLower, + host: host + }, { + $set: { + uri: self.href + } + }); + } else { + log(`uri is fine: ${acctLower}`); + } + + await updatePerson(self.href); + + log(`return resynced remote user: ${acctLower}`); + return await User.findOne({ uri: self.href }); +} + + log(`return existing remote user: ${acctLower}`); return user; }; + +async function resolveSelf(acctLower: string) { + log(`WebFinger for ${acctLower}`); + const finger = await webFinger(acctLower); + const self = finger.links.find(link => link.rel && link.rel.toLowerCase() === 'self'); + if (!self) { + throw new Error('self link not found'); + } + return self; +} diff --git a/src/server/api/endpoints/users/show.ts b/src/server/api/endpoints/users/show.ts index 8ec0eb8dd9..dd09bd5b91 100644 --- a/src/server/api/endpoints/users/show.ts +++ b/src/server/api/endpoints/users/show.ts @@ -1,5 +1,5 @@ import $ from 'cafy'; import ID from '../../../../misc/cafy-id'; -import User, { pack, ILocalUser } from '../../../../models/user'; +import User, { pack, ILocalUser, isRemoteUser } from '../../../../models/user'; import resolveRemoteUser from '../../../../remote/resolve-user'; const cursorOption = { fields: { data: false } }; @@ -61,5 +61,11 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => res(await pack(user, me, { detail: true })); + + if (isRemoteUser(user)) { + if (user.updatedAt == null || Date.now() - user.updatedAt.getTime() > 1000 * 60 * 60 * 24) { + resolveRemoteUser(username, host, { }, true); + } + } } }); diff --git a/src/tools/resync-remote-user.ts b/src/tools/resync-remote-user.ts new file mode 100644 index 0000000000..3a63512f45 --- /dev/null +++ b/src/tools/resync-remote-user.ts @@ -0,0 +1,32 @@ +import parseAcct from "../misc/acct/parse"; +import resolveUser from '../remote/resolve-user'; +import * as debug from 'debug'; + +debug.enable('*'); + +async function main(acct: string): Promise { + const { username, host } = parseAcct(acct); + await resolveUser(username, host, {}, true); +} + +// get args +const args = process.argv.slice(2); +let acct = args[0]; + +// normalize args +acct = acct.replace(/^@/, ''); + +// check args +if (!acct.match(/^\w+@\w/)) { + throw `Invalied acct format. Valied format are user@host`; +} + +console.log(`resync ${acct}`); + +main(acct).then(() => { + console.log('success'); + process.exit(0); +}).catch(e => { + console.warn(e); + process.exit(1); +});