fetchPersonWithRenewal
This commit is contained in:
parent
a5cccf3799
commit
54fe8ca600
|
@ -40,6 +40,7 @@ type NodeInfo = {
|
|||
@Injectable()
|
||||
export class FetchInstanceMetadataService {
|
||||
private logger: Logger;
|
||||
private httpColon = 'https://';
|
||||
|
||||
constructor(
|
||||
private httpRequestService: HttpRequestService,
|
||||
|
@ -49,6 +50,7 @@ export class FetchInstanceMetadataService {
|
|||
private redisClient: Redis.Redis,
|
||||
) {
|
||||
this.logger = this.loggerService.getLogger('metadata', 'cyan');
|
||||
this.httpColon = 'http://';
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
@ -72,8 +74,7 @@ export class FetchInstanceMetadataService {
|
|||
const _instance = await this.federatedInstanceService.fetch(host);
|
||||
const now = Date.now();
|
||||
if (_instance && _instance.infoUpdatedAt && (now - _instance.infoUpdatedAt.getTime() < 1000 * 60 * 60 * 3)) {
|
||||
// unlock at the finally caluse
|
||||
return;
|
||||
throw new Error('Skip because updated recently');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,6 +120,12 @@ export class FetchInstanceMetadataService {
|
|||
await this.federatedInstanceService.update(instance.id, updates);
|
||||
|
||||
this.logger.succ(`Successfuly updated metadata of ${instance.host}`);
|
||||
this.logger.debug('Updated metadata:', {
|
||||
info: !!info,
|
||||
dom: !!dom,
|
||||
manifest: !!manifest,
|
||||
updates,
|
||||
});
|
||||
} catch (e) {
|
||||
this.logger.error(`Failed to update metadata of ${instance.host}: ${e}`);
|
||||
} finally {
|
||||
|
@ -131,7 +138,7 @@ export class FetchInstanceMetadataService {
|
|||
this.logger.info(`Fetching nodeinfo of ${instance.host} ...`);
|
||||
|
||||
try {
|
||||
const wellknown = await this.httpRequestService.getJson('https://' + instance.host + '/.well-known/nodeinfo')
|
||||
const wellknown = await this.httpRequestService.getJson(this.httpColon + instance.host + '/.well-known/nodeinfo')
|
||||
.catch(err => {
|
||||
if (err.statusCode === 404) {
|
||||
throw new Error('No nodeinfo provided');
|
||||
|
@ -174,7 +181,7 @@ export class FetchInstanceMetadataService {
|
|||
private async fetchDom(instance: MiInstance): Promise<DOMWindow['document']> {
|
||||
this.logger.info(`Fetching HTML of ${instance.host} ...`);
|
||||
|
||||
const url = 'https://' + instance.host;
|
||||
const url = this.httpColon + instance.host;
|
||||
|
||||
const html = await this.httpRequestService.getHtml(url);
|
||||
|
||||
|
@ -186,7 +193,7 @@ export class FetchInstanceMetadataService {
|
|||
|
||||
@bindThis
|
||||
private async fetchManifest(instance: MiInstance): Promise<Record<string, unknown> | null> {
|
||||
const url = 'https://' + instance.host;
|
||||
const url = this.httpColon + instance.host;
|
||||
|
||||
const manifestUrl = url + '/manifest.json';
|
||||
|
||||
|
@ -197,7 +204,7 @@ export class FetchInstanceMetadataService {
|
|||
|
||||
@bindThis
|
||||
private async fetchFaviconUrl(instance: MiInstance, doc: DOMWindow['document'] | null): Promise<string | null> {
|
||||
const url = 'https://' + instance.host;
|
||||
const url = this.httpColon + instance.host;
|
||||
|
||||
if (doc) {
|
||||
// https://github.com/misskey-dev/misskey/pull/8220#issuecomment-1025104043
|
||||
|
@ -224,12 +231,12 @@ export class FetchInstanceMetadataService {
|
|||
@bindThis
|
||||
private async fetchIconUrl(instance: MiInstance, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
|
||||
if (manifest && manifest.icons && manifest.icons.length > 0 && manifest.icons[0].src) {
|
||||
const url = 'https://' + instance.host;
|
||||
const url = this.httpColon + instance.host;
|
||||
return (new URL(manifest.icons[0].src, url)).href;
|
||||
}
|
||||
|
||||
if (doc) {
|
||||
const url = 'https://' + instance.host;
|
||||
const url = this.httpColon + instance.host;
|
||||
|
||||
// https://github.com/misskey-dev/misskey/pull/8220#issuecomment-1025104043
|
||||
const links = Array.from(doc.getElementsByTagName('link')).reverse();
|
||||
|
|
|
@ -122,7 +122,7 @@ export class ApDbResolverService implements OnApplicationShutdown {
|
|||
user: MiRemoteUser;
|
||||
key: MiUserPublickey | null;
|
||||
} | null> {
|
||||
const user = await this.apPersonService.resolvePerson(uri) as MiRemoteUser;
|
||||
const user = await this.apPersonService.resolvePerson(uri, undefined, true) as MiRemoteUser;
|
||||
if (user.isDeleted) return null;
|
||||
|
||||
const keys = await this.publicKeyByUserIdCache.fetch(
|
||||
|
|
|
@ -36,7 +36,6 @@ import { ApResolverService } from './ApResolverService.js';
|
|||
import { ApAudienceService } from './ApAudienceService.js';
|
||||
import { ApPersonService } from './models/ApPersonService.js';
|
||||
import { ApQuestionService } from './models/ApQuestionService.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||
import type { Resolver } from './ApResolverService.js';
|
||||
import type { IAccept, IAdd, IAnnounce, IBlock, ICreate, IDelete, IFlag, IFollow, ILike, IObject, IReject, IRemove, IUndo, IUpdate, IMove } from './type.js';
|
||||
|
@ -109,15 +108,6 @@ export class ApInboxService {
|
|||
} else {
|
||||
await this.performOneActivity(actor, activity);
|
||||
}
|
||||
|
||||
// ついでにリモートユーザーの情報が古かったら更新しておく
|
||||
if (actor.uri) {
|
||||
if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
|
||||
setImmediate(() => {
|
||||
this.apPersonService.updatePerson(actor.uri);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
|
|
@ -107,16 +107,24 @@ export class ApRequestService {
|
|||
@bindThis
|
||||
public async signedPost(user: { id: MiUser['id'] }, url: string, object: unknown, level: string): Promise<void> {
|
||||
const body = typeof object === 'string' ? object : JSON.stringify(object);
|
||||
|
||||
const key = await this.getPrivateKey(user.id, level);
|
||||
const req = createSignedPost({
|
||||
level,
|
||||
key: await this.getPrivateKey(user.id, level),
|
||||
key,
|
||||
url,
|
||||
body,
|
||||
additionalHeaders: {
|
||||
'User-Agent': this.config.userAgent,
|
||||
},
|
||||
});
|
||||
|
||||
this.logger.debug('create signed post', {
|
||||
version: 'draft',
|
||||
level,
|
||||
url,
|
||||
keyId: key.keyId,
|
||||
});
|
||||
|
||||
await this.httpRequestService.send(url, {
|
||||
method: req.request.method,
|
||||
headers: req.request.headers,
|
||||
|
@ -131,14 +139,23 @@ export class ApRequestService {
|
|||
*/
|
||||
@bindThis
|
||||
public async signedGet(url: string, user: { id: MiUser['id'] }, level: string): Promise<unknown> {
|
||||
const key = await this.getPrivateKey(user.id, level);
|
||||
const req = createSignedGet({
|
||||
level,
|
||||
key: await this.getPrivateKey(user.id, level),
|
||||
key,
|
||||
url,
|
||||
additionalHeaders: {
|
||||
'User-Agent': this.config.userAgent,
|
||||
},
|
||||
});
|
||||
|
||||
this.logger.debug('create signed get', {
|
||||
version: 'draft',
|
||||
level,
|
||||
url,
|
||||
keyId: key.keyId,
|
||||
});
|
||||
|
||||
const res = await this.httpRequestService.send(url, {
|
||||
method: req.request.method,
|
||||
headers: req.request.headers,
|
||||
|
|
|
@ -248,6 +248,22 @@ export class ApPersonService implements OnModuleInit {
|
|||
return null;
|
||||
}
|
||||
|
||||
@bindThis
|
||||
async fetchPersonWithRenewal(uri: string): Promise<MiLocalUser | MiRemoteUser | null> {
|
||||
const exist = await this.fetchPerson(uri);
|
||||
if (exist == null) return null;
|
||||
|
||||
// ついでにリモートユーザーの情報が古かったら更新しておく
|
||||
if (this.userEntityService.isRemoteUser(exist)) {
|
||||
if (exist.lastFetchedAt == null || Date.now() - exist.lastFetchedAt.getTime() > 1000 * 60 * 60 * 3) {
|
||||
await this.updatePerson(exist.uri);
|
||||
return await this.fetchPerson(uri);
|
||||
}
|
||||
}
|
||||
|
||||
return exist;
|
||||
}
|
||||
|
||||
private async resolveAvatarAndBanner(user: MiRemoteUser, icon: any, image: any): Promise<Partial<Pick<MiRemoteUser, 'avatarId' | 'bannerId' | 'avatarUrl' | 'bannerUrl' | 'avatarBlurhash' | 'bannerBlurhash'>>> {
|
||||
if (user == null) throw new Error('failed to create user: user is null');
|
||||
|
||||
|
@ -624,9 +640,9 @@ export class ApPersonService implements OnModuleInit {
|
|||
* リモートサーバーからフェッチしてMisskeyに登録しそれを返します。
|
||||
*/
|
||||
@bindThis
|
||||
public async resolvePerson(uri: string, resolver?: Resolver): Promise<MiLocalUser | MiRemoteUser> {
|
||||
public async resolvePerson(uri: string, resolver?: Resolver, withRenewal = false): Promise<MiLocalUser | MiRemoteUser> {
|
||||
//#region このサーバーに既に登録されていたらそれを返す
|
||||
const exist = await this.fetchPerson(uri);
|
||||
const exist = withRenewal ? await this.fetchPersonWithRenewal(uri) : await this.fetchPerson(uri);
|
||||
if (exist) return exist;
|
||||
//#endregion
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import type { MiRemoteUser } from '@/models/User.js';
|
|||
import type { MiUserPublickey } from '@/models/UserPublickey.js';
|
||||
import { ApDbResolverService } from '@/core/activitypub/ApDbResolverService.js';
|
||||
import { StatusError } from '@/misc/status-error.js';
|
||||
import * as Acct from '@/misc/acct.js';
|
||||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js';
|
||||
import { LdSignatureService } from '@/core/activitypub/LdSignatureService.js';
|
||||
|
@ -79,7 +80,6 @@ export class InboxProcessorService {
|
|||
key: MiUserPublickey | null;
|
||||
} | null = null;
|
||||
|
||||
// keyIdでわからなければ、activity.actorを元にDBから取得 || activity.actorを元にリモートから取得
|
||||
try {
|
||||
authUser = await this.apDbResolverService.getAuthUserFromApId(getApId(activity.actor), signature.keyId);
|
||||
} catch (err) {
|
||||
|
@ -103,7 +103,15 @@ export class InboxProcessorService {
|
|||
}
|
||||
|
||||
// HTTP-Signatureの検証
|
||||
const httpSignatureValidated = verifyDraftSignature(signature, authUser.key.keyPem);
|
||||
const errorLogger = (ms: any) => this.logger.error(ms);
|
||||
const httpSignatureValidated = verifyDraftSignature(signature, authUser.key.keyPem, errorLogger);
|
||||
this.logger.debug('Inbox message validation: ', {
|
||||
userId: authUser.user.id,
|
||||
userAcct: Acct.toString(authUser.user),
|
||||
parsedKeyId: signature.keyId,
|
||||
foundKeyId: authUser.key.keyId,
|
||||
httpSignatureValidated,
|
||||
});
|
||||
|
||||
// また、signatureのsignerは、activity.actorと一致する必要がある
|
||||
if (!httpSignatureValidated || authUser.user.uri !== activity.actor) {
|
||||
|
|
Loading…
Reference in New Issue