From 9edd0d25c2022b7a84174425bc7c71dc7018f9d2 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Fri, 24 Feb 2023 06:37:22 +0100 Subject: Pass `--detectOpenHandles` to Jest (#9895) Co-authored-by: tamaina --- packages/backend/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/backend') diff --git a/packages/backend/package.json b/packages/backend/package.json index 2e8161308b..c5cddac9de 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -15,8 +15,8 @@ "typecheck": "tsc --noEmit", "eslint": "eslint --quiet \"src/**/*.ts\"", "lint": "pnpm typecheck && pnpm eslint", - "jest": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --runInBand", - "jest-and-coverage": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit --runInBand", + "jest": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --runInBand --detectOpenHandles", + "jest-and-coverage": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit --runInBand --detectOpenHandles", "jest-clear": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --clearCache", "test": "pnpm jest", "test-and-coverage": "pnpm jest-and-coverage" -- cgit v1.3.1-freya 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 ++++++++++------------ packages/backend/test/tests/ap-request.ts | 55 ----------------- packages/backend/test/tsconfig.json | 3 +- packages/backend/test/unit/ap-request.ts | 56 +++++++++++++++++ 4 files changed, 92 insertions(+), 94 deletions(-) delete mode 100644 packages/backend/test/tests/ap-request.ts create mode 100644 packages/backend/test/unit/ap-request.ts (limited to 'packages/backend') 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`, diff --git a/packages/backend/test/tests/ap-request.ts b/packages/backend/test/tests/ap-request.ts deleted file mode 100644 index 8c586861ad..0000000000 --- a/packages/backend/test/tests/ap-request.ts +++ /dev/null @@ -1,55 +0,0 @@ -import * as assert from 'assert'; -import httpSignature from '@peertube/http-signature'; -import { genRsaKeyPair } from '../../src/misc/gen-key-pair.js'; -import { createSignedPost, createSignedGet } from '../../src/activitypub/ap-request.js'; - -export const buildParsedSignature = (signingString: string, signature: string, algorithm: string) => { - return { - scheme: 'Signature', - params: { - keyId: 'KeyID', // dummy, not used for verify - algorithm: algorithm, - headers: [ '(request-target)', 'date', 'host', 'digest' ], // dummy, not used for verify - signature: signature, - }, - signingString: signingString, - algorithm: algorithm.toUpperCase(), - keyId: 'KeyID', // dummy, not used for verify - }; -}; - -describe('ap-request', () => { - test('createSignedPost with verify', async () => { - const keypair = await genRsaKeyPair(); - const key = { keyId: 'x', 'privateKeyPem': keypair.privateKey }; - const url = 'https://example.com/inbox'; - const activity = { a: 1 }; - const body = JSON.stringify(activity); - const headers = { - 'User-Agent': 'UA', - }; - - const req = createSignedPost({ key, url, body, additionalHeaders: headers }); - - const parsed = buildParsedSignature(req.signingString, req.signature, 'rsa-sha256'); - - const result = httpSignature.verifySignature(parsed, keypair.publicKey); - assert.deepStrictEqual(result, true); - }); - - test('createSignedGet with verify', async () => { - const keypair = await genRsaKeyPair(); - const key = { keyId: 'x', 'privateKeyPem': keypair.privateKey }; - const url = 'https://example.com/outbox'; - const headers = { - 'User-Agent': 'UA', - }; - - const req = createSignedGet({ key, url, additionalHeaders: headers }); - - const parsed = buildParsedSignature(req.signingString, req.signature, 'rsa-sha256'); - - const result = httpSignature.verifySignature(parsed, keypair.publicKey); - assert.deepStrictEqual(result, true); - }); -}); diff --git a/packages/backend/test/tsconfig.json b/packages/backend/test/tsconfig.json index 5d91d0923a..da82ddc4a1 100644 --- a/packages/backend/test/tsconfig.json +++ b/packages/backend/test/tsconfig.json @@ -37,6 +37,7 @@ }, "compileOnSave": false, "include": [ - "./**/*.ts" + "./**/*.ts", + "../src/@types/**/*.ts", ] } diff --git a/packages/backend/test/unit/ap-request.ts b/packages/backend/test/unit/ap-request.ts new file mode 100644 index 0000000000..98f352e1c6 --- /dev/null +++ b/packages/backend/test/unit/ap-request.ts @@ -0,0 +1,56 @@ +import * as assert from 'assert'; +import httpSignature from '@peertube/http-signature'; + +import { genRsaKeyPair } from '@/misc/gen-key-pair.js'; +import { ApRequestCreator } from '@/core/activitypub/ApRequestService.js'; + +export const buildParsedSignature = (signingString: string, signature: string, algorithm: string) => { + return { + scheme: 'Signature', + params: { + keyId: 'KeyID', // dummy, not used for verify + algorithm: algorithm, + headers: ['(request-target)', 'date', 'host', 'digest'], // dummy, not used for verify + signature: signature, + }, + signingString: signingString, + algorithm: algorithm.toUpperCase(), + keyId: 'KeyID', // dummy, not used for verify + }; +}; + +describe('ap-request', () => { + test('createSignedPost with verify', async () => { + const keypair = await genRsaKeyPair(); + const key = { keyId: 'x', 'privateKeyPem': keypair.privateKey }; + const url = 'https://example.com/inbox'; + const activity = { a: 1 }; + const body = JSON.stringify(activity); + const headers = { + 'User-Agent': 'UA', + }; + + const req = ApRequestCreator.createSignedPost({ key, url, body, additionalHeaders: headers }); + + const parsed = buildParsedSignature(req.signingString, req.signature, 'rsa-sha256'); + + const result = httpSignature.verifySignature(parsed, keypair.publicKey); + assert.deepStrictEqual(result, true); + }); + + test('createSignedGet with verify', async () => { + const keypair = await genRsaKeyPair(); + const key = { keyId: 'x', 'privateKeyPem': keypair.privateKey }; + const url = 'https://example.com/outbox'; + const headers = { + 'User-Agent': 'UA', + }; + + const req = ApRequestCreator.createSignedGet({ key, url, additionalHeaders: headers }); + + const parsed = buildParsedSignature(req.signingString, req.signature, 'rsa-sha256'); + + const result = httpSignature.verifySignature(parsed, keypair.publicKey); + assert.deepStrictEqual(result, true); + }); +}); -- cgit v1.3.1-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') 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.3.1-freya