feat: Hiding stack traces in production env
This commit is contained in:
parent
8fc0a3b590
commit
34b2f2f748
|
|
@ -2,11 +2,19 @@
|
|||
* SPDX-FileCopyrightText: MomentQYC and other misskey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { FastifyReply, FastifyRequest } from 'fastify';
|
||||
|
||||
export function ErrorHandling(message: string): Error {
|
||||
export function ErrorHandling(message: string, reply?: FastifyReply, statusCode?: number): Error {
|
||||
const error = new Error(message);
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
error.stack = undefined;
|
||||
}
|
||||
if (reply) {
|
||||
reply.code(statusCode ?? 500);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
export function ErrorHandler(error: Error, request: FastifyRequest, reply: FastifyReply): void {
|
||||
throw ErrorHandling(error.message, reply);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import { UtilityService } from '@/core/UtilityService.js';
|
|||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { IActivity } from '@/core/activitypub/type.js';
|
||||
import { ErrorHandler } from '@/misc/error.js';
|
||||
import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions } from 'fastify';
|
||||
import type { FindOptionsWhere } from 'typeorm';
|
||||
|
||||
|
|
@ -462,6 +463,8 @@ export class ActivityPubServerService {
|
|||
fastify.addContentTypeParser('application/activity+json', { parseAs: 'string' }, fastify.getDefaultJsonParser('ignore', 'ignore'));
|
||||
fastify.addContentTypeParser('application/ld+json', { parseAs: 'string' }, fastify.getDefaultJsonParser('ignore', 'ignore'));
|
||||
|
||||
fastify.setErrorHandler(ErrorHandler);
|
||||
|
||||
fastify.addHook('onRequest', (request, reply, done) => {
|
||||
reply.header('Access-Control-Allow-Headers', 'Accept');
|
||||
reply.header('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import { LoggerService } from '@/core/LoggerService.js';
|
|||
import { bindThis } from '@/decorators.js';
|
||||
import { isMimeImage } from '@/misc/is-mime-image.js';
|
||||
import { correctFilename } from '@/misc/correct-filename.js';
|
||||
import { ErrorHandler } from '@/misc/error.js';
|
||||
import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions } from 'fastify';
|
||||
|
||||
const _filename = fileURLToPath(import.meta.url);
|
||||
|
|
@ -59,6 +60,7 @@ export class FileServerService {
|
|||
|
||||
@bindThis
|
||||
public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) {
|
||||
fastify.setErrorHandler(ErrorHandler);
|
||||
fastify.addHook('onRequest', (request, reply, done) => {
|
||||
reply.header('Content-Security-Policy', 'default-src \'none\'; img-src \'self\'; media-src \'self\'; style-src \'unsafe-inline\'');
|
||||
done();
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { bindThis } from '@/decorators.js';
|
|||
import NotesChart from '@/core/chart/charts/notes.js';
|
||||
import UsersChart from '@/core/chart/charts/users.js';
|
||||
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||
import { ErrorHandler } from '@/misc/error.js';
|
||||
import type { FastifyInstance, FastifyPluginOptions } from 'fastify';
|
||||
|
||||
const nodeinfo2_1path = '/nodeinfo/2.1';
|
||||
|
|
@ -118,6 +119,8 @@ export class NodeinfoServerService {
|
|||
|
||||
const cache = new MemorySingleCache<Awaited<ReturnType<typeof nodeinfo2>>>(1000 * 60 * 10);
|
||||
|
||||
fastify.setErrorHandler(ErrorHandler);
|
||||
|
||||
fastify.get(nodeinfo2_1path, async (request, reply) => {
|
||||
const base = await cache.fetch(() => nodeinfo2());
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
|||
import { LoggerService } from '@/core/LoggerService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { ErrorHandler } from '@/misc/error.js';
|
||||
import { ActivityPubServerService } from './ActivityPubServerService.js';
|
||||
import { NodeinfoServerService } from './NodeinfoServerService.js';
|
||||
import { ApiServerService } from './api/ApiServerService.js';
|
||||
|
|
@ -76,6 +77,7 @@ export class ServerService implements OnApplicationShutdown {
|
|||
logger: !['production', 'test'].includes(process.env.NODE_ENV ?? ''),
|
||||
});
|
||||
this.#fastify = fastify;
|
||||
fastify.setErrorHandler(ErrorHandler);
|
||||
|
||||
// HSTS
|
||||
// 6months (15552000sec)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import type { User } from '@/models/entities/User.js';
|
|||
import * as Acct from '@/misc/acct.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { ErrorHandler } from '@/misc/error.js';
|
||||
import { NodeinfoServerService } from './NodeinfoServerService.js';
|
||||
import type { FindOptionsWhere } from 'typeorm';
|
||||
import type { FastifyInstance, FastifyPluginOptions } from 'fastify';
|
||||
|
|
@ -51,6 +52,8 @@ export class WellKnownServerService {
|
|||
|
||||
fastify.register(fastifyAccepts);
|
||||
|
||||
fastify.setErrorHandler(ErrorHandler);
|
||||
|
||||
fastify.addHook('onRequest', (request, reply, done) => {
|
||||
reply.header('Access-Control-Allow-Headers', 'Accept');
|
||||
reply.header('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import type { InstancesRepository, AccessTokensRepository } from '@/models/index
|
|||
import { DI } from '@/di-symbols.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { ErrorHandler } from '@/misc/error.js';
|
||||
import endpoints from './endpoints.js';
|
||||
import { ApiCallService } from './ApiCallService.js';
|
||||
import { SignupApiService } from './SignupApiService.js';
|
||||
|
|
@ -56,6 +57,8 @@ export class ApiServerService {
|
|||
|
||||
fastify.register(fastifyCookie, {});
|
||||
|
||||
fastify.setErrorHandler(ErrorHandler);
|
||||
|
||||
// Prevent cache
|
||||
fastify.addHook('onRequest', (request, reply, done) => {
|
||||
reply.header('Cache-Control', 'private, max-age=0, must-revalidate');
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { Inject, Injectable } from '@nestjs/common';
|
|||
import type { Config } from '@/config.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { ErrorHandler } from '@/misc/error.js';
|
||||
import { genOpenapiSpec } from './gen-spec.js';
|
||||
import type { FastifyInstance, FastifyPluginOptions } from 'fastify';
|
||||
|
||||
|
|
@ -23,6 +24,7 @@ export class OpenApiServerService {
|
|||
|
||||
@bindThis
|
||||
public createServer(fastify: FastifyInstance, _options: FastifyPluginOptions, done: (err?: Error) => void) {
|
||||
fastify.setErrorHandler(ErrorHandler);
|
||||
fastify.get('/api-doc', async (_request, reply) => {
|
||||
reply.header('Cache-Control', 'public, max-age=86400');
|
||||
return await reply.sendFile('/redoc.html', staticAssets);
|
||||
|
|
|
|||
|
|
@ -31,9 +31,9 @@ import { MemoryKVCache } from '@/misc/cache.js';
|
|||
import { LoggerService } from '@/core/LoggerService.js';
|
||||
import Logger from '@/logger.js';
|
||||
import { StatusError } from '@/misc/status-error.js';
|
||||
import { ErrorHandler, ErrorHandling } from '@/misc/error.js';
|
||||
import type { ServerResponse } from 'node:http';
|
||||
import type { FastifyInstance } from 'fastify';
|
||||
import { ErrorHandling } from '@/misc/error.js';
|
||||
|
||||
// TODO: Consider migrating to @node-oauth/oauth2-server once
|
||||
// https://github.com/node-oauth/node-oauth2-server/issues/180 is figured out.
|
||||
|
|
@ -354,6 +354,9 @@ export class OAuth2ProviderService {
|
|||
public async createServer(fastify: FastifyInstance): Promise<void> {
|
||||
// https://datatracker.ietf.org/doc/html/rfc8414.html
|
||||
// https://indieauth.spec.indieweb.org/#indieauth-server-metadata
|
||||
|
||||
fastify.setErrorHandler(ErrorHandler);
|
||||
|
||||
fastify.get('/.well-known/oauth-authorization-server', async (_request, reply) => {
|
||||
reply.send({
|
||||
issuer: this.config.url,
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ import { FeedService } from './FeedService.js';
|
|||
import { UrlPreviewService } from './UrlPreviewService.js';
|
||||
import { ClientLoggerService } from './ClientLoggerService.js';
|
||||
import type { FastifyInstance, FastifyPluginOptions, FastifyReply } from 'fastify';
|
||||
import { ErrorHandling } from '@/misc/error.js';
|
||||
|
||||
const _filename = fileURLToPath(import.meta.url);
|
||||
const _dirname = dirname(_filename);
|
||||
|
|
@ -147,18 +146,18 @@ export class ClientServerService {
|
|||
if (request.url === bullBoardPath || request.url.startsWith(bullBoardPath + '/')) {
|
||||
const token = request.cookies.token;
|
||||
if (token == null) {
|
||||
reply.code(401);
|
||||
throw ErrorHandling('login required');
|
||||
reply.code(401).send('Login required');
|
||||
return;
|
||||
}
|
||||
const user = await this.usersRepository.findOneBy({ token });
|
||||
if (user == null) {
|
||||
reply.code(403);
|
||||
throw ErrorHandling('no such user');
|
||||
reply.code(403).send('No such user');
|
||||
return;
|
||||
}
|
||||
const isAdministrator = await this.roleService.isAdministrator(user);
|
||||
if (!isAdministrator) {
|
||||
reply.code(403);
|
||||
throw ErrorHandling('access denied');
|
||||
reply.code(403).send('Access denied');
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -683,12 +682,13 @@ export class ClientServerService {
|
|||
|
||||
fastify.setErrorHandler(async (error, request, reply) => {
|
||||
const errId = randomUUID();
|
||||
const stack = (process.env.NODE_ENV === 'production') ? '' : error.stack;
|
||||
this.clientLoggerService.logger.error(`Internal error occurred in ${request.routerPath}: ${error.message}`, {
|
||||
path: request.routerPath,
|
||||
params: request.params,
|
||||
query: request.query,
|
||||
code: error.name,
|
||||
stack: error.stack,
|
||||
stack,
|
||||
id: errId,
|
||||
});
|
||||
reply.code(500);
|
||||
|
|
|
|||
Loading…
Reference in New Issue