perf(federation): Use hint for getAuthUserFromApId (#13470)

* Hint for getAuthUserFromApId

* とどのつまりこれでいいのか?
This commit is contained in:
MeiMei 2024-02-28 16:44:01 +09:00 committed by GitHub
parent 59ae735169
commit aaacfabc1b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 13 additions and 60 deletions

View file

@ -35,7 +35,6 @@ export type UriParseResult = {
@Injectable() @Injectable()
export class ApDbResolverService implements OnApplicationShutdown { export class ApDbResolverService implements OnApplicationShutdown {
private publicKeyCache: MemoryKVCache<MiUserPublickey | null>;
private publicKeyByUserIdCache: MemoryKVCache<MiUserPublickey[] | null>; private publicKeyByUserIdCache: MemoryKVCache<MiUserPublickey[] | null>;
constructor( constructor(
@ -54,7 +53,6 @@ export class ApDbResolverService implements OnApplicationShutdown {
private cacheService: CacheService, private cacheService: CacheService,
private apPersonService: ApPersonService, private apPersonService: ApPersonService,
) { ) {
this.publicKeyCache = new MemoryKVCache<MiUserPublickey | null>(1e3 * 60 * 20); // 20分
this.publicKeyByUserIdCache = new MemoryKVCache<MiUserPublickey[] | null>(1e3 * 60 * 20); // 20分 this.publicKeyByUserIdCache = new MemoryKVCache<MiUserPublickey[] | null>(1e3 * 60 * 20); // 20分
} }
@ -116,41 +114,11 @@ export class ApDbResolverService implements OnApplicationShutdown {
} }
} }
/**
* AP KeyId => Misskey User and Key
*/
@bindThis
public async getAuthUserFromKeyId(keyId: string): Promise<{
user: MiRemoteUser;
key: MiUserPublickey;
} | null> {
const key = await this.publicKeyCache.fetch(keyId, async () => {
const key = await this.userPublickeysRepository.findOneBy({
keyId,
});
if (key == null) return null;
return key;
}, key => key != null);
if (key == null) return null;
const user = await this.cacheService.findUserById(key.userId).catch(() => null) as MiRemoteUser | null;
if (user == null) return null;
if (user.isDeleted) return null;
return {
user,
key,
};
}
/** /**
* AP Actor id => Misskey User and Key * AP Actor id => Misskey User and Key
*/ */
@bindThis @bindThis
public async getAuthUserFromApId(uri: string): Promise<{ public async getAuthUserFromApId(uri: string, keyId?: string): Promise<{
user: MiRemoteUser; user: MiRemoteUser;
key: MiUserPublickey | null; key: MiUserPublickey | null;
} | null> { } | null> {
@ -170,6 +138,7 @@ export class ApDbResolverService implements OnApplicationShutdown {
keys[0] : keys[0] :
keys.find(x => { keys.find(x => {
try { try {
if (x.keyId === keyId) return true;
const url = new URL(x.keyId); const url = new URL(x.keyId);
const path = url.pathname.split('/').pop()?.toLowerCase(); const path = url.pathname.split('/').pop()?.toLowerCase();
if (url.hash) { if (url.hash) {
@ -193,16 +162,10 @@ export class ApDbResolverService implements OnApplicationShutdown {
@bindThis @bindThis
public refreshCacheByUserId(userId: MiUser['id']): void { public refreshCacheByUserId(userId: MiUser['id']): void {
this.publicKeyByUserIdCache.delete(userId); this.publicKeyByUserIdCache.delete(userId);
for (const [k, v] of this.publicKeyCache.cache.entries()) {
if (v.value?.userId === userId) {
this.publicKeyCache.delete(k);
}
}
} }
@bindThis @bindThis
public dispose(): void { public dispose(): void {
this.publicKeyCache.dispose();
this.publicKeyByUserIdCache.dispose(); this.publicKeyByUserIdCache.dispose();
} }

View file

@ -77,12 +77,11 @@ export class InboxProcessorService {
let authUser: { let authUser: {
user: MiRemoteUser; user: MiRemoteUser;
key: MiUserPublickey | null; key: MiUserPublickey | null;
} | null = await this.apDbResolverService.getAuthUserFromKeyId(signature.keyId); } | null = null;
// keyIdでわからなければ、activity.actorを元にDBから取得 || activity.actorを元にリモートから取得 // keyIdでわからなければ、activity.actorを元にDBから取得 || activity.actorを元にリモートから取得
if (authUser == null) {
try { try {
authUser = await this.apDbResolverService.getAuthUserFromApId(getApId(activity.actor)); authUser = await this.apDbResolverService.getAuthUserFromApId(getApId(activity.actor), signature.keyId);
} catch (err) { } catch (err) {
// 対象が4xxならスキップ // 対象が4xxならスキップ
if (err instanceof StatusError) { if (err instanceof StatusError) {
@ -92,7 +91,6 @@ export class InboxProcessorService {
throw new Error(`Error in actor ${activity.actor} - ${err.statusCode}`); throw new Error(`Error in actor ${activity.actor} - ${err.statusCode}`);
} }
} }
}
// それでもわからなければ終了 // それでもわからなければ終了
if (authUser == null) { if (authUser == null) {
@ -110,21 +108,13 @@ export class InboxProcessorService {
// また、signatureのsignerは、activity.actorと一致する必要がある // また、signatureのsignerは、activity.actorと一致する必要がある
if (!httpSignatureValidated || authUser.user.uri !== activity.actor) { if (!httpSignatureValidated || authUser.user.uri !== activity.actor) {
// 一致しなくても、でもLD-Signatureがありそうならそっちも見る // 一致しなくても、でもLD-Signatureがありそうならそっちも見る
if (activity.signature) { if (activity.signature?.creator) {
if (activity.signature.type !== 'RsaSignature2017') { if (activity.signature.type !== 'RsaSignature2017') {
throw new Bull.UnrecoverableError(`skip: unsupported LD-signature type ${activity.signature.type}`); throw new Bull.UnrecoverableError(`skip: unsupported LD-signature type ${activity.signature.type}`);
} }
// activity.signature.creator: https://example.oom/users/user#main-key authUser = await this.apDbResolverService.getAuthUserFromApId(activity.signature.creator.replace(/#.*/, ''));
// みたいになっててUserを引っ張れば公開キーも入ることを期待する
if (activity.signature.creator) {
const candicate = activity.signature.creator.replace(/#.*/, '');
const user = await this.apPersonService.resolvePerson(candicate).catch(() => null);
if (user) this.apDbResolverService.refreshCacheByUserId(user.id);
}
// keyIdからLD-Signatureのユーザーを取得
authUser = await this.apDbResolverService.getAuthUserFromKeyId(activity.signature.creator);
if (authUser == null) { if (authUser == null) {
throw new Bull.UnrecoverableError('skip: LD-Signatureのユーザーが取得できませんでした'); throw new Bull.UnrecoverableError('skip: LD-Signatureのユーザーが取得できませんでした');
} }