Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf(federation): Ed25519署名に対応する #13464

Merged
merged 155 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
155 commits
Select commit Hold shift + click to select a range
02dfe0a
1. ed25519キーペアを発行・Personとして公開鍵を送受信
tamaina Feb 26, 2024
1835397
validate additionalPublicKeys
tamaina Feb 26, 2024
5b7b850
getAuthUserFromApIdはmainを選ぶ
tamaina Feb 26, 2024
00738b9
:v:
tamaina Feb 26, 2024
172546f
fix
tamaina Feb 26, 2024
1d780ac
signatureAlgorithm
tamaina Feb 27, 2024
13e0a64
set publicKeyCache lifetime
tamaina Feb 27, 2024
e2a8f4f
refresh
tamaina Feb 27, 2024
5876a28
httpMessageSignatureAcceptable
tamaina Feb 27, 2024
eb8bef4
ED25519_SIGNED_ALGORITHM
tamaina Feb 27, 2024
437e69c
ED25519_PUBLIC_KEY_SIGNATURE_ALGORITHM
tamaina Feb 27, 2024
9705ec4
remove sign additionalPublicKeys signature requirements
tamaina Feb 27, 2024
f6b7872
httpMessageSignaturesSupported
tamaina Feb 27, 2024
8579cb2
httpMessageSignaturesImplementationLevel
tamaina Feb 27, 2024
59ae735
httpMessageSignaturesImplementationLevel: '01'
tamaina Feb 27, 2024
aaacfab
perf(federation): Use hint for getAuthUserFromApId (#13470)
mei23 Feb 28, 2024
2bc4221
Merge branch 'develop' into ed25519
tamaina Feb 28, 2024
a4e7d69
Merge branch 'develop' into ed25519
tamaina Feb 29, 2024
a1e6cb0
use @misskey-dev/node-http-message-signatures
tamaina Feb 29, 2024
fc20ef0
fix
tamaina Feb 29, 2024
735714d
signedPost, signedGet
tamaina Feb 29, 2024
434520a
ap-request.tsを復活させる
tamaina Feb 29, 2024
5f89b0a
remove digest prerender
tamaina Feb 29, 2024
66c0942
fix test?
tamaina Feb 29, 2024
7751d80
fix test
tamaina Feb 29, 2024
16cea7d
add httpMessageSignaturesImplementationLevel to FederationInstance
tamaina Mar 1, 2024
87ded2b
ManyToOne
tamaina Mar 1, 2024
a5cccf3
Merge branch 'develop' into ed25519
tamaina Mar 1, 2024
54fe8ca
fetchPersonWithRenewal
tamaina Mar 1, 2024
bec6159
exactKey
tamaina Mar 1, 2024
743b740
:v:
tamaina Mar 1, 2024
0aa316e
Merge branch 'develop' into ed25519
tamaina Mar 1, 2024
fd71ad7
use const
tamaina Mar 1, 2024
67758d2
use gen-key-pair fn. from '@misskey-dev/node-http-message-signatures'
tamaina Mar 1, 2024
65fa25a
Merge branch 'develop' into ed25519
tamaina Mar 1, 2024
86c9f0b
update node-http-message-signatures
tamaina Mar 1, 2024
65bd187
fix
tamaina Mar 1, 2024
9111b5c
@misskey-dev/[email protected]
tamaina Mar 1, 2024
d86b8c8
getAuthUserFromApIdでupdatePersonの頻度を増やす
tamaina Mar 1, 2024
ea6c38c
cacheRaw.date
tamaina Mar 1, 2024
30820d9
Merge branch 'develop' into ed25519
tamaina Mar 2, 2024
1357b07
use requiredInputs
tamaina Mar 2, 2024
e4f70f0
Merge branch 'develop' into ed25519
tamaina Mar 3, 2024
a405b62
update @misskey-dev/node-http-message-signatures
tamaina Mar 3, 2024
13af6f2
clean up
tamaina Mar 3, 2024
aabdb66
err msg
tamaina Mar 3, 2024
25d5a8c
fix(backend): fetchInstanceMetadataのLockが永遠に解除されない問題を修正
tamaina Mar 3, 2024
89e1ff6
fix httpMessageSignaturesImplementationLevel validation
tamaina Mar 3, 2024
862ebe2
Merge branch 'fix-fedupdlck' into ed25519
tamaina Mar 3, 2024
2dde845
fix test
tamaina Mar 3, 2024
41a461e
fix
tamaina Mar 3, 2024
2926f68
comment
tamaina Mar 3, 2024
64fcf73
comment
tamaina Mar 3, 2024
7eb19d5
improve test
tamaina Mar 3, 2024
76b20dc
Merge branch 'fix-fedupdlck' into ed25519
tamaina Mar 3, 2024
c7eed1c
fix
tamaina Mar 3, 2024
6a56aea
use Promise.all in genRSAAndEd25519KeyPair
tamaina Mar 3, 2024
d772eac
refreshAndprepareEd25519KeyPair
tamaina Mar 3, 2024
941aed6
refreshAndfindKey
tamaina Mar 4, 2024
83f6358
commetn
tamaina Mar 4, 2024
25cc9e0
refactor public keys add
tamaina Mar 4, 2024
eefca03
digestプリレンダを復活させる
tamaina Mar 4, 2024
79249a0
fix, async
tamaina Mar 4, 2024
7a334a5
fix
tamaina Mar 4, 2024
821a79f
!== true
tamaina Mar 4, 2024
1af1bc8
use save
tamaina Mar 4, 2024
7d77c70
Deliver update person when new key generated (not tested)
tamaina Mar 4, 2024
ac2cf73
Merge branch 'develop' into ed25519
tamaina Mar 4, 2024
15782f7
循環参照で落ちるのを解消?
tamaina Mar 5, 2024
0082f6f
fix?
tamaina Mar 5, 2024
2a622b0
Revert "fix?"
tamaina Mar 5, 2024
31bf1db
a
tamaina Mar 5, 2024
4b9ffb8
logger
tamaina Mar 5, 2024
ac4336d
log
tamaina Mar 5, 2024
6e4357c
change logger
tamaina Mar 5, 2024
430f0b7
秘密鍵の変更は、フラグではなく鍵を引き回すようにする
tamaina Mar 5, 2024
e4fea42
addAllKnowingSharedInboxRecipe
tamaina Mar 5, 2024
021801c
nanka meccha kaeta
tamaina Mar 5, 2024
a84de3c
Merge branch 'develop' into ed25519
tamaina Mar 5, 2024
6b02efa
delivre
tamaina Mar 5, 2024
0e509c4
キャッシュ有効チェックはロック取得前に行う
tamaina Mar 5, 2024
834f465
@misskey-dev/[email protected]
tamaina Mar 5, 2024
689a9ce
PrivateKeyPem
tamaina Mar 5, 2024
0127f89
getLocalUserPrivateKey
tamaina Mar 5, 2024
01b8d2f
fix test
tamaina Mar 5, 2024
ab29cba
if
tamaina Mar 5, 2024
a701fed
fix ap-request
tamaina Mar 5, 2024
39fba74
update node-http-message-signatures
tamaina Mar 6, 2024
fef9ebf
fix type error
tamaina Mar 6, 2024
844feb1
update package
tamaina Mar 7, 2024
9973610
Merge branch 'develop' into ed25519
tamaina Mar 7, 2024
e543ffe
fix type
tamaina Mar 7, 2024
74c8f0a
update package
tamaina Mar 7, 2024
6907b65
retry no key
tamaina Mar 9, 2024
d0da9f3
@misskey-dev/[email protected]
tamaina Mar 9, 2024
75a2f1c
fix type error
tamaina Mar 9, 2024
4310229
log keyid
tamaina Mar 9, 2024
08e3a7c
Merge branch 'develop' into ed25519
tamaina Mar 9, 2024
d168ec7
logger
tamaina Mar 9, 2024
70693af
Merge branch 'ed25519' of https://github.com/misskey-dev/misskey into…
tamaina Mar 9, 2024
1690e06
db-resolver
tamaina Mar 9, 2024
da4a44b
JSON.stringify
tamaina Mar 9, 2024
8104963
HTTP Signatureがなかったり使えなかったりしそうな場合にLD Signatureを活用するように
tamaina Mar 9, 2024
154a202
inbox-delayed use actor if no signature
tamaina Mar 9, 2024
eb84956
ユーザーとキーの同一性チェックはhostの一致にする
tamaina Mar 9, 2024
9bfa38e
log signature parse err
tamaina Mar 9, 2024
e2b574a
save array
tamaina Mar 10, 2024
76487de
とりあえずtryで囲っておく
tamaina Mar 10, 2024
d7c32ce
fetchPersonWithRenewalでエラーが起きたら古いデータを返す
tamaina Mar 10, 2024
aa5181c
use transactionalEntityManager
tamaina Mar 10, 2024
d200da8
Merge branch 'develop' into ed25519
tamaina May 2, 2024
c58b4f8
fix spdx
tamaina May 2, 2024
baca55c
Merge branch 'develop' into ed25519
tamaina May 8, 2024
be102f2
@misskey-dev/[email protected]
tamaina May 8, 2024
bdaef5f
Merge branch 'develop' into ed25519
tamaina Jun 11, 2024
f31996e
add comment
tamaina Jun 11, 2024
3717ff3
fix
tamaina Jun 11, 2024
64004fd
publicKeyに配列が入ってもいいようにする
tamaina Jun 11, 2024
133970a
define additionalPublicKeys
tamaina Jun 11, 2024
a3d4eae
fix
tamaina Jun 11, 2024
7306a6c
Merge branch 'develop' into ed25519
tamaina Jun 29, 2024
7353c73
merge fix
tamaina Jun 29, 2024
3777779
Merge branch 'develop' into ed25519
tamaina Jul 17, 2024
c80b16c
refreshAndprepareEd25519KeyPair → refreshAndPrepareEd25519KeyPair
tamaina Jul 17, 2024
7e2c3e4
remove gen-key-pair.ts
tamaina Jul 17, 2024
f2c412c
defaultMaxListeners = 512
tamaina Jul 17, 2024
57bfffe
Revert "defaultMaxListeners = 512"
tamaina Jul 17, 2024
d0aada5
genRSAAndEd25519KeyPairではキーを直列に生成する?
tamaina Jul 17, 2024
613c127
maxConcurrency: 8
tamaina Jul 17, 2024
a80a7f6
maxConcurrency: 16
tamaina Jul 17, 2024
c2d084b
maxConcurrency: 8
tamaina Jul 17, 2024
d3280fe
Revert "genRSAAndEd25519KeyPairではキーを直列に生成する?"
tamaina Jul 17, 2024
9e0a93f
maxWorkers: '90%'
tamaina Jul 17, 2024
38a5e09
Revert "maxWorkers: '90%'"
tamaina Jul 17, 2024
44f0064
e2e/timelines.tsで個々のテストに対するtimeoutを削除, maxConcurrency: 32
tamaina Jul 17, 2024
09b2e71
better error handling of this.userPublickeysRepository.delete
tamaina Jul 17, 2024
41883c4
better comment
tamaina Jul 17, 2024
5afc659
set result to keypairEntityCache
tamaina Jul 17, 2024
a0c93bb
Merge branch 'develop' into ed25519
tamaina Jul 17, 2024
ffd12d0
deliverJobConcurrency: 16, deliverJobPerSec: 1024, inboxJobConcurrenc…
tamaina Jul 17, 2024
fe77f21
inboxJobPerSec: 64
tamaina Jul 17, 2024
b7349e5
delete request.headers['host'];
tamaina Jul 17, 2024
1f0e7a4
fix
tamaina Jul 17, 2024
de677a5
// node-fetch will generate this for us. if we keep 'Host', it won't …
tamaina Jul 17, 2024
e602f2e
move delete host
tamaina Jul 17, 2024
72cda5c
modify comment
tamaina Jul 17, 2024
9591860
modify comment
tamaina Jul 17, 2024
cd19ad6
fix correct → collect
tamaina Jul 17, 2024
99113d5
refreshAndfindKey → refreshAndFindKey
tamaina Jul 17, 2024
c00b61e
modify comment
tamaina Jul 17, 2024
29d9bbf
modify attachLdSignature
tamaina Jul 17, 2024
aed2806
getApId, InboxProcessorService
tamaina Jul 17, 2024
8c76c7b
TODO
tamaina Jul 17, 2024
61d904e
[skip ci] add CHANGELOG
tamaina Jul 17, 2024
4c33e48
Merge branch 'develop' into ed25519
tamaina Jul 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions packages/backend/migration/1708980134301-APMultipleKeys.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/

export class APMultipleKeys1708980134301 {
name = 'APMultipleKeys1708980134301'

async up(queryRunner) {
await queryRunner.query(`DROP INDEX "public"."IDX_171e64971c780ebd23fae140bb"`);
await queryRunner.query(`ALTER TABLE "user_keypair" ADD "ed25519PublicKey" character varying(128)`);
await queryRunner.query(`ALTER TABLE "user_keypair" ADD "ed25519PrivateKey" character varying(128)`);
await queryRunner.query(`ALTER TABLE "user_keypair" ADD "ed25519PublicKeySignature" character varying(720)`);
await queryRunner.query(`ALTER TABLE "user_keypair" ADD "ed25519SignatureAlgorithm" character varying(32)`);
await queryRunner.query(`ALTER TABLE "user_publickey" DROP CONSTRAINT "FK_10c146e4b39b443ede016f6736d"`);
await queryRunner.query(`ALTER TABLE "user_publickey" DROP CONSTRAINT "PK_10c146e4b39b443ede016f6736d"`);
await queryRunner.query(`ALTER TABLE "user_publickey" ADD CONSTRAINT "PK_0db6a5fdb992323449edc8ee421" PRIMARY KEY ("userId", "keyId")`);
await queryRunner.query(`ALTER TABLE "user_publickey" DROP CONSTRAINT "PK_0db6a5fdb992323449edc8ee421"`);
await queryRunner.query(`ALTER TABLE "user_publickey" ADD CONSTRAINT "PK_171e64971c780ebd23fae140bba" PRIMARY KEY ("keyId")`);
await queryRunner.query(`ALTER TABLE "user_publickey" ADD CONSTRAINT "UQ_10c146e4b39b443ede016f6736d" UNIQUE ("userId")`);
await queryRunner.query(`CREATE INDEX "IDX_10c146e4b39b443ede016f6736" ON "user_publickey" ("userId") `);
await queryRunner.query(`ALTER TABLE "user_publickey" ADD CONSTRAINT "FK_10c146e4b39b443ede016f6736d" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}

async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "user_publickey" DROP CONSTRAINT "FK_10c146e4b39b443ede016f6736d"`);
await queryRunner.query(`DROP INDEX "public"."IDX_10c146e4b39b443ede016f6736"`);
await queryRunner.query(`ALTER TABLE "user_publickey" DROP CONSTRAINT "UQ_10c146e4b39b443ede016f6736d"`);
await queryRunner.query(`ALTER TABLE "user_publickey" DROP CONSTRAINT "PK_171e64971c780ebd23fae140bba"`);
await queryRunner.query(`ALTER TABLE "user_publickey" ADD CONSTRAINT "PK_0db6a5fdb992323449edc8ee421" PRIMARY KEY ("userId", "keyId")`);
await queryRunner.query(`ALTER TABLE "user_publickey" DROP CONSTRAINT "PK_0db6a5fdb992323449edc8ee421"`);
await queryRunner.query(`ALTER TABLE "user_publickey" ADD CONSTRAINT "PK_10c146e4b39b443ede016f6736d" PRIMARY KEY ("userId")`);
await queryRunner.query(`ALTER TABLE "user_publickey" ADD CONSTRAINT "FK_10c146e4b39b443ede016f6736d" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "followersVisibility" DROP DEFAULT`);
await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "followersVisibility" TYPE "public"."user_profile_followersVisibility_enum_old" USING "followersVisibility"::"text"::"public"."user_profile_followersVisibility_enum_old"`);
await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "followersVisibility" SET DEFAULT 'public'`);
await queryRunner.query(`ALTER TABLE "user_keypair" DROP COLUMN "ed25519SignatureAlgorithm"`);
await queryRunner.query(`ALTER TABLE "user_keypair" DROP COLUMN "ed25519PublicKeySignature"`);
await queryRunner.query(`ALTER TABLE "user_keypair" DROP COLUMN "ed25519PrivateKey"`);
await queryRunner.query(`ALTER TABLE "user_keypair" DROP COLUMN "ed25519PublicKey"`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_171e64971c780ebd23fae140bb" ON "user_publickey" ("keyId") `);
}
}
7 changes: 3 additions & 4 deletions packages/backend/src/core/CreateSystemUserService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { randomUUID } from 'node:crypto';
import { Inject, Injectable } from '@nestjs/common';
import bcrypt from 'bcryptjs';
import { IsNull, DataSource } from 'typeorm';
import { genRsaKeyPair } from '@/misc/gen-key-pair.js';
import { genRSAAndEd25519KeyPair } from '@/misc/gen-key-pair.js';
import { MiUser } from '@/models/User.js';
import { MiUserProfile } from '@/models/UserProfile.js';
import { IdService } from '@/core/IdService.js';
Expand Down Expand Up @@ -38,7 +38,7 @@ export class CreateSystemUserService {
// Generate secret
const secret = generateNativeUserToken();

const keyPair = await genRsaKeyPair();
const keyPair = await genRSAAndEd25519KeyPair();

let account!: MiUser;

Expand All @@ -64,9 +64,8 @@ export class CreateSystemUserService {
}).then(x => transactionalEntityManager.findOneByOrFail(MiUser, x.identifiers[0]));

await transactionalEntityManager.insert(MiUserKeypair, {
publicKey: keyPair.publicKey,
privateKey: keyPair.privateKey,
userId: account.id,
...keyPair,
});

await transactionalEntityManager.insert(MiUserProfile, {
Expand Down
1 change: 1 addition & 0 deletions packages/backend/src/core/GlobalEventService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ export interface InternalEventTypes {
unmute: { muterId: MiUser['id']; muteeId: MiUser['id']; };
userListMemberAdded: { userListId: MiUserList['id']; memberId: MiUser['id']; };
userListMemberRemoved: { userListId: MiUserList['id']; memberId: MiUser['id']; };
userKeypairUpdated: { userId: MiUser['id']; };
}

// name/messages(spec) pairs dictionary
Expand Down
21 changes: 3 additions & 18 deletions packages/backend/src/core/SignupService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { bindThis } from '@/decorators.js';
import UsersChart from '@/core/chart/charts/users.js';
import { UtilityService } from '@/core/UtilityService.js';
import { MetaService } from '@/core/MetaService.js';
import { genRSAAndEd25519KeyPair } from '@/misc/gen-key-pair.js';

@Injectable()
export class SignupService {
Expand Down Expand Up @@ -93,22 +94,7 @@ export class SignupService {
}
}

const keyPair = await new Promise<string[]>((res, rej) =>
generateKeyPair('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'spki',
format: 'pem',
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: undefined,
passphrase: undefined,
},
}, (err, publicKey, privateKey) =>
err ? rej(err) : res([publicKey, privateKey]),
));
const keyPair = await genRSAAndEd25519KeyPair();

let account!: MiUser;

Expand All @@ -131,9 +117,8 @@ export class SignupService {
}));

