From d1d3b48e5164c2335e892d2ac0f520f066d4734b Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Fri, 24 Feb 2023 08:10:48 +0100 Subject: test(backend): restore ap-request tests (#9997) Co-authored-by: tamaina --- .../src/core/activitypub/ApRequestService.ts | 72 ++++++++++------------ 1 file changed, 34 insertions(+), 38 deletions(-) (limited to 'packages/backend/src') diff --git a/packages/backend/src/core/activitypub/ApRequestService.ts b/packages/backend/src/core/activitypub/ApRequestService.ts index bfd53dfabf..71fbc29476 100644 --- a/packages/backend/src/core/activitypub/ApRequestService.ts +++ b/packages/backend/src/core/activitypub/ApRequestService.ts @@ -28,31 +28,15 @@ type PrivateKey = { keyId: string; }; -@Injectable() -export class ApRequestService { - private logger: Logger; - - constructor( - @Inject(DI.config) - private config: Config, - - private userKeypairStoreService: UserKeypairStoreService, - private httpRequestService: HttpRequestService, - private loggerService: LoggerService, - ) { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - this.logger = this.loggerService?.getLogger('ap-request'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる - } - - @bindThis - private createSignedPost(args: { key: PrivateKey, url: string, body: string, additionalHeaders: Record }): Signed { +export class ApRequestCreator { + static createSignedPost(args: { key: PrivateKey, url: string, body: string, additionalHeaders: Record }): Signed { const u = new URL(args.url); const digestHeader = `SHA-256=${crypto.createHash('sha256').update(args.body).digest('base64')}`; const request: Request = { url: u.href, method: 'POST', - headers: this.objectAssignWithLcKey({ + headers: this.#objectAssignWithLcKey({ 'Date': new Date().toUTCString(), 'Host': u.host, 'Content-Type': 'application/activity+json', @@ -60,7 +44,7 @@ export class ApRequestService { }, args.additionalHeaders), }; - const result = this.signToRequest(request, args.key, ['(request-target)', 'date', 'host', 'digest']); + const result = this.#signToRequest(request, args.key, ['(request-target)', 'date', 'host', 'digest']); return { request, @@ -70,21 +54,20 @@ export class ApRequestService { }; } - @bindThis - private createSignedGet(args: { key: PrivateKey, url: string, additionalHeaders: Record }): Signed { + static createSignedGet(args: { key: PrivateKey, url: string, additionalHeaders: Record }): Signed { const u = new URL(args.url); const request: Request = { url: u.href, method: 'GET', - headers: this.objectAssignWithLcKey({ + headers: this.#objectAssignWithLcKey({ 'Accept': 'application/activity+json, application/ld+json', 'Date': new Date().toUTCString(), 'Host': new URL(args.url).host, }, args.additionalHeaders), }; - const result = this.signToRequest(request, args.key, ['(request-target)', 'date', 'host', 'accept']); + const result = this.#signToRequest(request, args.key, ['(request-target)', 'date', 'host', 'accept']); return { request, @@ -94,13 +77,12 @@ export class ApRequestService { }; } - @bindThis - private signToRequest(request: Request, key: PrivateKey, includeHeaders: string[]): Signed { - const signingString = this.genSigningString(request, includeHeaders); + static #signToRequest(request: Request, key: PrivateKey, includeHeaders: string[]): Signed { + const signingString = this.#genSigningString(request, includeHeaders); const signature = crypto.sign('sha256', Buffer.from(signingString), key.privateKeyPem).toString('base64'); const signatureHeader = `keyId="${key.keyId}",algorithm="rsa-sha256",headers="${includeHeaders.join(' ')}",signature="${signature}"`; - request.headers = this.objectAssignWithLcKey(request.headers, { + request.headers = this.#objectAssignWithLcKey(request.headers, { Signature: signatureHeader, }); // node-fetch will generate this for us. if we keep 'Host', it won't change with redirects! @@ -114,9 +96,8 @@ export class ApRequestService { }; } - @bindThis - private genSigningString(request: Request, includeHeaders: string[]): string { - request.headers = this.lcObjectKey(request.headers); + static #genSigningString(request: Request, includeHeaders: string[]): string { + request.headers = this.#lcObjectKey(request.headers); const results: string[] = []; @@ -131,16 +112,31 @@ export class ApRequestService { return results.join('\n'); } - @bindThis - private lcObjectKey(src: Record): Record { + static #lcObjectKey(src: Record): Record { const dst: Record = {}; for (const key of Object.keys(src).filter(x => x !== '__proto__' && typeof src[x] === 'string')) dst[key.toLowerCase()] = src[key]; return dst; } - @bindThis - private objectAssignWithLcKey(a: Record, b: Record): Record { - return Object.assign(this.lcObjectKey(a), this.lcObjectKey(b)); + static #objectAssignWithLcKey(a: Record, b: Record): Record { + return Object.assign(this.#lcObjectKey(a), this.#lcObjectKey(b)); + } +} + +@Injectable() +export class ApRequestService { + private logger: Logger; + + constructor( + @Inject(DI.config) + private config: Config, + + private userKeypairStoreService: UserKeypairStoreService, + private httpRequestService: HttpRequestService, + private loggerService: LoggerService, + ) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + this.logger = this.loggerService?.getLogger('ap-request'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる } @bindThis @@ -149,7 +145,7 @@ export class ApRequestService { const keypair = await this.userKeypairStoreService.getUserKeypair(user.id); - const req = this.createSignedPost({ + const req = ApRequestCreator.createSignedPost({ key: { privateKeyPem: keypair.privateKey, keyId: `${this.config.url}/users/${user.id}#main-key`, @@ -176,7 +172,7 @@ export class ApRequestService { public async signedGet(url: string, user: { id: User['id'] }) { const keypair = await this.userKeypairStoreService.getUserKeypair(user.id); - const req = this.createSignedGet({ + const req = ApRequestCreator.createSignedGet({ key: { privateKeyPem: keypair.privateKey, keyId: `${this.config.url}/users/${user.id}#main-key`, -- cgit v1.2.3-freya From e4336f5b7657e2f5c40c7e7c71232a6653738574 Mon Sep 17 00:00:00 2001 From: tamaina Date: Fri, 24 Feb 2023 16:32:01 +0900 Subject: fix(server): notes/createで、fileIdsと見つかったファイルの数が異なる場合はエラーにする (#9911) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(server): notes/createで、fileIdsと見つかったファイルの数が異なる場合はエラーにする * NO_SUCH_FILE --- packages/backend/src/server/api/endpoints/notes/create.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'packages/backend/src') diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts index 593444968e..f4c5a84a4f 100644 --- a/packages/backend/src/server/api/endpoints/notes/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/create.ts @@ -79,6 +79,12 @@ export const meta = { code: 'YOU_HAVE_BEEN_BLOCKED', id: 'b390d7e1-8a5e-46ed-b625-06271cafd3d3', }, + + noSuchFile: { + message: 'Some files are not found.', + code: 'NO_SUCH_FILE', + id: 'b6992544-63e7-67f0-fa7f-32444b1b5306', + }, }, } as const; @@ -207,6 +213,10 @@ export default class extends Endpoint { .orderBy('array_position(ARRAY[:...fileIds], "id"::text)') .setParameters({ fileIds }) .getMany(); + + if (files.length !== fileIds.length) { + throw new ApiError(meta.errors.noSuchFile); + } } let renote: Note | null = null; -- cgit v1.2.3-freya From 0ec5327474d7bf6f16ad5219e928e510e899d517 Mon Sep 17 00:00:00 2001 From: xianon Date: Sat, 25 Feb 2023 04:27:37 +0900 Subject: 未知のユーザーが deleteActor されたら処理をスキップする (#10067) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/core/activitypub/ApInboxService.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'packages/backend/src') diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index 21d2d16ed8..6d9569bce2 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -450,8 +450,10 @@ export class ApInboxService { return `skip: delete actor ${actor.uri} !== ${uri}`; } - const user = await this.usersRepository.findOneByOrFail({ id: actor.id }); - if (user.isDeleted) { + const user = await this.usersRepository.findOneBy({ id: actor.id }); + if (user == null) { + return 'skip: actor not found'; + } else if (user.isDeleted) { return 'skip: already deleted'; } -- cgit v1.2.3-freya From 8b30c0c0cd8087337f6db7e9fd7fa267d68baebe Mon Sep 17 00:00:00 2001 From: tamaina Date: Sat, 25 Feb 2023 05:22:09 +0900 Subject: fix(client): Android ChromeでPWAとしてインストールできない問題を修正 (#10069) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(client): Android ChromeでPWAとしてインストールできない問題を修正 * 順番関係ある? --- packages/backend/src/server/web/manifest.json | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'packages/backend/src') diff --git a/packages/backend/src/server/web/manifest.json b/packages/backend/src/server/web/manifest.json index f8b77cbd93..41171d62a1 100644 --- a/packages/backend/src/server/web/manifest.json +++ b/packages/backend/src/server/web/manifest.json @@ -17,10 +17,18 @@ "sizes": "512x512", "type": "image/png", "purpose": "maskable" + }, + { + "src": "/static-assets/splash.png", + "sizes": "300x300", + "type": "image/png", + "purpose": "any" } ], "share_target": { "action": "/share/", + "method": "GET", + "enctype": "application/x-www-form-urlencoded", "params": { "title": "title", "text": "text", -- cgit v1.2.3-freya From ea04778649f24719c40ff40f16438175f62da534 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 25 Feb 2023 18:26:35 +0900 Subject: feat: in-channel featured note Resolve #9938 --- CHANGELOG.md | 1 + .../src/server/api/endpoints/notes/featured.ts | 3 ++ packages/frontend/src/pages/channel.vue | 36 +++++++++++++++------- 3 files changed, 29 insertions(+), 11 deletions(-) (limited to 'packages/backend/src') diff --git a/CHANGELOG.md b/CHANGELOG.md index d885c47ca0..489fcff2cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ You should also include the user name that made the change. ## 13.x.x (unreleased) ### Improvements +- チャンネル内ハイライト - renoteした際の表示を改善 - バックグラウンドで一定時間経過したらページネーションのアイテム更新をしない - enhance(client): MkUrlPreviewの閉じるボタンを見やすく diff --git a/packages/backend/src/server/api/endpoints/notes/featured.ts b/packages/backend/src/server/api/endpoints/notes/featured.ts index 26f69373d1..cf939f6631 100644 --- a/packages/backend/src/server/api/endpoints/notes/featured.ts +++ b/packages/backend/src/server/api/endpoints/notes/featured.ts @@ -28,6 +28,7 @@ export const paramDef = { properties: { limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, offset: { type: 'integer', default: 0 }, + channelId: { type: 'string', nullable: true, format: 'misskey:id' }, }, required: [], } as const; @@ -63,6 +64,8 @@ export default class extends Endpoint { .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); + if (ps.channelId) query.andWhere('note.channelId = :channelId', { channelId: ps.channelId }); + if (me) this.queryService.generateMutedUserQuery(query, me); if (me) this.queryService.generateBlockedUserQuery(query, me); diff --git a/packages/frontend/src/pages/channel.vue b/packages/frontend/src/pages/channel.vue index f59b7d7f90..6b4fcb32f8 100644 --- a/packages/frontend/src/pages/channel.vue +++ b/packages/frontend/src/pages/channel.vue @@ -1,9 +1,9 @@