From 1fc1d8e88b5948ee13737bf2ab35cb0481a758d6 Mon Sep 17 00:00:00 2001 From: DarkCat09 Date: Thu, 21 Sep 2023 13:18:12 +0400 Subject: [PATCH 01/16] NotHtmlMimetype error handling --- src/errors/handler.ts | 9 +-------- src/errors/main.ts | 32 ++++++++++++++++++++++---------- src/handlers/main.ts | 2 +- templates/error.ejs | 8 ++++++++ 4 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/errors/handler.ts b/src/errors/handler.ts index 1b0e472..909757a 100644 --- a/src/errors/handler.ts +++ b/src/errors/handler.ts @@ -29,10 +29,6 @@ function apiErrorHandler(error: Error, reply: FastifyReply) { }); } - if (error instanceof NotHtmlMimetypeError) { - return generateResponse(501); - } - if (getFastifyError(error)?.statusCode === 400) { return generateResponse(400); } @@ -45,10 +41,6 @@ function apiErrorHandler(error: Error, reply: FastifyReply) { } function htmlErrorHandler(error: Error, reply: FastifyReply, url: string) { - if (error instanceof NotHtmlMimetypeError) { - return reply.redirect(301, error.url); - } - if (getFastifyError(error)?.statusCode === 400) { return reply.code(400).view("/templates/error.ejs", { url, @@ -62,6 +54,7 @@ function htmlErrorHandler(error: Error, reply: FastifyReply, url: string) { url, code: error.code, description: error.description, + proxyBtn: error instanceof NotHtmlMimetypeError, }); } diff --git a/src/errors/main.ts b/src/errors/main.ts index 29190c9..bee68f3 100644 --- a/src/errors/main.ts +++ b/src/errors/main.ts @@ -3,7 +3,11 @@ export abstract class TxtDotError extends Error { name: string; description: string; - constructor(code: number, name: string, description: string) { + constructor( + code: number, + name: string, + description: string, + ) { super(description); this.code = code; this.name = name; @@ -13,22 +17,30 @@ export abstract class TxtDotError extends Error { export class EngineParseError extends TxtDotError { constructor(message: string) { - super(422, "EngineParseError", `Parse error: ${message}`); + super( + 422, + "EngineParseError", + `Parse error: ${message}`, + ); } } export class LocalResourceError extends TxtDotError { constructor() { - super(403, "LocalResourceError", "Proxying local resources is forbidden."); + super( + 403, + "LocalResourceError", + "Proxying local resources is forbidden.", + ); } } -export class NotHtmlMimetypeError extends Error { - name: string = "NotHtmlMimetypeError"; - url: string; - - constructor(url: string) { - super(); - this.url = url; +export class NotHtmlMimetypeError extends TxtDotError { + constructor() { + super( + 421, + "NotHtmlMimetypeError", + "Received non-HTML content, use proxy", + ); } } diff --git a/src/handlers/main.ts b/src/handlers/main.ts index d3fa83a..27875a2 100644 --- a/src/handlers/main.ts +++ b/src/handlers/main.ts @@ -32,7 +32,7 @@ export default async function handlePage( const mime: string | undefined = response.headers["content-type"]?.toString(); if (mime && mime.indexOf("text/html") === -1) { - throw new NotHtmlMimetypeError(url); + throw new NotHtmlMimetypeError(); } return getFallbackEngine(urlObj.hostname, engine)( diff --git a/templates/error.ejs b/templates/error.ejs index 127c7da..2094b13 100644 --- a/templates/error.ejs +++ b/templates/error.ejs @@ -15,6 +15,14 @@

txt.

<%= description %>

From 47e4db1fc8a61b6e0fb047fb9e5318f73fc5d59e Mon Sep 17 00:00:00 2001 From: DarkCat09 Date: Thu, 21 Sep 2023 13:51:25 +0400 Subject: [PATCH 02/16] Proxying --- src/app.ts | 6 ++++-- src/routes/browser/proxy.ts | 18 ++++++++++++++++++ src/types/requests/browser.ts | 30 ++++++++++++++++++++++++++---- 3 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 src/routes/browser/proxy.ts diff --git a/src/app.ts b/src/app.ts index 65f5a5d..8c1f59f 100644 --- a/src/app.ts +++ b/src/app.ts @@ -9,9 +9,10 @@ import fastifySwagger from "@fastify/swagger"; import fastifySwaggerUi from "@fastify/swagger-ui"; import ejs from "ejs"; -import getRoute from "./routes/browser/get"; -import parseRoute from "./routes/api/parse"; import indexRoute from "./routes/browser/index"; +import getRoute from "./routes/browser/get"; +import proxyRoute from "./routes/browser/proxy"; +import parseRoute from "./routes/api/parse"; import rawHtml from "./routes/api/raw-html"; import publicConfig from "./publicConfig"; @@ -54,6 +55,7 @@ class App { fastify.register(indexRoute); fastify.register(getRoute); + fastify.register(proxyRoute); fastify.register(parseRoute); fastify.register(rawHtml); diff --git a/src/routes/browser/proxy.ts b/src/routes/browser/proxy.ts new file mode 100644 index 0000000..4947abf --- /dev/null +++ b/src/routes/browser/proxy.ts @@ -0,0 +1,18 @@ +import { FastifyInstance } from "fastify"; +import { IProxySchema, ProxySchema } from "../../types/requests/browser"; +import axios from "../../types/axios"; + +export default async function proxyRoute(fastify: FastifyInstance) { + fastify.get( + "/proxy", + { schema: ProxySchema }, + async (request, reply) => { + const response = await axios.get(request.query.url); + const mime: string | undefined = response.headers["content-type"]?.toString(); + const clen: string | undefined = response.headers["content-length"]?.toString(); + mime && reply.header("Content-Type", mime); + clen && reply.header("Content-Length", Number(clen)); + return reply.send(response.data); + } + ); +} diff --git a/src/types/requests/browser.ts b/src/types/requests/browser.ts index e9891ed..4507b11 100644 --- a/src/types/requests/browser.ts +++ b/src/types/requests/browser.ts @@ -6,10 +6,9 @@ export interface IGetSchema { Querystring: IGetQuerySchema; } -export const indexSchema = { - produces: ["text/html"], - hide: true -}; +export interface IProxySchema { + Querystring: IProxyQuerySchema; +} export const getQuerySchema = { type: "object", @@ -32,9 +31,32 @@ export const getQuerySchema = { } as const; export type IGetQuerySchema = FromSchema; +export const proxyQuerySchema = { + type: "object", + required: ["url"], + properties: { + url: { + type: "string", + description: "URL", + }, + } +} as const; +export type IProxyQuerySchema = FromSchema; + +export const indexSchema = { + hide: true, + produces: ["text/html"], +}; + export const GetSchema: FastifySchema = { description: "Get page", hide: true, querystring: getQuerySchema, produces: ["text/html", "text/plain"], }; + +export const ProxySchema: FastifySchema = { + description: "Proxy resource", + hide: true, + querystring: proxyQuerySchema, +} From 553efb1da68fa4af5b305e4212cd1d8ae3a6d179 Mon Sep 17 00:00:00 2001 From: DarkCat09 Date: Thu, 21 Sep 2023 16:26:32 +0400 Subject: [PATCH 03/16] New config entries --- .env.example | 2 ++ src/app.ts | 5 ++++- src/config/config.service.ts | 3 +++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 22b7787..26f6507 100644 --- a/.env.example +++ b/.env.example @@ -2,3 +2,5 @@ HOST=127.0.0.1 # 0.0.0.0 if txtdot is not behind reverse proxy PORT=8080 REVERSE_PROXY=true # only for reverse proxy; see docs + +PROXY_RES=true diff --git a/src/app.ts b/src/app.ts index 8c1f59f..6843d3c 100644 --- a/src/app.ts +++ b/src/app.ts @@ -55,7 +55,10 @@ class App { fastify.register(indexRoute); fastify.register(getRoute); - fastify.register(proxyRoute); + + if (this.config.proxy_res) + fastify.register(proxyRoute); + fastify.register(parseRoute); fastify.register(rawHtml); diff --git a/src/config/config.service.ts b/src/config/config.service.ts index fa870ab..13ddb8d 100644 --- a/src/config/config.service.ts +++ b/src/config/config.service.ts @@ -4,6 +4,7 @@ export class ConfigService { public readonly host: string; public readonly port: number; public readonly reverse_proxy: boolean; + public readonly proxy_res: boolean; constructor() { config(); @@ -12,5 +13,7 @@ export class ConfigService { this.port = Number(process.env.PORT) || 8080; this.reverse_proxy = Boolean(process.env.REVERSE_PROXY) || false; + + this.proxy_res = Boolean(process.env.PROXY_RES) || true; } } From f56b79c5633681cff1766ecfefbd140a834630d3 Mon Sep 17 00:00:00 2001 From: DarkCat09 Date: Thu, 21 Sep 2023 16:28:55 +0400 Subject: [PATCH 04/16] getConfig() --- src/app.ts | 15 ++++++--------- src/config/main.ts | 12 ++++++++++++ 2 files changed, 18 insertions(+), 9 deletions(-) create mode 100644 src/config/main.ts diff --git a/src/app.ts b/src/app.ts index 6843d3c..fff4239 100644 --- a/src/app.ts +++ b/src/app.ts @@ -17,18 +17,15 @@ import rawHtml from "./routes/api/raw-html"; import publicConfig from "./publicConfig"; import errorHandler from "./errors/handler"; +import getConfig from "./config/main"; class App { - config: ConfigService; - - constructor() { - this.config = new ConfigService(); - } - async init() { + const config = getConfig(); + const fastify = Fastify({ logger: true, - trustProxy: this.config.reverse_proxy, + trustProxy: config.reverse_proxy, }); fastify.register(fastifyStatic, { @@ -56,7 +53,7 @@ class App { fastify.register(indexRoute); fastify.register(getRoute); - if (this.config.proxy_res) + if (config.proxy_res) fastify.register(proxyRoute); fastify.register(parseRoute); @@ -65,7 +62,7 @@ class App { fastify.setErrorHandler(errorHandler); fastify.listen( - { host: this.config.host, port: this.config.port }, + { host: config.host, port: config.port }, (err) => { err && console.log(err); } diff --git a/src/config/main.ts b/src/config/main.ts new file mode 100644 index 0000000..37dcad3 --- /dev/null +++ b/src/config/main.ts @@ -0,0 +1,12 @@ +import { ConfigService } from "./config.service"; + +let configSvc: ConfigService | undefined; + +export default function getConfig(): ConfigService { + if (configSvc) { + return configSvc; + } + + configSvc = new ConfigService(); + return configSvc; +} From 86c033bdaaf3470da4b587dd62ba718dcc5cd300 Mon Sep 17 00:00:00 2001 From: DarkCat09 Date: Thu, 21 Sep 2023 16:32:08 +0400 Subject: [PATCH 05/16] Use common getConfig() --- src/errors/handler.ts | 6 +++++- src/errors/main.ts | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/errors/handler.ts b/src/errors/handler.ts index 909757a..5d28722 100644 --- a/src/errors/handler.ts +++ b/src/errors/handler.ts @@ -3,6 +3,7 @@ import { NotHtmlMimetypeError, TxtDotError } from "./main"; import { getFastifyError } from "./validation"; import { IGetSchema } from "../types/requests/browser"; +import getConfig from "../config/main"; export default function errorHandler( error: Error, @@ -54,7 +55,10 @@ function htmlErrorHandler(error: Error, reply: FastifyReply, url: string) { url, code: error.code, description: error.description, - proxyBtn: error instanceof NotHtmlMimetypeError, + proxyBtn: ( + error instanceof NotHtmlMimetypeError && + getConfig().proxy_res + ), }); } diff --git a/src/errors/main.ts b/src/errors/main.ts index bee68f3..81f983a 100644 --- a/src/errors/main.ts +++ b/src/errors/main.ts @@ -1,3 +1,5 @@ +import getConfig from "../config/main"; + export abstract class TxtDotError extends Error { code: number; name: string; @@ -40,7 +42,11 @@ export class NotHtmlMimetypeError extends TxtDotError { super( 421, "NotHtmlMimetypeError", - "Received non-HTML content, use proxy", + "Received non-HTML content, " + ( + getConfig().proxy_res ? + "use proxy instead of parser." : + "proxying is disabled by the instance admin." + ), ); } } From 645542795daf9e64116ddc0fe1f4febd74eae93a Mon Sep 17 00:00:00 2001 From: DarkCat09 Date: Thu, 21 Sep 2023 17:58:23 +0400 Subject: [PATCH 06/16] Template variable bugfix --- templates/error.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/error.ejs b/templates/error.ejs index 2094b13..2bea449 100644 --- a/templates/error.ejs +++ b/templates/error.ejs @@ -15,7 +15,7 @@

txt.