await transactionalEntityManager.save(new MiUserKeypair({
publicKey: keyPair[0],
privateKey: keyPair[1],
userId: account.id,
...keyPair,
}));

await transactionalEntityManager.save(new MiUserProfile({
Expand Down
45 changes: 44 additions & 1 deletion packages/backend/src/core/UserKeypairService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/

import { sign } from 'node:crypto';
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
import * as Redis from 'ioredis';
import type { MiUser } from '@/models/User.js';
Expand All @@ -11,6 +12,8 @@ import { RedisKVCache } from '@/misc/cache.js';
import type { MiUserKeypair } from '@/models/UserKeypair.js';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
import { ED25519_SIGN_ALGORITHM, genEd25519KeyPair } from '@/misc/gen-key-pair.js';
import { GlobalEventService, GlobalEvents } from '@/core/GlobalEventService.js';

@Injectable()
export class UserKeypairService implements OnApplicationShutdown {
Expand All @@ -19,9 +22,12 @@ export class UserKeypairService implements OnApplicationShutdown {
constructor(
@Inject(DI.redis)
private redisClient: Redis.Redis,

@Inject(DI.redisForSub)
private redisForSub: Redis.Redis,
@Inject(DI.userKeypairsRepository)
private userKeypairsRepository: UserKeypairsRepository,

private globalEventService: GlobalEventService,
) {
this.cache = new RedisKVCache<MiUserKeypair>(this.redisClient, 'userKeypair', {
lifetime: 1000 * 60 * 60 * 24, // 24h
Expand All @@ -30,13 +36,50 @@ export class UserKeypairService implements OnApplicationShutdown {
toRedisConverter: (value) => JSON.stringify(value),
fromRedisConverter: (value) => JSON.parse(value),
});

this.redisForSub.on('message', this.onMessage);
}

@bindThis
public async getUserKeypair(userId: MiUser['id']): Promise<MiUserKeypair> {
return await this.cache.fetch(userId);
}

@bindThis
public async refresh(userId: MiUser['id']): Promise<void> {
return await this.cache.refresh(userId);
}

@bindThis
public async prepareEd25519KeyPair(userId: MiUser['id']): Promise<void> {
await this.refresh(userId);
const keypair = await this.cache.fetch(userId);
if (keypair.ed25519PublicKey != null) return;
const ed25519 = await genEd25519KeyPair();
const ed25519PublicKeySignature = sign(ED25519_SIGN_ALGORITHM, Buffer.from(ed25519.publicKey), keypair.privateKey).toString('base64');
tamaina marked this conversation as resolved.
Show resolved Hide resolved
await this.userKeypairsRepository.update({ userId }, {
ed25519PublicKey: ed25519.publicKey,
ed25519PrivateKey: ed25519.privateKey,
ed25519PublicKeySignature,
ed25519SignatureAlgorithm: `rsa-${ED25519_SIGN_ALGORITHM}`,
});
this.globalEventService.publishInternalEvent('userKeypairUpdated', { userId });
}

@bindThis
private async onMessage(_: string, data: string): Promise<void> {
const obj = JSON.parse(data);

if (obj.channel === 'internal') {
const { type, body } = obj.message as GlobalEvents['internal']['payload'];
switch (type) {
case 'userKeypairUpdated': {
this.refresh(body.userId);
break;
}
}
}
}
@bindThis
public dispose(): void {
this.cache.dispose();
Expand Down
43 changes: 37 additions & 6 deletions packages/backend/src/core/activitypub/ApDbResolverService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { NotesRepository, UserPublickeysRepository, UsersRepository } from '@/models/_.js';
import type { MiUser, NotesRepository, UserPublickeysRepository, UsersRepository } from '@/models/_.js';
import type { Config } from '@/config.js';
import { MemoryKVCache } from '@/misc/cache.js';
import type { MiUserPublickey } from '@/models/UserPublickey.js';
Expand Down Expand Up @@ -36,7 +36,7 @@ export type UriParseResult = {
@Injectable()
export class ApDbResolverService implements OnApplicationShutdown {
private publicKeyCache: MemoryKVCache<MiUserPublickey | null>;
private publicKeyByUserIdCache: MemoryKVCache<MiUserPublickey | null>;
private publicKeyByUserIdCache: MemoryKVCache<MiUserPublickey[] | null>;

constructor(
@Inject(DI.config)
Expand All @@ -54,8 +54,8 @@ export class ApDbResolverService implements OnApplicationShutdown {
private cacheService: CacheService,
private apPersonService: ApPersonService,
) {
this.publicKeyCache = new MemoryKVCache<MiUserPublickey | null>(Infinity);
this.publicKeyByUserIdCache = new MemoryKVCache<MiUserPublickey | null>(Infinity);
this.publicKeyCache = new MemoryKVCache<MiUserPublickey | null>(1e3 * 60 * 20); // 20分
this.publicKeyByUserIdCache = new MemoryKVCache<MiUserPublickey[] | null>(1e3 * 60 * 20); // 20分
}

@bindThis
Expand Down Expand Up @@ -157,18 +157,49 @@ export class ApDbResolverService implements OnApplicationShutdown {
const user = await this.apPersonService.resolvePerson(uri) as MiRemoteUser;
if (user.isDeleted) return null;

const key = await this.publicKeyByUserIdCache.fetch(
const keys = await this.publicKeyByUserIdCache.fetch(
user.id,
() => this.userPublickeysRepository.findOneBy({ userId: user.id }),
() => this.userPublickeysRepository.find({ where: { userId: user.id } }),
v => v != null,
);

if (keys == null || keys.length === 8) return null;

// 公開鍵は複数あるが、mainっぽいのを選ぶ
const key = keys.length === 1 ?
keys[0] :
keys.find(x => {
try {
const url = new URL(x.keyId);
const path = url.pathname.split('/').pop()?.toLowerCase();
if (url.hash) {
if (url.hash.toLowerCase().includes('main')) {
return true;
}
} else if (path?.includes('main') || path === 'publickey') {
return true;
}
} catch { /* noop */ }

return false;
}) ?? keys[0];

return {
user,
key,
};
}

@bindThis
public refreshCacheByUserId(userId: MiUser['id']): void {
this.publicKeyByUserIdCache.delete(userId);
for (const [k, v] of this.publicKeyCache.cache.entries()) {
if (v.value?.userId === userId) {
this.publicKeyCache.delete(k);
}
}
}

@bindThis
public dispose(): void {
this.publicKeyCache.dispose();
Expand Down
21 changes: 14 additions & 7 deletions packages/backend/src/core/activitypub/ApDeliverManagerService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import { DI } from '@/di-symbols.js';
import type { FollowingsRepository } from '@/models/_.js';
import type { MiLocalUser, MiRemoteUser, MiUser } from '@/models/User.js';
import { QueueService } from '@/core/QueueService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { bindThis } from '@/decorators.js';
import type { IActivity } from '@/core/activitypub/type.js';
import { ThinUser } from '@/queue/types.js';
import { UserKeypairService } from '../UserKeypairService.js';

interface IRecipe {
type: string;
Expand Down Expand Up @@ -40,14 +40,14 @@ class DeliverManager {

/**
* Constructor
* @param userEntityService
* @param userKeypairService
* @param followingsRepository
* @param queueService
* @param actor Actor
* @param activity Activity to deliver
*/
constructor(
private userEntityService: UserEntityService,
private userKeypairService: UserKeypairService,
private followingsRepository: FollowingsRepository,
private queueService: QueueService,

Expand Down Expand Up @@ -105,6 +105,13 @@ class DeliverManager {
*/
@bindThis
public async execute(): Promise<void> {
//#region MIGRATION
/**
* ed25519の署名がなければ追加する
*/
await this.userKeypairService.prepareEd25519KeyPair(this.actor.id);
//#endregion

// The value flags whether it is shared or not.
// key: inbox URL, value: whether it is sharedInbox
const inboxes = new Map<string, boolean>();
Expand Down Expand Up @@ -154,7 +161,7 @@ export class ApDeliverManagerService {
@Inject(DI.followingsRepository)
private followingsRepository: FollowingsRepository,

private userEntityService: UserEntityService,
private userKeypairService: UserKeypairService,
private queueService: QueueService,
) {
}
Expand All @@ -167,7 +174,7 @@ export class ApDeliverManagerService {
@bindThis
public async deliverToFollowers(actor: { id: MiLocalUser['id']; host: null; }, activity: IActivity): Promise<void> {
const manager = new DeliverManager(
this.userEntityService,
this.userKeypairService,
this.followingsRepository,
this.queueService,
actor,
Expand All @@ -186,7 +193,7 @@ export class ApDeliverManagerService {
@bindThis
public async deliverToUser(actor: { id: MiLocalUser['id']; host: null; }, activity: IActivity, to: MiRemoteUser): Promise<void> {
const manager = new DeliverManager(
this.userEntityService,
this.userKeypairService,
this.followingsRepository,
this.queueService,
actor,
Expand All @@ -199,7 +206,7 @@ export class ApDeliverManagerService {
@bindThis
public createDeliverManager(actor: { id: MiUser['id']; host: null; }, activity: IActivity | null): DeliverManager {
return new DeliverManager(
this.userEntityService,
this.userKeypairService,
this.followingsRepository,
this.queueService,

Expand Down
Loading
Loading