Merge branch 'develop' into schedule-note

This commit is contained in:
かっこかり 2023-11-14 22:18:00 +09:00 committed by GitHub
commit cb00b236d2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 1471 additions and 1062 deletions

View file

@ -59,7 +59,6 @@
"dependencies": {
"@aws-sdk/client-s3": "3.412.0",
"@aws-sdk/lib-storage": "3.412.0",
"@smithy/node-http-handler": "2.1.5",
"@bull-board/api": "5.9.1",
"@bull-board/fastify": "5.9.1",
"@bull-board/ui": "5.9.1",
@ -68,7 +67,7 @@
"@fastify/cookie": "9.1.0",
"@fastify/cors": "8.4.1",
"@fastify/express": "2.3.0",
"@fastify/http-proxy": "9.2.1",
"@fastify/http-proxy": "9.3.0",
"@fastify/multipart": "8.0.0",
"@fastify/static": "6.12.0",
"@fastify/view": "8.2.0",
@ -78,8 +77,9 @@
"@peertube/http-signature": "1.7.0",
"@simplewebauthn/server": "8.3.5",
"@sinonjs/fake-timers": "11.2.2",
"@smithy/node-http-handler": "2.1.5",
"@swc/cli": "0.1.62",
"@swc/core": "1.3.95",
"@swc/core": "1.3.96",
"accepts": "1.3.8",
"ajv": "8.12.0",
"archiver": "6.0.1",
@ -87,7 +87,7 @@
"bcryptjs": "2.4.3",
"blurhash": "2.0.5",
"body-parser": "1.20.2",
"bullmq": "4.12.8",
"bullmq": "4.13.2",
"cacheable-lookup": "7.0.0",
"cbor": "9.0.1",
"chalk": "5.3.0",
@ -99,8 +99,9 @@
"date-fns": "2.30.0",
"deep-email-validator": "0.1.21",
"fastify": "4.24.3",
"fastify-raw-body": "^4.2.2",
"feed": "4.2.2",
"file-type": "18.6.0",
"file-type": "18.7.0",
"fluent-ffmpeg": "2.1.2",
"form-data": "4.0.0",
"got": "13.0.0",
@ -122,7 +123,7 @@
"mime-types": "2.1.35",
"misskey-js": "workspace:*",
"ms": "3.0.0-canary.1",
"nanoid": "5.0.2",
"nanoid": "5.0.3",
"nested-property": "4.0.0",
"node-fetch": "3.3.2",
"nodemailer": "6.9.7",
@ -156,7 +157,7 @@
"strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0",
"summaly": "github:misskey-dev/summaly",
"systeminformation": "5.21.15",
"systeminformation": "5.21.17",
"tinycolor2": "1.6.0",
"tmp": "0.2.1",
"tsc-alias": "1.8.8",
@ -174,50 +175,50 @@
"@jest/globals": "29.7.0",
"@simplewebauthn/typescript-types": "8.3.4",
"@swc/jest": "0.2.29",
"@types/accepts": "1.3.6",
"@types/archiver": "6.0.0",
"@types/bcryptjs": "2.4.5",
"@types/body-parser": "1.19.4",
"@types/accepts": "1.3.7",
"@types/archiver": "6.0.1",
"@types/bcryptjs": "2.4.6",
"@types/body-parser": "1.19.5",
"@types/cbor": "6.0.0",
"@types/color-convert": "2.0.2",
"@types/content-disposition": "0.5.7",
"@types/fluent-ffmpeg": "2.1.23",
"@types/http-link-header": "1.0.4",
"@types/jest": "29.5.7",
"@types/js-yaml": "4.0.8",
"@types/jsdom": "21.1.4",
"@types/jsonld": "1.5.11",
"@types/jsrsasign": "10.5.11",
"@types/mime-types": "2.1.3",
"@types/ms": "0.7.33",
"@types/node": "20.8.10",
"@types/color-convert": "2.0.3",
"@types/content-disposition": "0.5.8",
"@types/fluent-ffmpeg": "2.1.24",
"@types/http-link-header": "1.0.5",
"@types/jest": "29.5.8",
"@types/js-yaml": "4.0.9",
"@types/jsdom": "21.1.5",
"@types/jsonld": "1.5.12",
"@types/jsrsasign": "10.5.12",
"@types/mime-types": "2.1.4",
"@types/ms": "0.7.34",
"@types/node": "20.9.0",
"@types/node-fetch": "3.0.3",
"@types/nodemailer": "6.4.13",
"@types/oauth": "0.9.3",
"@types/oauth2orize": "1.11.2",
"@types/oauth2orize-pkce": "0.1.1",
"@types/pg": "8.10.7",
"@types/pug": "2.0.8",
"@types/punycode": "2.1.1",
"@types/qrcode": "1.5.4",
"@types/random-seed": "0.3.4",
"@types/ratelimiter": "3.4.5",
"@types/rename": "1.0.6",
"@types/sanitize-html": "2.9.3",
"@types/semver": "7.5.4",
"@types/nodemailer": "6.4.14",
"@types/oauth": "0.9.4",
"@types/oauth2orize": "1.11.3",
"@types/oauth2orize-pkce": "0.1.2",
"@types/pg": "8.10.9",
"@types/pug": "2.0.9",
"@types/punycode": "2.1.2",
"@types/qrcode": "1.5.5",
"@types/random-seed": "0.3.5",
"@types/ratelimiter": "3.4.6",
"@types/rename": "1.0.7",
"@types/sanitize-html": "2.9.4",
"@types/semver": "7.5.5",
"@types/sharp": "0.32.0",
"@types/simple-oauth2": "5.0.6",
"@types/sinonjs__fake-timers": "8.1.4",
"@types/tinycolor2": "1.4.5",
"@types/tmp": "0.2.5",
"@types/vary": "1.1.2",
"@types/web-push": "3.6.2",
"@types/ws": "8.5.8",
"@typescript-eslint/eslint-plugin": "6.9.1",
"@typescript-eslint/parser": "6.9.1",
"@types/simple-oauth2": "5.0.7",
"@types/sinonjs__fake-timers": "8.1.5",
"@types/tinycolor2": "1.4.6",
"@types/tmp": "0.2.6",
"@types/vary": "1.1.3",
"@types/web-push": "3.6.3",
"@types/ws": "8.5.9",
"@typescript-eslint/eslint-plugin": "6.11.0",
"@typescript-eslint/parser": "6.11.0",
"aws-sdk-client-mock": "3.0.0",
"cross-env": "7.0.3",
"eslint": "8.52.0",
"eslint": "8.53.0",
"eslint-plugin-import": "2.29.0",
"execa": "8.0.1",
"jest": "29.7.0",

View file

@ -3,6 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import * as crypto from 'node:crypto';
import { IncomingMessage } from 'node:http';
import { Inject, Injectable } from '@nestjs/common';
import fastifyAccepts from '@fastify/accepts';
@ -108,7 +109,58 @@ export class ActivityPubServerService {
return;
}
// TODO: request.bodyのバリデーション
if (signature.params.headers.indexOf('host') === -1
|| request.headers.host !== this.config.host) {
// Host not specified or not match.
reply.code(401);
return;
}
if (signature.params.headers.indexOf('digest') === -1) {
// Digest not found.
reply.code(401);
} else {
const digest = request.headers.digest;
if (typeof digest !== 'string') {
// Huh?
reply.code(401);
return;
}
const re = /^([a-zA-Z0-9\-]+)=(.+)$/;
const match = digest.match(re);
if (match == null) {
// Invalid digest
reply.code(401);
return;
}
const algo = match[1];
const digestValue = match[2];
if (algo !== 'SHA-256') {
// Unsupported digest algorithm
reply.code(401);
return;
}
if (request.rawBody == null) {
// Bad request
reply.code(400);
return;
}
const hash = crypto.createHash('sha256').update(request.rawBody).digest('base64');
if (hash !== digestValue) {
// Invalid digest
reply.code(401);
return;
}
}
this.queueService.inbox(request.body as IActivity, signature);
reply.code(202);
@ -474,8 +526,8 @@ export class ActivityPubServerService {
//#region Routing
// inbox (limit: 64kb)
fastify.post('/inbox', { bodyLimit: 1024 * 64 }, async (request, reply) => await this.inbox(request, reply));
fastify.post('/users/:user/inbox', { bodyLimit: 1024 * 64 }, async (request, reply) => await this.inbox(request, reply));
fastify.post('/inbox', { config: { rawBody: true }, bodyLimit: 1024 * 64 }, async (request, reply) => await this.inbox(request, reply));
fastify.post('/users/:user/inbox', { config: { rawBody: true }, bodyLimit: 1024 * 64 }, async (request, reply) => await this.inbox(request, reply));
// note
fastify.get<{ Params: { note: string; } }>('/notes/:note', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => {

View file

@ -9,6 +9,7 @@ import { fileURLToPath } from 'node:url';
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
import Fastify, { FastifyInstance } from 'fastify';
import fastifyStatic from '@fastify/static';
import fastifyRawBody from 'fastify-raw-body';
import { IsNull } from 'typeorm';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import type { Config } from '@/config.js';
@ -86,6 +87,13 @@ export class ServerService implements OnApplicationShutdown {
});
}
// Register raw-body parser for ActivityPub HTTP signature validation.
fastify.register(fastifyRawBody, {
global: false,
encoding: 'utf-8',
runFirst: true,
});
// Register non-serving static server so that the child services can use reply.sendFile.
// `root` here is just a placeholder and each call must use its own `rootPath`.
fastify.register(fastifyStatic, {

View file

@ -10,6 +10,7 @@ import * as ep___admin_meta from './endpoints/admin/meta.js';
import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js';
import * as ep___admin_accounts_create from './endpoints/admin/accounts/create.js';
import * as ep___admin_accounts_delete from './endpoints/admin/accounts/delete.js';
import * as ep___admin_accounts_findByEmail from './endpoints/admin/accounts/find-by-email.js';
import * as ep___admin_ad_create from './endpoints/admin/ad/create.js';
import * as ep___admin_ad_delete from './endpoints/admin/ad/delete.js';
import * as ep___admin_ad_list from './endpoints/admin/ad/list.js';
@ -370,6 +371,7 @@ const $admin_meta: Provider = { provide: 'ep:admin/meta', useClass: ep___admin_m
const $admin_abuseUserReports: Provider = { provide: 'ep:admin/abuse-user-reports', useClass: ep___admin_abuseUserReports.default };
const $admin_accounts_create: Provider = { provide: 'ep:admin/accounts/create', useClass: ep___admin_accounts_create.default };
const $admin_accounts_delete: Provider = { provide: 'ep:admin/accounts/delete', useClass: ep___admin_accounts_delete.default };
const $admin_accounts_findByEmail: Provider = { provide: 'ep:admin/accounts/find-by-email', useClass: ep___admin_accounts_findByEmail.default };
const $admin_ad_create: Provider = { provide: 'ep:admin/ad/create', useClass: ep___admin_ad_create.default };
const $admin_ad_delete: Provider = { provide: 'ep:admin/ad/delete', useClass: ep___admin_ad_delete.default };
const $admin_ad_list: Provider = { provide: 'ep:admin/ad/list', useClass: ep___admin_ad_list.default };
@ -734,6 +736,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$admin_abuseUserReports,
$admin_accounts_create,
$admin_accounts_delete,
$admin_accounts_findByEmail,
$admin_ad_create,
$admin_ad_delete,
$admin_ad_list,
@ -1092,6 +1095,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$admin_abuseUserReports,
$admin_accounts_create,
$admin_accounts_delete,
$admin_accounts_findByEmail,
$admin_ad_create,
$admin_ad_delete,
$admin_ad_list,

View file

@ -10,6 +10,7 @@ import * as ep___admin_meta from './endpoints/admin/meta.js';
import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js';
import * as ep___admin_accounts_create from './endpoints/admin/accounts/create.js';
import * as ep___admin_accounts_delete from './endpoints/admin/accounts/delete.js';
import * as ep___admin_accounts_findByEmail from './endpoints/admin/accounts/find-by-email.js';
import * as ep___admin_ad_create from './endpoints/admin/ad/create.js';
import * as ep___admin_ad_delete from './endpoints/admin/ad/delete.js';
import * as ep___admin_ad_list from './endpoints/admin/ad/list.js';
@ -368,6 +369,7 @@ const eps = [
['admin/abuse-user-reports', ep___admin_abuseUserReports],
['admin/accounts/create', ep___admin_accounts_create],
['admin/accounts/delete', ep___admin_accounts_delete],
['admin/accounts/find-by-email', ep___admin_accounts_findByEmail],
['admin/ad/create', ep___admin_ad_create],
['admin/ad/delete', ep___admin_ad_delete],
['admin/ad/list', ep___admin_ad_list],

View file

@ -0,0 +1,61 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { UserProfilesRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { ApiError } from '@/server/api/error.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireAdmin: true,
errors: {
userNotFound: {
message: 'No such user who has the email address.',
code: 'USER_NOT_FOUND',
id: 'cb865949-8af5-4062-a88c-ef55e8786d1d',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
email: { type: 'string' },
},
required: ['email'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
@Inject(DI.userProfilesRepository)
private userProfilesRepository: UserProfilesRepository,
private userEntityService: UserEntityService,
) {
super(meta, paramDef, async (ps, me) => {
const profile = await this.userProfilesRepository.findOne({
where: { email: ps.email },
relations: ['user'],
});
if (profile == null) {
throw new ApiError(meta.errors.userNotFound);
}
const res = await this.userEntityService.pack(profile.user!, null, {
detail: true,
});
return res;
});
}
}