1
0
mirror of https://github.com/misskey-dev/misskey.git synced 2026-05-22 08:14:07 +02:00

perf: rsa sign on slacc (#17322)

* perf: rsa sign on slacc

* fix: missing async/await

* fix: threadPoolSize is always number

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* test(backend): init slacc in unit setup and await ap-request signing

* test(backend): move slacc init to unit testEnvironment

* test(backend): delete unused file

* docs: update CHANGELOG

* docs: fix indent

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* chore: migrate to vitest

* fix

* fix: fix changelog

* chore: regenerate lockfile

* docs: changelog

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com>
This commit is contained in:
Acid Chicken
2026-05-12 17:36:49 +09:00
committed by GitHub
parent a19da1258d
commit b950f905e5
18 changed files with 201 additions and 130 deletions

View File

@@ -37,19 +37,19 @@
"@tensorflow/tfjs": "4.22.0",
"@tensorflow/tfjs-node": "4.22.0",
"bufferutil": "4.1.0",
"slacc-android-arm-eabi": "0.0.10",
"slacc-android-arm64": "0.0.10",
"slacc-darwin-arm64": "0.0.10",
"slacc-darwin-universal": "0.0.10",
"slacc-darwin-x64": "0.0.10",
"slacc-freebsd-x64": "0.0.10",
"slacc-linux-arm-gnueabihf": "0.0.10",
"slacc-linux-arm64-gnu": "0.0.10",
"slacc-linux-arm64-musl": "0.0.10",
"slacc-linux-x64-gnu": "0.0.10",
"slacc-linux-x64-musl": "0.0.10",
"slacc-win32-arm64-msvc": "0.0.10",
"slacc-win32-x64-msvc": "0.0.10",
"slacc-android-arm-eabi": "0.1.5",
"slacc-android-arm64": "0.1.5",
"slacc-darwin-arm64": "0.1.5",
"slacc-darwin-universal": "0.1.5",
"slacc-darwin-x64": "0.1.5",
"slacc-freebsd-x64": "0.1.5",
"slacc-linux-arm-gnueabihf": "0.1.5",
"slacc-linux-arm64-gnu": "0.1.5",
"slacc-linux-arm64-musl": "0.1.5",
"slacc-linux-x64-gnu": "0.1.5",
"slacc-linux-x64-musl": "0.1.5",
"slacc-win32-arm64-msvc": "0.1.5",
"slacc-win32-x64-msvc": "0.1.5",
"utf-8-validate": "6.0.6"
},
"dependencies": {
@@ -142,7 +142,7 @@
"secure-json-parse": "4.1.0",
"semver": "7.7.4",
"sharp": "0.33.5",
"slacc": "0.0.10",
"slacc": "0.1.5",
"strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0",
"systeminformation": "5.31.5",

View File

@@ -4,7 +4,21 @@
*/
import { NestFactory } from '@nestjs/core';
import { init } from 'slacc';
import { NestLogger } from '@/NestLogger.js';
import type { Config } from '@/config.js';
let slaccInitialized = false;
export function initExtraThreadPool(config: Config) {
if (slaccInitialized) return;
const threadPoolSize = Math.max(config.threadPoolSize ?? 1, 1);
init(threadPoolSize);
slaccInitialized = true;
}
export async function server() {
const { MainModule } = await import('../MainModule.js');

View File

@@ -13,7 +13,7 @@ import { loadConfig } from '@/config.js';
import type { Config } from '@/config.js';
import { showMachineInfo } from '@/misc/show-machine-info.js';
import { envOption } from '@/env.js';
import { jobQueue, server } from './common.js';
import { initExtraThreadPool, jobQueue, server } from './common.js';
const logger = new Logger('core', 'cyan');
const bootLogger = logger.createSubLogger('boot', 'magenta');
@@ -64,6 +64,8 @@ export async function masterMain() {
bootLogger.succ('Misskey initialized');
initExtraThreadPool(config);
if (config.sentryForBackend) {
const Sentry = await import('@sentry/node');
const { nodeProfilingIntegration } = await import('@sentry/profiling-node');

View File

@@ -6,7 +6,7 @@
import cluster from 'node:cluster';
import { envOption } from '@/env.js';
import { loadConfig } from '@/config.js';
import { jobQueue, server } from './common.js';
import { initExtraThreadPool, jobQueue, server } from './common.js';
/**
* Init worker process
@@ -14,6 +14,8 @@ import { jobQueue, server } from './common.js';
export async function workerMain() {
const config = loadConfig();
initExtraThreadPool(config);
if (config.sentryForBackend) {
const Sentry = await import('@sentry/node');
const { nodeProfilingIntegration } = await import('@sentry/profiling-node');

View File

@@ -85,6 +85,7 @@ type Source = {
maxFileSize?: number;
clusterLimit?: number;
threadPoolSize?: number;
id: string;
@@ -158,6 +159,7 @@ export type Config = {
allowedPrivateNetworks: string[] | undefined;
maxFileSize: number;
clusterLimit: number | undefined;
threadPoolSize: number;
id: string;
outgoingAddress: string | undefined;
outgoingAddressFamily: 'ipv4' | 'ipv6' | 'dual' | undefined;
@@ -313,6 +315,7 @@ export function loadConfig(): Config {
allowedPrivateNetworks: config.allowedPrivateNetworks,
maxFileSize: config.maxFileSize ?? 262144000,
clusterLimit: config.clusterLimit,
threadPoolSize: config.threadPoolSize ?? 1,
outgoingAddress: config.outgoingAddress,
outgoingAddressFamily: config.outgoingAddressFamily,
deliverJobConcurrency: config.deliverJobConcurrency,

View File

@@ -5,8 +5,10 @@
import * as crypto from 'node:crypto';
import { URL } from 'node:url';
import { promisify } from 'node:util';
import { Inject, Injectable } from '@nestjs/common';
import * as htmlParser from 'node-html-parser';
import { RsaKeyPair } from 'slacc';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import type { MiUser } from '@/models/User.js';
@@ -39,7 +41,7 @@ type PrivateKey = {
};
export class ApRequestCreator {
static createSignedPost(args: { key: PrivateKey, url: string, body: string, digest?: string, additionalHeaders: Record<string, string> }): Signed {
static async createSignedPost(args: { key: PrivateKey, url: string, body: string, digest?: string, additionalHeaders: Record<string, string> }): Promise<Signed> {
const u = new URL(args.url);
const digestHeader = args.digest ?? this.createDigest(args.body);
@@ -54,7 +56,7 @@ export class ApRequestCreator {
}, args.additionalHeaders),
};
const result = this.#signToRequest(request, args.key, ['(request-target)', 'date', 'host', 'digest']);
const result = await this.#signToRequest(request, args.key, ['(request-target)', 'date', 'host', 'digest']);
return {
request,
@@ -68,7 +70,7 @@ export class ApRequestCreator {
return `SHA-256=${crypto.createHash('sha256').update(body).digest('base64')}`;
}
static createSignedGet(args: { key: PrivateKey, url: string, additionalHeaders: Record<string, string> }): Signed {
static async createSignedGet(args: { key: PrivateKey, url: string, additionalHeaders: Record<string, string> }): Promise<Signed> {
const u = new URL(args.url);
const request: Request = {
@@ -81,7 +83,7 @@ export class ApRequestCreator {
}, args.additionalHeaders),
};
const result = this.#signToRequest(request, args.key, ['(request-target)', 'date', 'host']);
const result = await this.#signToRequest(request, args.key, ['(request-target)', 'date', 'host']);
return {
request,
@@ -91,9 +93,10 @@ export class ApRequestCreator {
};
}
static #signToRequest(request: Request, key: PrivateKey, includeHeaders: string[]): Signed {
static async #signToRequest(request: Request, key: PrivateKey, includeHeaders: string[]): Promise<Signed> {
const signingString = this.#genSigningString(request, includeHeaders);
const signature = crypto.sign('sha256', Buffer.from(signingString), key.privateKeyPem).toString('base64');
const sign = promisify(RsaKeyPair.prototype.sign).bind(RsaKeyPair.fromPem(key.privateKeyPem));
const signature = (await sign(Buffer.from(signingString))).toString('base64');
const signatureHeader = `keyId="${key.keyId}",algorithm="rsa-sha256",headers="${includeHeaders.join(' ')}",signature="${signature}"`;
request.headers = this.#objectAssignWithLcKey(request.headers, {
@@ -160,7 +163,7 @@ export class ApRequestService {
const keypair = await this.userKeypairService.getUserKeypair(user.id);
const req = ApRequestCreator.createSignedPost({
const req = await ApRequestCreator.createSignedPost({
key: {
privateKeyPem: keypair.privateKey,
keyId: `${this.config.url}/users/${user.id}#main-key`,
@@ -189,7 +192,7 @@ export class ApRequestService {
const _followAlternate = followAlternate ?? true;
const keypair = await this.userKeypairService.getUserKeypair(user.id);
const req = ApRequestCreator.createSignedGet({
const req = await ApRequestCreator.createSignedGet({
key: {
privateKeyPem: keypair.privateKey,
keyId: `${this.config.url}/users/${user.id}#main-key`,

View File

@@ -4,7 +4,9 @@
*/
import * as crypto from 'node:crypto';
import { promisify } from 'node:util';
import { Injectable } from '@nestjs/common';
import { RsaKeyPair } from 'slacc';
import { HttpRequestService } from '@/core/HttpRequestService.js';
import { bindThis } from '@/decorators.js';
import { CONTEXT, PRELOADED_CONTEXTS } from './misc/contexts.js';
@@ -45,11 +47,9 @@ class JsonLd {
const toBeSigned = await this.createVerifyData(data, options);
const signer = crypto.createSign('sha256');
signer.update(toBeSigned);
signer.end();
const sign = promisify(RsaKeyPair.prototype.sign).bind(RsaKeyPair.fromPem(privateKey));
const signature = signer.sign(privateKey);
const signature = await sign(Buffer.from(toBeSigned));
return {
...data,

View File

@@ -0,0 +1,10 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { init } from 'slacc';
import { builtinEnvironments } from 'vitest/runtime';
init(1);
export default builtinEnvironments.node;

View File

@@ -42,7 +42,7 @@ describe('ap-request', () => {
'User-Agent': 'UA',
};
const req = ApRequestCreator.createSignedPost({ key, url, body, additionalHeaders: headers });
const req = await ApRequestCreator.createSignedPost({ key, url, body, additionalHeaders: headers });
const parsed = buildParsedSignature(req.signingString, req.signature, 'rsa-sha256');
@@ -58,7 +58,7 @@ describe('ap-request', () => {
'User-Agent': 'UA',
};
const req = ApRequestCreator.createSignedGet({ key, url, additionalHeaders: headers });
const req = await ApRequestCreator.createSignedGet({ key, url, additionalHeaders: headers });
const parsed = buildParsedSignature(req.signingString, req.signature, 'rsa-sha256');

View File

@@ -6,6 +6,7 @@ export default mergeConfig(
defineConfig({
test: {
globalSetup: './test/setup.unit.ts',
environment: './test/environment.unit.ts',
include: ['test/unit/**/*.ts', 'src/**/*.test.ts'],
},
}),