From 3fe2650a5efb8dcefec107bc1e2d2239e40c792e Mon Sep 17 00:00:00 2001 From: Russell2259 <84256826+Russell2259@users.noreply.github.com> Date: Thu, 25 Jan 2024 20:52:54 -0700 Subject: [PATCH] moving to new repo --- lib/bare-server-modified/AbstractMessage.d.ts | 34 -- lib/bare-server-modified/AbstractMessage.js | 61 --- lib/bare-server-modified/BareServer.d.ts | 90 ----- lib/bare-server-modified/BareServer.js | 168 -------- lib/bare-server-modified/Meta.d.ts | 33 -- lib/bare-server-modified/Meta.js | 43 --- lib/bare-server-modified/V1.d.ts | 2 - lib/bare-server-modified/V1.js | 254 ------------ lib/bare-server-modified/V2.d.ts | 2 - lib/bare-server-modified/V2.js | 364 ------------------ lib/bare-server-modified/V3.d.ts | 2 - lib/bare-server-modified/V3.js | 305 --------------- lib/bare-server-modified/createServer.d.ts | 52 --- lib/bare-server-modified/createServer.js | 99 ----- lib/bare-server-modified/encodeProtocol.d.ts | 3 - lib/bare-server-modified/encodeProtocol.js | 48 --- lib/bare-server-modified/headerUtil.d.ts | 8 - lib/bare-server-modified/headerUtil.js | 48 --- lib/bare-server-modified/remoteUtil.d.ts | 9 - lib/bare-server-modified/remoteUtil.js | 36 -- lib/bare-server-modified/requestUtil.d.ts | 13 - lib/bare-server-modified/requestUtil.js | 185 --------- lib/bare-server-modified/splitHeaderUtil.d.ts | 14 - lib/bare-server-modified/splitHeaderUtil.js | 60 --- server/index.js | 2 +- 25 files changed, 1 insertion(+), 1934 deletions(-) delete mode 100644 lib/bare-server-modified/AbstractMessage.d.ts delete mode 100644 lib/bare-server-modified/AbstractMessage.js delete mode 100644 lib/bare-server-modified/BareServer.d.ts delete mode 100644 lib/bare-server-modified/BareServer.js delete mode 100644 lib/bare-server-modified/Meta.d.ts delete mode 100644 lib/bare-server-modified/Meta.js delete mode 100644 lib/bare-server-modified/V1.d.ts delete mode 100644 lib/bare-server-modified/V1.js delete mode 100644 lib/bare-server-modified/V2.d.ts delete mode 100644 lib/bare-server-modified/V2.js delete mode 100644 lib/bare-server-modified/V3.d.ts delete mode 100644 lib/bare-server-modified/V3.js delete mode 100644 lib/bare-server-modified/createServer.d.ts delete mode 100644 lib/bare-server-modified/createServer.js delete mode 100644 lib/bare-server-modified/encodeProtocol.d.ts delete mode 100644 lib/bare-server-modified/encodeProtocol.js delete mode 100644 lib/bare-server-modified/headerUtil.d.ts delete mode 100644 lib/bare-server-modified/headerUtil.js delete mode 100644 lib/bare-server-modified/remoteUtil.d.ts delete mode 100644 lib/bare-server-modified/remoteUtil.js delete mode 100644 lib/bare-server-modified/requestUtil.d.ts delete mode 100644 lib/bare-server-modified/requestUtil.js delete mode 100644 lib/bare-server-modified/splitHeaderUtil.d.ts delete mode 100644 lib/bare-server-modified/splitHeaderUtil.js diff --git a/lib/bare-server-modified/AbstractMessage.d.ts b/lib/bare-server-modified/AbstractMessage.d.ts deleted file mode 100644 index 8a5dbba..0000000 --- a/lib/bare-server-modified/AbstractMessage.d.ts +++ /dev/null @@ -1,34 +0,0 @@ -/// -/// -import type { IncomingMessage, ServerResponse } from 'node:http'; -import { Headers } from 'headers-polyfill'; -import type { BareHeaders } from './requestUtil.js'; -export interface RequestInit { - method: string; - path: string; - headers: Headers | BareHeaders; -} -/** - * Abstraction for the data read from IncomingMessage - */ -export declare class Request { - body: IncomingMessage; - method: string; - headers: Headers; - url: URL; - constructor(body: IncomingMessage, init: RequestInit); -} -export type ResponseBody = Buffer | IncomingMessage; -export interface ResponseInit { - headers?: Headers | BareHeaders; - status?: number; - statusText?: string; -} -export declare class Response { - body?: ResponseBody; - status: number; - statusText?: string; - headers: Headers; - constructor(body: ResponseBody | undefined, init?: ResponseInit); -} -export declare function writeResponse(response: Response, res: ServerResponse): boolean; diff --git a/lib/bare-server-modified/AbstractMessage.js b/lib/bare-server-modified/AbstractMessage.js deleted file mode 100644 index 47fc4db..0000000 --- a/lib/bare-server-modified/AbstractMessage.js +++ /dev/null @@ -1,61 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.writeResponse = exports.Response = exports.Request = void 0; -const node_stream_1 = require("node:stream"); -const headers_polyfill_1 = require("headers-polyfill"); -/** - * Abstraction for the data read from IncomingMessage - */ -class Request { - body; - method; - headers; - url; - constructor(body, init) { - this.body = body; - this.method = init.method; - this.headers = new headers_polyfill_1.Headers(init.headers); - // Parse the URL pathname. Host doesn't matter. - this.url = new URL(init.path, 'http://bare-server-node'); - } -} -exports.Request = Request; -class Response { - body; - status; - statusText; - headers; - constructor(body, init = {}) { - if (body) { - this.body = body instanceof node_stream_1.Stream ? body : Buffer.from(body); - } - if (typeof init.status === 'number') { - this.status = init.status; - } - else { - this.status = 200; - } - if (typeof init.statusText === 'string') { - this.statusText = init.statusText; - } - this.headers = new headers_polyfill_1.Headers(init.headers); - } -} -exports.Response = Response; -function writeResponse(response, res) { - for (const [header, value] of response.headers) - res.setHeader(header, value); - res.writeHead(response.status, response.statusText); - if (response.body instanceof node_stream_1.Stream) { - const { body } = response; - res.on('close', () => body.destroy()); - body.pipe(res); - } - else if (response.body instanceof Buffer) - res.end(response.body); - else - res.end(); - return true; -} -exports.writeResponse = writeResponse; -//# sourceMappingURL=AbstractMessage.js.map \ No newline at end of file diff --git a/lib/bare-server-modified/BareServer.d.ts b/lib/bare-server-modified/BareServer.d.ts deleted file mode 100644 index aa2b28c..0000000 --- a/lib/bare-server-modified/BareServer.d.ts +++ /dev/null @@ -1,90 +0,0 @@ -/// -/// -/// -/// -/// -/// -/// -import type { LookupOneOptions } from 'node:dns'; -import EventEmitter from 'node:events'; -import type { Agent as HttpAgent, IncomingMessage, ServerResponse } from 'node:http'; -import type { Agent as HttpsAgent } from 'node:https'; -import type { Duplex } from 'node:stream'; -import type WebSocket from 'ws'; -import { Request, Response } from './AbstractMessage.js'; -import type { JSONDatabaseAdapter } from './Meta.js'; -export interface BareErrorBody { - code: string; - id: string; - message?: string; - stack?: string; -} -export declare class BareError extends Error { - status: number; - body: BareErrorBody; - constructor(status: number, body: BareErrorBody); -} -export declare const pkg: { - version: string; -}; -export declare function json(status: number, json: T): Response; -export type BareMaintainer = { - email?: string; - website?: string; -}; -export type BareProject = { - name?: string; - description?: string; - email?: string; - website?: string; - repository?: string; - version?: string; -}; -export type BareLanguage = 'NodeJS' | 'ServiceWorker' | 'Deno' | 'Java' | 'PHP' | 'Rust' | 'C' | 'C++' | 'C#' | 'Ruby' | 'Go' | 'Crystal' | 'Shell' | string; -export type BareManifest = { - maintainer?: BareMaintainer; - project?: BareProject; - versions: string[]; - language: BareLanguage; - memoryUsage?: number; -}; -export interface Options { - logErrors: boolean; - /** - * Callback for filtering the remote URL. - * @returns Nothing - * @throws An error if the remote is bad. - */ - filterRemote?: (remote: Readonly) => Promise | void; - /** - * DNS lookup - * May not get called when remote.host is an IP - * Use in combination with filterRemote to block IPs - */ - lookup: (hostname: string, options: LookupOneOptions, callback: (err: NodeJS.ErrnoException | null, address: string, family: number) => void) => void; - localAddress?: string; - family?: number; - maintainer?: BareMaintainer; - httpAgent: HttpAgent; - httpsAgent: HttpsAgent; - database: JSONDatabaseAdapter; - wss: WebSocket.Server; -} -export type RouteCallback = (request: Request, response: ServerResponse, options: Options) => Promise | Response; -export type SocketRouteCallback = (request: Request, socket: Duplex, head: Buffer, options: Options) => Promise | void; -export default class Server extends EventEmitter { - routes: Map; - socketRoutes: Map; - versions: string[]; - private closed; - private directory; - private options; - /** - * Remove all timers and listeners - */ - close(): void; - shouldRoute(request: IncomingMessage): boolean; - get instanceInfo(): BareManifest; - routeUpgrade(req: IncomingMessage, socket: Duplex, head: Buffer): Promise; - routeRequest(req: IncomingMessage, res: ServerResponse): Promise; -} diff --git a/lib/bare-server-modified/BareServer.js b/lib/bare-server-modified/BareServer.js deleted file mode 100644 index ce2d153..0000000 --- a/lib/bare-server-modified/BareServer.js +++ /dev/null @@ -1,168 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.json = exports.pkg = exports.BareError = void 0; -const node_events_1 = __importDefault(require("node:events")); -const node_fs_1 = require("node:fs"); -const node_path_1 = require("node:path"); -const http_errors_1 = __importDefault(require("http-errors")); -const AbstractMessage_js_1 = require("./AbstractMessage.js"); -class BareError extends Error { - status; - body; - constructor(status, body) { - super(body.message || body.code); - this.status = status; - this.body = body; - } -} -exports.BareError = BareError; -exports.pkg = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(__dirname, '..', 'package.json'), 'utf-8')); -const project = { - name: 'bare-server-node', - description: 'TOMPHTTP NodeJS Bare Server', - repository: 'https://github.com/tomphttp/bare-server-node', - version: exports.pkg.version, -}; -function json(status, json) { - const send = Buffer.from(JSON.stringify(json, null, '\t')); - return new AbstractMessage_js_1.Response(send, { - status, - headers: { - 'content-type': 'application/json', - 'content-length': send.byteLength.toString(), - }, - }); -} -exports.json = json; -class Server extends node_events_1.default { - routes = new Map(); - socketRoutes = new Map(); - versions = []; - closed = false; - directory; - options; - /** - * @internal - */ - constructor(directory, options) { - super(); - this.directory = directory; - this.options = options; - } - /** - * Remove all timers and listeners - */ - close() { - this.closed = true; - this.emit('close'); - } - shouldRoute(request) { - return (!this.closed && - request.url !== undefined && - request.url.startsWith(this.directory)); - } - get instanceInfo() { - return { - versions: this.versions, - language: 'NodeJS', - memoryUsage: Math.round((process.memoryUsage().heapUsed / 1024 / 1024) * 100) / 100, - maintainer: this.options.maintainer, - project, - }; - } - async routeUpgrade(req, socket, head) { - const request = new AbstractMessage_js_1.Request(req, { - method: req.method, - path: req.url, - headers: req.headers, - }); - const service = request.url.pathname.slice(this.directory.length - 1); - if (this.socketRoutes.has(service)) { - const call = this.socketRoutes.get(service); - try { - await call(request, socket, head, this.options); - } - catch (error) { - if (this.options.logErrors) { - console.error(error); - } - socket.end(); - } - } - else { - socket.end(); - } - } - async routeRequest(req, res) { - const request = new AbstractMessage_js_1.Request(req, { - method: req.method, - path: req.url, - headers: req.headers, - }); - const service = request.url.pathname.slice(this.directory.length - 1); - let response; - try { - if (request.method === 'OPTIONS') { - response = new AbstractMessage_js_1.Response(undefined, { status: 200 }); - } - else if (service === '/') { - response = json(200, this.instanceInfo); - } - else if (this.routes.has(service)) { - const call = this.routes.get(service); - response = await call(request, res, this.options); - } - else { - throw new http_errors_1.default.NotFound(); - } - } - catch (error) { - if (this.options.logErrors) - console.error(error); - if (http_errors_1.default.isHttpError(error)) { - response = json(error.statusCode, { - code: 'UNKNOWN', - id: `error.${error.name}`, - message: error.message, - stack: error.stack, - }); - } - else if (error instanceof Error) { - response = json(500, { - code: 'UNKNOWN', - id: `error.${error.name}`, - message: error.message, - stack: error.stack, - }); - } - else { - response = json(500, { - code: 'UNKNOWN', - id: 'error.Exception', - message: error, - stack: new Error(error).stack, - }); - } - if (!(response instanceof AbstractMessage_js_1.Response)) { - if (this.options.logErrors) { - console.error('Cannot', request.method, request.url.pathname, ': Route did not return a response.'); - } - throw new http_errors_1.default.InternalServerError(); - } - } - response.headers.set('x-robots-tag', 'noindex'); - response.headers.set('access-control-allow-headers', '*'); - response.headers.set('access-control-allow-origin', '*'); - response.headers.set('access-control-allow-methods', '*'); - response.headers.set('access-control-expose-headers', '*'); - // don't fetch preflight on every request... - // instead, fetch preflight every 10 minutes - response.headers.set('access-control-max-age', '7200'); - (0, AbstractMessage_js_1.writeResponse)(response, res); - } -} -exports.default = Server; -//# sourceMappingURL=BareServer.js.map \ No newline at end of file diff --git a/lib/bare-server-modified/Meta.d.ts b/lib/bare-server-modified/Meta.d.ts deleted file mode 100644 index 46f3c3b..0000000 --- a/lib/bare-server-modified/Meta.d.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { BareHeaders } from './requestUtil'; -export interface MetaV1 { - v: 1; - response?: { - headers: BareHeaders; - }; -} -export interface MetaV2 { - v: 2; - response?: { - status: number; - statusText: string; - headers: BareHeaders; - }; - sendHeaders: BareHeaders; - remote: string; - forwardHeaders: string[]; -} -export default interface CommonMeta { - value: MetaV1 | MetaV2; - expires: number; -} -export interface Database { - get(key: string): string | undefined | PromiseLike; - set(key: string, value: string): unknown; - has(key: string): boolean | PromiseLike; - delete(key: string): boolean | PromiseLike; - entries(): IterableIterator<[string, string]> | PromiseLike>; -} -/** - * Routine - */ -export declare function cleanupDatabase(database: Database): Promise; diff --git a/lib/bare-server-modified/Meta.js b/lib/bare-server-modified/Meta.js deleted file mode 100644 index c7886e0..0000000 --- a/lib/bare-server-modified/Meta.js +++ /dev/null @@ -1,43 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.cleanupDatabase = exports.JSONDatabaseAdapter = void 0; -/** - * @internal - */ -class JSONDatabaseAdapter { - impl; - constructor(impl) { - this.impl = impl; - } - async get(key) { - const res = await this.impl.get(key); - if (typeof res === 'string') - return JSON.parse(res); - } - async set(key, value) { - return await this.impl.set(key, JSON.stringify(value)); - } - async has(key) { - return await this.impl.has(key); - } - async delete(key) { - return await this.impl.delete(key); - } - async *[Symbol.asyncIterator]() { - for (const [id, value] of await this.impl.entries()) { - yield [id, JSON.parse(value)]; - } - } -} -exports.JSONDatabaseAdapter = JSONDatabaseAdapter; -/** - * Routine - */ -async function cleanupDatabase(database) { - const adapter = new JSONDatabaseAdapter(database); - for await (const [id, { expires }] of adapter) - if (expires < Date.now()) - database.delete(id); -} -exports.cleanupDatabase = cleanupDatabase; -//# sourceMappingURL=Meta.js.map \ No newline at end of file diff --git a/lib/bare-server-modified/V1.d.ts b/lib/bare-server-modified/V1.d.ts deleted file mode 100644 index d152b77..0000000 --- a/lib/bare-server-modified/V1.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -import type Server from './BareServer.js'; -export default function registerV1(server: Server): void; diff --git a/lib/bare-server-modified/V1.js b/lib/bare-server-modified/V1.js deleted file mode 100644 index be0c6a9..0000000 --- a/lib/bare-server-modified/V1.js +++ /dev/null @@ -1,254 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const headers_polyfill_1 = require("headers-polyfill"); -const AbstractMessage_js_1 = require("./AbstractMessage.js"); -const BareServer_js_1 = require("./BareServer.js"); -const encodeProtocol_js_1 = require("./encodeProtocol.js"); -const headerUtil_js_1 = require("./headerUtil.js"); -const remoteUtil_js_1 = require("./remoteUtil.js"); -const requestUtil_js_1 = require("./requestUtil.js"); -const validProtocols = ['http:', 'https:', 'ws:', 'wss:']; -function loadForwardedHeaders(forward, target, request) { - for (const header of forward) { - const value = request.headers.get(header); - if (value !== null) - target[header] = value; - } -} -function readHeaders(request) { - const remote = Object.create(null); - const headers = Object.create(null); - for (const remoteProp of ['host', 'port', 'protocol', 'path']) { - const header = `x-bare-${remoteProp}`; - const value = request.headers.get(header); - if (value === null) - throw new BareServer_js_1.BareError(400, { - code: 'MISSING_BARE_HEADER', - id: `request.headers.${header}`, - message: `Header was not specified.`, - }); - switch (remoteProp) { - case 'port': - if (isNaN(parseInt(value))) { - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: `request.headers.${header}`, - message: `Header was not a valid integer.`, - }); - } - break; - case 'protocol': - if (!validProtocols.includes(value)) { - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: `request.headers.${header}`, - message: `Header was invalid`, - }); - } - break; - } - remote[remoteProp] = value; - } - const xBareHeaders = request.headers.get('x-bare-headers'); - if (xBareHeaders === null) - throw new BareServer_js_1.BareError(400, { - code: 'MISSING_BARE_HEADER', - id: `request.headers.x-bare-headers`, - message: `Header was not specified.`, - }); - try { - const json = JSON.parse(xBareHeaders); - for (const header in json) { - const value = json[header]; - if (typeof value === 'string') { - headers[header] = value; - } - else if (Array.isArray(value)) { - const array = []; - for (const val of value) { - if (typeof val !== 'string') { - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: `bare.headers.${header}`, - message: `Header was not a String.`, - }); - } - array.push(val); - } - headers[header] = array; - } - else { - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: `bare.headers.${header}`, - message: `Header was not a String.`, - }); - } - } - } - catch (error) { - if (error instanceof SyntaxError) { - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: `request.headers.x-bare-headers`, - message: `Header contained invalid JSON. (${error.message})`, - }); - } - else { - throw error; - } - } - const xBareForwardHeaders = request.headers.get('x-bare-forward-headers'); - if (xBareForwardHeaders === null) - throw new BareServer_js_1.BareError(400, { - code: 'MISSING_BARE_HEADER', - id: `request.headers.x-bare-forward-headers`, - message: `Header was not specified.`, - }); - try { - loadForwardedHeaders(JSON.parse(xBareForwardHeaders), headers, request); - } - catch (error) { - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: `request.headers.x-bare-forward-headers`, - message: `Header contained invalid JSON. (${error instanceof Error ? error.message : error})`, - }); - } - return { remote: (0, remoteUtil_js_1.remoteToURL)(remote), headers }; -} -const tunnelRequest = async (request, res, options) => { - const abort = new AbortController(); - request.body.on('close', () => { - if (!request.body.complete) - abort.abort(); - }); - res.on('close', () => { - abort.abort(); - }); - const { remote, headers } = readHeaders(request); - const response = await (0, requestUtil_js_1.fetch)(request, abort.signal, headers, remote, options); - const responseHeaders = new headers_polyfill_1.Headers(); - for (const header in response.headers) { - if (header === 'content-encoding' || header === 'x-content-encoding') - responseHeaders.set('content-encoding', (0, headerUtil_js_1.flattenHeader)(response.headers[header])); - else if (header === 'content-length') - responseHeaders.set('content-length', (0, headerUtil_js_1.flattenHeader)(response.headers[header])); - } - responseHeaders.set('x-bare-headers', JSON.stringify((0, headerUtil_js_1.mapHeadersFromArray)((0, headerUtil_js_1.rawHeaderNames)(response.rawHeaders), { - ...response.headers, - }))); - responseHeaders.set('x-bare-status', response.statusCode.toString()); - responseHeaders.set('x-bare-status-text', response.statusMessage); - return new AbstractMessage_js_1.Response(response, { status: 200, headers: responseHeaders }); -}; -const metaExpiration = 30e3; -const wsMeta = async (request, res, options) => { - if (request.method === 'OPTIONS') { - return new AbstractMessage_js_1.Response(undefined, { status: 200 }); - } - const id = request.headers.get('x-bare-id'); - if (id === null) - throw new BareServer_js_1.BareError(400, { - code: 'MISSING_BARE_HEADER', - id: 'request.headers.x-bare-id', - message: 'Header was not specified', - }); - const meta = await options.database.get(id); - // check if meta isn't undefined and if the version equals 1 - if (meta?.value.v !== 1) - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: 'request.headers.x-bare-id', - message: 'Unregistered ID', - }); - await options.database.delete(id); - return (0, BareServer_js_1.json)(200, { - headers: meta.value.response?.headers, - }); -}; -const wsNewMeta = async (request, res, options) => { - const id = (0, requestUtil_js_1.randomHex)(16); - await options.database.set(id, { - value: { v: 1 }, - expires: Date.now() + metaExpiration, - }); - return new AbstractMessage_js_1.Response(Buffer.from(id)); -}; -const tunnelSocket = async (request, socket, head, options) => { - const abort = new AbortController(); - request.body.on('close', () => { - if (!request.body.complete) - abort.abort(); - }); - socket.on('close', () => { - abort.abort(); - }); - if (!request.headers.has('sec-websocket-protocol')) { - socket.end(); - return; - } - const [firstProtocol, data] = request.headers - .get('sec-websocket-protocol') - .split(/,\s*/g); - if (firstProtocol !== 'bare') { - socket.end(); - return; - } - const { remote, headers, forward_headers: forwardHeaders, id, } = JSON.parse((0, encodeProtocol_js_1.decodeProtocol)(data)); - loadForwardedHeaders(forwardHeaders, headers, request); - const [remoteResponse, remoteSocket] = await (0, requestUtil_js_1.upgradeFetch)(request, abort.signal, headers, (0, remoteUtil_js_1.remoteToURL)(remote), options); - remoteSocket.on('close', () => { - // console.log('Remote closed'); - socket.end(); - }); - socket.on('close', () => { - // console.log('Serving closed'); - remoteSocket.end(); - }); - remoteSocket.on('error', (error) => { - if (options.logErrors) { - console.error('Remote socket error:', error); - } - socket.end(); - }); - socket.on('error', (error) => { - if (options.logErrors) { - console.error('Serving socket error:', error); - } - remoteSocket.end(); - }); - if (typeof id === 'string') { - const meta = await options.database.get(id); - if (meta?.value.v === 1) { - meta.value.response = { - headers: (0, headerUtil_js_1.mapHeadersFromArray)((0, headerUtil_js_1.rawHeaderNames)(remoteResponse.rawHeaders), { - ...remoteResponse.headers, - }), - }; - await options.database.set(id, meta); - } - } - const responseHeaders = [ - `HTTP/1.1 101 Switching Protocols`, - `Upgrade: websocket`, - `Connection: Upgrade`, - `Sec-WebSocket-Protocol: bare`, - `Sec-WebSocket-Accept: ${remoteResponse.headers['sec-websocket-accept']}`, - ]; - if ('sec-websocket-extensions' in remoteResponse.headers) { - responseHeaders.push(`Sec-WebSocket-Extensions: ${remoteResponse.headers['sec-websocket-extensions']}`); - } - socket.write(responseHeaders.concat('', '').join('\r\n')); - remoteSocket.pipe(socket); - socket.pipe(remoteSocket); -}; -function registerV1(server) { - server.routes.set('/v1/', tunnelRequest); - server.routes.set('/v1/ws-new-meta', wsNewMeta); - server.routes.set('/v1/ws-meta', wsMeta); - server.socketRoutes.set('/v1/', tunnelSocket); - server.versions.push('v1'); -} -exports.default = registerV1; -//# sourceMappingURL=V1.js.map \ No newline at end of file diff --git a/lib/bare-server-modified/V2.d.ts b/lib/bare-server-modified/V2.d.ts deleted file mode 100644 index 602953c..0000000 --- a/lib/bare-server-modified/V2.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -import type Server from './BareServer.js'; -export default function registerV2(server: Server): void; diff --git a/lib/bare-server-modified/V2.js b/lib/bare-server-modified/V2.js deleted file mode 100644 index 05c93dc..0000000 --- a/lib/bare-server-modified/V2.js +++ /dev/null @@ -1,364 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const headers_polyfill_1 = require("headers-polyfill"); -const AbstractMessage_js_1 = require("./AbstractMessage.js"); -const BareServer_js_1 = require("./BareServer.js"); -const headerUtil_js_1 = require("./headerUtil.js"); -const remoteUtil_js_1 = require("./remoteUtil.js"); -const requestUtil_js_1 = require("./requestUtil.js"); -const splitHeaderUtil_js_1 = require("./splitHeaderUtil.js"); -const validProtocols = ['http:', 'https:', 'ws:', 'wss:']; -const forbiddenForwardHeaders = [ - 'connection', - 'transfer-encoding', - 'host', - 'connection', - 'origin', - 'referer', -]; -const forbiddenPassHeaders = [ - 'vary', - 'connection', - 'transfer-encoding', - 'access-control-allow-headers', - 'access-control-allow-methods', - 'access-control-expose-headers', - 'access-control-max-age', - 'access-control-request-headers', - 'access-control-request-method', -]; -// common defaults -const defaultForwardHeaders = [ - 'accept-encoding', - 'accept-language', - 'sec-websocket-extensions', - 'sec-websocket-key', - 'sec-websocket-version', -]; -const defaultPassHeaders = [ - 'content-encoding', - 'content-length', - 'last-modified', -]; -// defaults if the client provides a cache key -const defaultCacheForwardHeaders = [ - 'if-modified-since', - 'if-none-match', - 'cache-control', -]; -const defaultCachePassHeaders = ['cache-control', 'etag']; -const cacheNotModified = 304; -function loadForwardedHeaders(forward, target, request) { - for (const header of forward) { - if (request.headers.has(header)) { - target[header] = request.headers.get(header); - } - } -} -const splitHeaderValue = /,\s*/g; -function readHeaders(request) { - const remote = Object.create(null); - const sendHeaders = Object.create(null); - const passHeaders = [...defaultPassHeaders]; - const passStatus = []; - const forwardHeaders = [...defaultForwardHeaders]; - // should be unique - const cache = request.url.searchParams.has('cache'); - if (cache) { - passHeaders.push(...defaultCachePassHeaders); - passStatus.push(cacheNotModified); - forwardHeaders.push(...defaultCacheForwardHeaders); - } - const headers = (0, splitHeaderUtil_js_1.joinHeaders)(request.headers); - for (const remoteProp of ['host', 'port', 'protocol', 'path']) { - const header = `x-bare-${remoteProp}`; - const value = headers.get(header); - if (value === null) - throw new BareServer_js_1.BareError(400, { - code: 'MISSING_BARE_HEADER', - id: `request.headers.${header}`, - message: `Header was not specified.`, - }); - switch (remoteProp) { - case 'port': - if (isNaN(parseInt(value))) { - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: `request.headers.${header}`, - message: `Header was not a valid integer.`, - }); - } - break; - case 'protocol': - if (!validProtocols.includes(value)) { - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: `request.headers.${header}`, - message: `Header was invalid`, - }); - } - break; - } - remote[remoteProp] = value; - } - const xBareHeaders = headers.get('x-bare-headers'); - if (xBareHeaders === null) - throw new BareServer_js_1.BareError(400, { - code: 'MISSING_BARE_HEADER', - id: `request.headers.x-bare-headers`, - message: `Header was not specified.`, - }); - try { - const json = JSON.parse(xBareHeaders); - for (const header in json) { - const value = json[header]; - if (typeof value === 'string') { - sendHeaders[header] = value; - } - else if (Array.isArray(value)) { - const array = []; - for (const val of value) { - if (typeof val !== 'string') { - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: `bare.headers.${header}`, - message: `Header was not a String.`, - }); - } - array.push(val); - } - sendHeaders[header] = array; - } - else - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: `bare.headers.${header}`, - message: `Header was not a String.`, - }); - } - } - catch (error) { - if (error instanceof SyntaxError) { - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: `request.headers.x-bare-headers`, - message: `Header contained invalid JSON. (${error.message})`, - }); - } - else { - throw error; - } - } - if (headers.has('x-bare-pass-status')) { - const parsed = headers.get('x-bare-pass-status').split(splitHeaderValue); - for (const value of parsed) { - const number = parseInt(value); - if (isNaN(number)) { - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: `request.headers.x-bare-pass-status`, - message: `Array contained non-number value.`, - }); - } - else { - passStatus.push(number); - } - } - } - if (headers.has('x-bare-pass-headers')) { - const parsed = headers.get('x-bare-pass-headers').split(splitHeaderValue); - for (let header of parsed) { - header = header.toLowerCase(); - if (forbiddenPassHeaders.includes(header)) { - throw new BareServer_js_1.BareError(400, { - code: 'FORBIDDEN_BARE_HEADER', - id: `request.headers.x-bare-forward-headers`, - message: `A forbidden header was passed.`, - }); - } - else { - passHeaders.push(header); - } - } - } - if (headers.has('x-bare-forward-headers')) { - const parsed = headers - .get('x-bare-forward-headers') - .split(splitHeaderValue); - for (let header of parsed) { - header = header.toLowerCase(); - if (forbiddenForwardHeaders.includes(header)) { - throw new BareServer_js_1.BareError(400, { - code: 'FORBIDDEN_BARE_HEADER', - id: `request.headers.x-bare-forward-headers`, - message: `A forbidden header was forwarded.`, - }); - } - else { - forwardHeaders.push(header); - } - } - } - return { - remote: (0, remoteUtil_js_1.remoteToURL)(remote), - sendHeaders, - passHeaders, - passStatus, - forwardHeaders, - }; -} -const tunnelRequest = async (request, res, options) => { - const abort = new AbortController(); - request.body.on('close', () => { - if (!request.body.complete) - abort.abort(); - }); - res.on('close', () => { - abort.abort(); - }); - const { remote, sendHeaders, passHeaders, passStatus, forwardHeaders } = readHeaders(request); - loadForwardedHeaders(forwardHeaders, sendHeaders, request); - const response = await (0, requestUtil_js_1.fetch)(request, abort.signal, sendHeaders, remote, options); - const responseHeaders = new headers_polyfill_1.Headers(); - for (const header of passHeaders) { - if (!(header in response.headers)) - continue; - responseHeaders.set(header, (0, headerUtil_js_1.flattenHeader)(response.headers[header])); - } - const status = passStatus.includes(response.statusCode) - ? response.statusCode - : 200; - if (status !== cacheNotModified) { - responseHeaders.set('x-bare-status', response.statusCode.toString()); - responseHeaders.set('x-bare-status-text', response.statusMessage); - responseHeaders.set('x-bare-headers', JSON.stringify((0, headerUtil_js_1.mapHeadersFromArray)((0, headerUtil_js_1.rawHeaderNames)(response.rawHeaders), { - ...response.headers, - }))); - } - return new AbstractMessage_js_1.Response(response, { - status, - headers: (0, splitHeaderUtil_js_1.splitHeaders)(responseHeaders), - }); -}; -const metaExpiration = 30e3; -const getMeta = async (request, res, options) => { - if (request.method === 'OPTIONS') { - return new AbstractMessage_js_1.Response(undefined, { status: 200 }); - } - const id = request.headers.get('x-bare-id'); - if (id === null) - throw new BareServer_js_1.BareError(400, { - code: 'MISSING_BARE_HEADER', - id: 'request.headers.x-bare-id', - message: 'Header was not specified', - }); - const meta = await options.database.get(id); - if (meta?.value.v !== 2) - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: 'request.headers.x-bare-id', - message: 'Unregistered ID', - }); - if (!meta.value.response) - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: 'request.headers.x-bare-id', - message: 'Meta not ready', - }); - await options.database.delete(id); - const responseHeaders = new headers_polyfill_1.Headers(); - responseHeaders.set('x-bare-status', meta.value.response.status.toString()); - responseHeaders.set('x-bare-status-text', meta.value.response.statusText); - responseHeaders.set('x-bare-headers', JSON.stringify(meta.value.response.headers)); - return new AbstractMessage_js_1.Response(undefined, { - status: 200, - headers: (0, splitHeaderUtil_js_1.splitHeaders)(responseHeaders), - }); -}; -const newMeta = async (request, res, options) => { - const { remote, sendHeaders, forwardHeaders } = readHeaders(request); - const id = (0, requestUtil_js_1.randomHex)(16); - await options.database.set(id, { - expires: Date.now() + metaExpiration, - value: { - v: 2, - remote: remote.toString(), - sendHeaders, - forwardHeaders, - }, - }); - return new AbstractMessage_js_1.Response(Buffer.from(id)); -}; -const tunnelSocket = async (request, socket, head, options) => { - const abort = new AbortController(); - request.body.on('close', () => { - if (!request.body.complete) - abort.abort(); - }); - socket.on('close', () => { - abort.abort(); - }); - if (!request.headers.has('sec-websocket-protocol')) { - socket.end(); - return; - } - const id = request.headers.get('sec-websocket-protocol'); - const meta = await options.database.get(id); - if (meta?.value.v !== 2) { - socket.end(); - return; - } - loadForwardedHeaders(meta.value.forwardHeaders, meta.value.sendHeaders, request); - const [remoteResponse, remoteSocket] = await (0, requestUtil_js_1.upgradeFetch)(request, abort.signal, meta.value.sendHeaders, new URL(meta.value.remote), options); - remoteSocket.on('close', () => { - socket.end(); - }); - socket.on('close', () => { - remoteSocket.end(); - }); - remoteSocket.on('error', (error) => { - if (options.logErrors) { - console.error('Remote socket error:', error); - } - socket.end(); - }); - socket.on('error', (error) => { - if (options.logErrors) { - console.error('Serving socket error:', error); - } - remoteSocket.end(); - }); - const remoteHeaders = new headers_polyfill_1.Headers(remoteResponse.headers); - meta.value.response = { - headers: (0, headerUtil_js_1.mapHeadersFromArray)((0, headerUtil_js_1.rawHeaderNames)(remoteResponse.rawHeaders), { - ...remoteResponse.headers, - }), - status: remoteResponse.statusCode, - statusText: remoteResponse.statusMessage, - }; - await options.database.set(id, meta); - const responseHeaders = [ - `HTTP/1.1 101 Switching Protocols`, - `Upgrade: websocket`, - `Connection: Upgrade`, - `Sec-WebSocket-Protocol: ${id}`, - ]; - if (remoteHeaders.has('sec-websocket-extensions')) { - responseHeaders.push(`Sec-WebSocket-Extensions: ${remoteHeaders.get('sec-websocket-extensions')}`); - } - if (remoteHeaders.has('sec-websocket-accept')) { - responseHeaders.push(`Sec-WebSocket-Accept: ${remoteHeaders.get('sec-websocket-accept')}`); - } - socket.write(responseHeaders.concat('', '').join('\r\n')); - remoteSocket.pipe(socket); - socket.pipe(remoteSocket); -}; -function registerV2(server) { - server.routes.set('/v2/', tunnelRequest); - server.routes.set('/v2/ws-new-meta', newMeta); - server.routes.set('/v2/ws-meta', getMeta); - server.socketRoutes.set('/v2/', tunnelSocket); - server.versions.push('v2'); -} -exports.default = registerV2; -//# sourceMappingURL=V2.js.map \ No newline at end of file diff --git a/lib/bare-server-modified/V3.d.ts b/lib/bare-server-modified/V3.d.ts deleted file mode 100644 index 53c098f..0000000 --- a/lib/bare-server-modified/V3.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -import type Server from './BareServer.js'; -export default function registerV3(server: Server): void; diff --git a/lib/bare-server-modified/V3.js b/lib/bare-server-modified/V3.js deleted file mode 100644 index 802bcb3..0000000 --- a/lib/bare-server-modified/V3.js +++ /dev/null @@ -1,305 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const headers_polyfill_1 = require("headers-polyfill"); -const AbstractMessage_js_1 = require("./AbstractMessage.js"); -const BareServer_js_1 = require("./BareServer.js"); -const headerUtil_js_1 = require("./headerUtil.js"); -const remoteUtil_js_1 = require("./remoteUtil.js"); -const requestUtil_js_1 = require("./requestUtil.js"); -const splitHeaderUtil_js_1 = require("./splitHeaderUtil.js"); -const forbiddenForwardHeaders = [ - 'connection', - 'transfer-encoding', - 'host', - 'connection', - 'origin', - 'referer', -]; -const forbiddenPassHeaders = [ - 'vary', - 'connection', - 'transfer-encoding', - 'access-control-allow-headers', - 'access-control-allow-methods', - 'access-control-expose-headers', - 'access-control-max-age', - 'access-control-request-headers', - 'access-control-request-method', -]; -// common defaults -const defaultForwardHeaders = ['accept-encoding', 'accept-language']; -const defaultPassHeaders = [ - 'content-encoding', - 'content-length', - 'last-modified', -]; -// defaults if the client provides a cache key -const defaultCacheForwardHeaders = [ - 'if-modified-since', - 'if-none-match', - 'cache-control', -]; -const defaultCachePassHeaders = ['cache-control', 'etag']; -const cacheNotModified = 304; -function loadForwardedHeaders(forward, target, request) { - for (const header of forward) { - if (request.headers.has(header)) { - target[header] = request.headers.get(header); - } - } -} -const splitHeaderValue = /,\s*/g; -function readHeaders(request) { - const sendHeaders = Object.create(null); - const passHeaders = [...defaultPassHeaders]; - const passStatus = []; - const forwardHeaders = [...defaultForwardHeaders]; - // should be unique - const cache = request.url.searchParams.has('cache'); - if (cache) { - passHeaders.push(...defaultCachePassHeaders); - passStatus.push(cacheNotModified); - forwardHeaders.push(...defaultCacheForwardHeaders); - } - const headers = (0, splitHeaderUtil_js_1.joinHeaders)(request.headers); - const xBareURL = headers.get('x-bare-url'); - if (xBareURL === null) - throw new BareServer_js_1.BareError(400, { - code: 'MISSING_BARE_HEADER', - id: `request.headers.x-bare-url`, - message: `Header was not specified.`, - }); - const remote = (0, remoteUtil_js_1.urlToRemote)(new URL(xBareURL)); - const xBareHeaders = headers.get('x-bare-headers'); - if (xBareHeaders === null) - throw new BareServer_js_1.BareError(400, { - code: 'MISSING_BARE_HEADER', - id: `request.headers.x-bare-headers`, - message: `Header was not specified.`, - }); - try { - const json = JSON.parse(xBareHeaders); - for (const header in json) { - const value = json[header]; - if (typeof value === 'string') { - sendHeaders[header] = value; - } - else if (Array.isArray(value)) { - const array = []; - for (const val of value) { - if (typeof val !== 'string') { - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: `bare.headers.${header}`, - message: `Header was not a String.`, - }); - } - array.push(val); - } - sendHeaders[header] = array; - } - else { - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: `bare.headers.${header}`, - message: `Header was not a String.`, - }); - } - } - } - catch (error) { - if (error instanceof SyntaxError) { - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: `request.headers.x-bare-headers`, - message: `Header contained invalid JSON. (${error.message})`, - }); - } - else { - throw error; - } - } - if (headers.has('x-bare-pass-status')) { - const parsed = headers.get('x-bare-pass-status').split(splitHeaderValue); - for (const value of parsed) { - const number = parseInt(value); - if (isNaN(number)) { - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: `request.headers.x-bare-pass-status`, - message: `Array contained non-number value.`, - }); - } - else { - passStatus.push(number); - } - } - } - if (headers.has('x-bare-pass-headers')) { - const parsed = headers.get('x-bare-pass-headers').split(splitHeaderValue); - for (let header of parsed) { - header = header.toLowerCase(); - if (forbiddenPassHeaders.includes(header)) { - throw new BareServer_js_1.BareError(400, { - code: 'FORBIDDEN_BARE_HEADER', - id: `request.headers.x-bare-forward-headers`, - message: `A forbidden header was passed.`, - }); - } - else { - passHeaders.push(header); - } - } - } - if (headers.has('x-bare-forward-headers')) { - const parsed = headers - .get('x-bare-forward-headers') - .split(splitHeaderValue); - for (let header of parsed) { - header = header.toLowerCase(); - if (forbiddenForwardHeaders.includes(header)) { - throw new BareServer_js_1.BareError(400, { - code: 'FORBIDDEN_BARE_HEADER', - id: `request.headers.x-bare-forward-headers`, - message: `A forbidden header was forwarded.`, - }); - } - else { - forwardHeaders.push(header); - } - } - } - return { - remote: (0, remoteUtil_js_1.remoteToURL)(remote), - sendHeaders, - passHeaders, - passStatus, - forwardHeaders, - }; -} -const tunnelRequest = async (request, res, options) => { - const abort = new AbortController(); - request.body.on('close', () => { - if (!request.body.complete) - abort.abort(); - }); - res.on('close', () => { - abort.abort(); - }); - const { remote, sendHeaders, passHeaders, passStatus, forwardHeaders } = readHeaders(request); - loadForwardedHeaders(forwardHeaders, sendHeaders, request); - const response = await (0, requestUtil_js_1.fetch)(request, abort.signal, sendHeaders, remote, options); - const responseHeaders = new headers_polyfill_1.Headers(); - for (const header of passHeaders) { - if (!(header in response.headers)) - continue; - responseHeaders.set(header, (0, headerUtil_js_1.flattenHeader)(response.headers[header])); - } - const status = passStatus.includes(response.statusCode) - ? response.statusCode - : 200; - if (status !== cacheNotModified) { - responseHeaders.set('x-bare-status', response.statusCode.toString()); - responseHeaders.set('x-bare-status-text', response.statusMessage); - responseHeaders.set('x-bare-headers', JSON.stringify((0, headerUtil_js_1.mapHeadersFromArray)((0, headerUtil_js_1.rawHeaderNames)(response.rawHeaders), { - ...response.headers, - }))); - } - return new AbstractMessage_js_1.Response(response, { - status, - headers: (0, splitHeaderUtil_js_1.splitHeaders)(responseHeaders), - }); -}; -function readSocket(socket) { - return new Promise((resolve, reject) => { - const messageListener = (event) => { - cleanup(); - if (typeof event.data !== 'string') - return reject(new TypeError('the first websocket message was not a text frame')); - try { - resolve(JSON.parse(event.data)); - } - catch (err) { - reject(err); - } - }; - const closeListener = () => { - cleanup(); - }; - const cleanup = () => { - socket.removeEventListener('message', messageListener); - socket.removeEventListener('close', closeListener); - clearTimeout(timeout); - }; - const timeout = setTimeout(() => { - cleanup(); - reject(new Error('Timed out before metadata could be read')); - }, 10e3); - socket.addEventListener('message', messageListener); - socket.addEventListener('close', closeListener); - }); -} -const tunnelSocket = async (request, socket, head, options) => options.wss.handleUpgrade(request.body, socket, head, async (client) => { - let _remoteSocket; - try { - const connectPacket = await readSocket(client); - if (connectPacket.type !== 'connect') - throw new Error('Client did not send open packet.'); - loadForwardedHeaders(connectPacket.forwardHeaders, connectPacket.headers, request); - const [remoteReq, remoteSocket] = await (0, requestUtil_js_1.webSocketFetch)(request, connectPacket.headers, new URL(connectPacket.remote), connectPacket.protocols, options); - _remoteSocket = remoteSocket; - const setCookieHeader = remoteReq.headers['set-cookie']; - const setCookies = setCookieHeader !== undefined - ? Array.isArray(setCookieHeader) - ? setCookieHeader - : [setCookieHeader] - : []; - client.send(JSON.stringify({ - type: 'open', - protocol: remoteSocket.protocol, - setCookies, - }), - // use callback to wait for this message to buffer and finally send before doing any piping - // otherwise the client will receive a random message from the remote before our open message - () => { - remoteSocket.addEventListener('message', (event) => { - client.send(event.data); - }); - client.addEventListener('message', (event) => { - remoteSocket.send(event.data); - }); - remoteSocket.addEventListener('close', () => { - client.close(); - }); - client.addEventListener('close', () => { - remoteSocket.close(); - }); - remoteSocket.addEventListener('error', (error) => { - if (options.logErrors) { - console.error('Remote socket error:', error); - } - client.close(); - }); - client.addEventListener('error', (error) => { - if (options.logErrors) { - console.error('Serving socket error:', error); - } - remoteSocket.close(); - }); - }); - } - catch (err) { - if (options.logErrors) - console.error(err); - client.close(); - if (_remoteSocket) - _remoteSocket.close(); - } -}); -function registerV3(server) { - server.routes.set('/v3/', tunnelRequest); - server.socketRoutes.set('/v3/', tunnelSocket); - server.versions.push('v3'); -} -exports.default = registerV3; -//# sourceMappingURL=V3.js.map \ No newline at end of file diff --git a/lib/bare-server-modified/createServer.d.ts b/lib/bare-server-modified/createServer.d.ts deleted file mode 100644 index 2838420..0000000 --- a/lib/bare-server-modified/createServer.d.ts +++ /dev/null @@ -1,52 +0,0 @@ -/// -/// -import { Agent as HttpAgent } from 'node:http'; -import { Agent as HttpsAgent } from 'node:https'; -import BareServer from './BareServer.js'; -import type { BareMaintainer, Options } from './BareServer.js'; -import type { Database } from './Meta.js'; -export declare const validIPFamily: number[]; -export type IPFamily = 0 | 4 | 6; -export interface BareServerInit { - logErrors?: boolean; - localAddress?: string; - /** - * When set, the default logic for blocking local IP addresses is disabled. - */ - filterRemote?: Options['filterRemote']; - /** - * When set, the default logic for blocking local IP addresses is disabled. - */ - lookup?: Options['lookup']; - /** - * If local IP addresses/DNS records should be blocked. - * @default true - */ - blockLocal?: boolean; - /** - * IP address family to use when resolving `host` or `hostname`. Valid values are `0`, `4`, and `6`. When unspecified/0, both IP v4 and v6 will be used. - */ - family?: IPFamily | number; - maintainer?: BareMaintainer; - httpAgent?: HttpAgent; - httpsAgent?: HttpsAgent; - /** - * If legacy clients should be supported (v1 & v2). If this is set to false, the database can be safely ignored. - * @default true - */ - legacySupport?: boolean; - database?: Database; -} -export interface Address { - address: string; - family: number; -} -/** - * Converts the address and family of a DNS lookup callback into an array if it wasn't already - */ -export declare function toAddressArray(address: string | Address[], family?: number): Address[]; -/** - * Create a Bare server. - * This will handle all lifecycles for unspecified options (httpAgent, httpsAgent, metaMap). - */ -export declare function createBareServer(directory: string, init?: BareServerInit): BareServer; diff --git a/lib/bare-server-modified/createServer.js b/lib/bare-server-modified/createServer.js deleted file mode 100644 index 695d300..0000000 --- a/lib/bare-server-modified/createServer.js +++ /dev/null @@ -1,99 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.createBareServer = exports.toAddressArray = exports.validIPFamily = void 0; -const node_dns_1 = require("node:dns"); -const node_http_1 = require("node:http"); -const node_https_1 = require("node:https"); -const ipaddr_js_1 = require("ipaddr.js"); -const ws_1 = require("ws"); -const BareServer_js_1 = __importDefault(require("./BareServer.js")); -const Meta_js_1 = require("./Meta.js"); -const V1_js_1 = __importDefault(require("./V1.js")); -const V2_js_1 = __importDefault(require("./V2.js")); -const V3_js_1 = __importDefault(require("./V3.js")); -exports.validIPFamily = [0, 4, 6]; -/** - * Converts the address and family of a DNS lookup callback into an array if it wasn't already - */ -function toAddressArray(address, family) { - if (typeof address === 'string') - return [ - { - address, - family, - }, - ]; - else - return address; -} -exports.toAddressArray = toAddressArray; -/** - * Create a Bare server. - * This will handle all lifecycles for unspecified options (httpAgent, httpsAgent, metaMap). - */ -function createBareServer(directory, init = {}) { - if (typeof directory !== 'string') - throw new Error('Directory must be specified.'); - if (!directory.startsWith('/') || !directory.endsWith('/')) - throw new RangeError('Directory must start and end with /'); - init.logErrors ??= false; - const cleanup = []; - if (typeof init.family === 'number' && !exports.validIPFamily.includes(init.family)) - throw new RangeError('init.family must be one of: 0, 4, 6'); - if (init.blockLocal ?? true) { - init.filterRemote ??= (url) => { - // if the remote is an IP then it didn't go through the init.lookup hook - // isValid determines if this is so - if ((0, ipaddr_js_1.isValid)(url.hostname) && (0, ipaddr_js_1.parse)(url.hostname).range() !== 'unicast') - throw new RangeError('Forbidden IP'); - }; - init.lookup ??= (hostname, options, callback) => (0, node_dns_1.lookup)(hostname, options, (err, address, family) => { - if (address && - toAddressArray(address, family).some(({ address }) => (0, ipaddr_js_1.parse)(address).range() !== 'unicast')) - callback(new RangeError('Forbidden IP'), '', -1); - else - callback(err, address, family); - }); - } - if (!init.httpAgent) { - const httpAgent = new node_http_1.Agent({ - keepAlive: true, - }); - init.httpAgent = httpAgent; - cleanup.push(() => httpAgent.destroy()); - } - if (!init.httpsAgent) { - const httpsAgent = new node_https_1.Agent({ - keepAlive: true, - }); - init.httpsAgent = httpsAgent; - cleanup.push(() => httpsAgent.destroy()); - } - if (!init.database) { - const database = new Map(); - const interval = setInterval(() => (0, Meta_js_1.cleanupDatabase)(database), 1000); - init.database = database; - cleanup.push(() => clearInterval(interval)); - } - const server = new BareServer_js_1.default(directory, { - ...init, - database: new Meta_js_1.JSONDatabaseAdapter(init.database), - wss: new ws_1.WebSocketServer({ noServer: true }), - }); - init.legacySupport ??= true; - if (init.legacySupport) { - (0, V1_js_1.default)(server); - (0, V2_js_1.default)(server); - } - (0, V3_js_1.default)(server); - server.once('close', () => { - for (const cb of cleanup) - cb(); - }); - return server; -} -exports.createBareServer = createBareServer; -//# sourceMappingURL=createServer.js.map \ No newline at end of file diff --git a/lib/bare-server-modified/encodeProtocol.d.ts b/lib/bare-server-modified/encodeProtocol.d.ts deleted file mode 100644 index 9468b7f..0000000 --- a/lib/bare-server-modified/encodeProtocol.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export declare function validProtocol(protocol: string): boolean; -export declare function encodeProtocol(protocol: string): string; -export declare function decodeProtocol(protocol: string): string; diff --git a/lib/bare-server-modified/encodeProtocol.js b/lib/bare-server-modified/encodeProtocol.js deleted file mode 100644 index cc9d769..0000000 --- a/lib/bare-server-modified/encodeProtocol.js +++ /dev/null @@ -1,48 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.decodeProtocol = exports.encodeProtocol = exports.validProtocol = void 0; -const validChars = "!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~"; -const reserveChar = '%'; -function validProtocol(protocol) { - for (let i = 0; i < protocol.length; i++) { - const char = protocol[i]; - if (!validChars.includes(char)) { - return false; - } - } - return true; -} -exports.validProtocol = validProtocol; -function encodeProtocol(protocol) { - let result = ''; - for (let i = 0; i < protocol.length; i++) { - const char = protocol[i]; - if (validChars.includes(char) && char !== reserveChar) { - result += char; - } - else { - const code = char.charCodeAt(0); - result += reserveChar + code.toString(16).padStart(2, '0'); - } - } - return result; -} -exports.encodeProtocol = encodeProtocol; -function decodeProtocol(protocol) { - let result = ''; - for (let i = 0; i < protocol.length; i++) { - const char = protocol[i]; - if (char === reserveChar) { - const code = parseInt(protocol.slice(i + 1, i + 3), 16); - const decoded = String.fromCharCode(code); - result += decoded; - i += 2; - } - else { - result += char; - } - } - return result; -} -exports.decodeProtocol = decodeProtocol; -//# sourceMappingURL=encodeProtocol.js.map \ No newline at end of file diff --git a/lib/bare-server-modified/headerUtil.d.ts b/lib/bare-server-modified/headerUtil.d.ts deleted file mode 100644 index ecac542..0000000 --- a/lib/bare-server-modified/headerUtil.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { BareHeaders } from './requestUtil.js'; -export declare function objectFromRawHeaders(raw: string[]): BareHeaders; -export declare function rawHeaderNames(raw: string[]): string[]; -export declare function mapHeadersFromArray(from: string[], to: BareHeaders): BareHeaders; -/** - * Converts a header into an HTTP-ready comma joined header. - */ -export declare function flattenHeader(value: string | string[]): string; diff --git a/lib/bare-server-modified/headerUtil.js b/lib/bare-server-modified/headerUtil.js deleted file mode 100644 index f9913e9..0000000 --- a/lib/bare-server-modified/headerUtil.js +++ /dev/null @@ -1,48 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.flattenHeader = exports.mapHeadersFromArray = exports.rawHeaderNames = exports.objectFromRawHeaders = void 0; -function objectFromRawHeaders(raw) { - const result = Object.create(null); - for (let i = 0; i < raw.length; i += 2) { - const [header, value] = raw.slice(i, i + 2); - if (header in result) { - const v = result[header]; - if (Array.isArray(v)) - v.push(value); - else - result[header] = [v, value]; - } - else - result[header] = value; - } - return result; -} -exports.objectFromRawHeaders = objectFromRawHeaders; -function rawHeaderNames(raw) { - const result = []; - for (let i = 0; i < raw.length; i += 2) { - if (!result.includes(raw[i])) - result.push(raw[i]); - } - return result; -} -exports.rawHeaderNames = rawHeaderNames; -function mapHeadersFromArray(from, to) { - for (const header of from) { - if (header.toLowerCase() in to) { - const value = to[header.toLowerCase()]; - delete to[header.toLowerCase()]; - to[header] = value; - } - } - return to; -} -exports.mapHeadersFromArray = mapHeadersFromArray; -/** - * Converts a header into an HTTP-ready comma joined header. - */ -function flattenHeader(value) { - return Array.isArray(value) ? value.join(', ') : value; -} -exports.flattenHeader = flattenHeader; -//# sourceMappingURL=headerUtil.js.map \ No newline at end of file diff --git a/lib/bare-server-modified/remoteUtil.d.ts b/lib/bare-server-modified/remoteUtil.d.ts deleted file mode 100644 index 1b317cb..0000000 --- a/lib/bare-server-modified/remoteUtil.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -export interface BareRemote { - host: string; - port: number | string; - path: string; - protocol: string; -} -export declare function remoteToURL(remote: BareRemote): URL; -export declare function resolvePort(url: URL): number; -export declare function urlToRemote(url: URL): BareRemote; diff --git a/lib/bare-server-modified/remoteUtil.js b/lib/bare-server-modified/remoteUtil.js deleted file mode 100644 index 71e8739..0000000 --- a/lib/bare-server-modified/remoteUtil.js +++ /dev/null @@ -1,36 +0,0 @@ -"use strict"; -/* - * Utilities for converting remotes to URLs - */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.urlToRemote = exports.resolvePort = exports.remoteToURL = void 0; -function remoteToURL(remote) { - return new URL(`${remote.protocol}${remote.host}:${remote.port}${remote.path}`); -} -exports.remoteToURL = remoteToURL; -function resolvePort(url) { - if (url.port) - return Number(url.port); - switch (url.protocol) { - case 'ws:': - case 'http:': - return 80; - case 'wss:': - case 'https:': - return 443; - default: - // maybe blob - return 0; - } -} -exports.resolvePort = resolvePort; -function urlToRemote(url) { - return { - protocol: url.protocol, - host: url.hostname, - port: resolvePort(url), - path: url.pathname + url.search, - }; -} -exports.urlToRemote = urlToRemote; -//# sourceMappingURL=remoteUtil.js.map \ No newline at end of file diff --git a/lib/bare-server-modified/requestUtil.d.ts b/lib/bare-server-modified/requestUtil.d.ts deleted file mode 100644 index 97e891f..0000000 --- a/lib/bare-server-modified/requestUtil.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -/// -/// -/// -import type { IncomingMessage } from 'node:http'; -import type { Duplex } from 'node:stream'; -import WebSocket from 'ws'; -import type { Request } from './AbstractMessage.js'; -import type { Options } from './BareServer.js'; -export type BareHeaders = Record; -export declare function randomHex(byteLength: number): string; -export declare function fetch(request: Request, signal: AbortSignal, requestHeaders: BareHeaders, remote: URL, options: Options): Promise; -export declare function upgradeFetch(request: Request, signal: AbortSignal, requestHeaders: BareHeaders, remote: URL, options: Options): Promise<[res: IncomingMessage, socket: Duplex, head: Buffer]>; -export declare function webSocketFetch(request: Request, requestHeaders: BareHeaders, remote: URL, protocols: string[], options: Options): Promise<[req: IncomingMessage, socket: WebSocket]>; diff --git a/lib/bare-server-modified/requestUtil.js b/lib/bare-server-modified/requestUtil.js deleted file mode 100644 index 792ad0c..0000000 --- a/lib/bare-server-modified/requestUtil.js +++ /dev/null @@ -1,185 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.webSocketFetch = exports.upgradeFetch = exports.fetch = exports.randomHex = void 0; -const node_crypto_1 = require("node:crypto"); -const node_http_1 = require("node:http"); -const node_https_1 = require("node:https"); -const ws_1 = __importDefault(require("ws")); -const BareServer_js_1 = require("./BareServer.js"); -function randomHex(byteLength) { - const bytes = new Uint8Array(byteLength); - (0, node_crypto_1.getRandomValues)(bytes); - let hex = ''; - for (const byte of bytes) - hex += byte.toString(16).padStart(2, '0'); - return hex; -} -exports.randomHex = randomHex; -function outgoingError(error) { - if (error instanceof Error) { - switch (error.code) { - case 'ENOTFOUND': - return new BareServer_js_1.BareError(500, { - code: 'HOST_NOT_FOUND', - id: 'request', - message: 'The specified host could not be resolved.', - }); - case 'ECONNREFUSED': - return new BareServer_js_1.BareError(500, { - code: 'CONNECTION_REFUSED', - id: 'response', - message: 'The remote rejected the request.', - }); - case 'ECONNRESET': - return new BareServer_js_1.BareError(500, { - code: 'CONNECTION_RESET', - id: 'response', - message: 'The request was forcibly closed.', - }); - case 'ETIMEOUT': - return new BareServer_js_1.BareError(500, { - code: 'CONNECTION_TIMEOUT', - id: 'response', - message: 'The response timed out.', - }); - } - } - return error; -} -async function fetch(request, signal, requestHeaders, remote, options) { - if (options.filterRemote) - await options.filterRemote(remote); - const req = { - method: request.method, - headers: requestHeaders, - setHost: false, - signal, - localAddress: options.localAddress, - family: options.family, - lookup: options.lookup, - }; - let outgoing; - // NodeJS will convert the URL into HTTP options automatically - // see https://github.com/nodejs/node/blob/e30e71665cab94118833cc536a43750703b19633/lib/internal/url.js#L1277 - if (remote.protocol === 'https:') - outgoing = (0, node_https_1.request)(remote, { - ...req, - agent: options.httpsAgent, - }); - else if (remote.protocol === 'http:') - outgoing = (0, node_http_1.request)(remote, { - ...req, - agent: options.httpAgent, - }); - else - throw new RangeError(`Unsupported protocol: '${remote.protocol}'`); - request.body.pipe(outgoing); - return await new Promise((resolve, reject) => { - outgoing.on('response', (response) => { - resolve(response); - }); - outgoing.on('upgrade', (req, socket) => { - reject('Remote did not send a response'); - socket.destroy(); - }); - outgoing.on('error', (error) => { - reject(outgoingError(error)); - }); - }); -} -exports.fetch = fetch; -async function upgradeFetch(request, signal, requestHeaders, remote, options) { - if (options.filterRemote) - await options.filterRemote(remote); - const req = { - headers: requestHeaders, - method: request.method, - timeout: 12e3, - setHost: false, - signal, - localAddress: options.localAddress, - family: options.family, - lookup: options.lookup, - }; - let outgoing; - // NodeJS will convert the URL into HTTP options automatically - // see https://github.com/nodejs/node/blob/e30e71665cab94118833cc536a43750703b19633/lib/internal/url.js#L1277 - // calling .replace on remote may look like it replaces other occurrences of wss:, but it only replaces the first which is remote.protocol - if (remote.protocol === 'wss:') - outgoing = (0, node_https_1.request)(remote.toString().replace('wss:', 'https:'), { - ...req, - agent: options.httpsAgent, - }); - else if (remote.protocol === 'ws:') - outgoing = (0, node_http_1.request)(remote.toString().replace('ws:', 'http:'), { - ...req, - agent: options.httpAgent, - }); - else - throw new RangeError(`Unsupported protocol: '${remote.protocol}'`); - outgoing.end(); - return await new Promise((resolve, reject) => { - outgoing.on('response', (res) => { - reject(new Error('Remote did not upgrade the WebSocket')); - res.destroy(); - }); - outgoing.on('upgrade', (res, socket, head) => { - resolve([res, socket, head]); - }); - outgoing.on('error', (error) => { - reject(outgoingError(error)); - }); - }); -} -exports.upgradeFetch = upgradeFetch; -async function webSocketFetch(request, requestHeaders, remote, protocols, options) { - if (options.filterRemote) - await options.filterRemote(remote); - const req = { - headers: requestHeaders, - method: request.method, - timeout: 12e3, - setHost: false, - localAddress: options.localAddress, - family: options.family, - lookup: options.lookup, - }; - let outgoing; - if (remote.protocol === 'wss:') - outgoing = new ws_1.default(remote, protocols, { - ...req, - agent: options.httpsAgent, - }); - else if (remote.protocol === 'ws:') - outgoing = new ws_1.default(remote, protocols, { - ...req, - agent: options.httpAgent, - }); - else - throw new RangeError(`Unsupported protocol: '${remote.protocol}'`); - return await new Promise((resolve, reject) => { - let request; - const cleanup = () => { - outgoing.removeEventListener('open', openListener); - outgoing.removeEventListener('open', openListener); - }; - outgoing.on('upgrade', (req) => { - request = req; - }); - const openListener = () => { - cleanup(); - resolve([request, outgoing]); - }; - const errorListener = (event) => { - cleanup(); - reject(outgoingError(event.error)); - }; - outgoing.addEventListener('open', openListener); - outgoing.addEventListener('error', errorListener); - }); -} -exports.webSocketFetch = webSocketFetch; -//# sourceMappingURL=requestUtil.js.map \ No newline at end of file diff --git a/lib/bare-server-modified/splitHeaderUtil.d.ts b/lib/bare-server-modified/splitHeaderUtil.d.ts deleted file mode 100644 index ed9a454..0000000 --- a/lib/bare-server-modified/splitHeaderUtil.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Headers } from 'headers-polyfill'; -/** - * - * Splits headers according to spec - * @param headers - * @returns Split headers - */ -export declare function splitHeaders(headers: Headers): Headers; -/** - * Joins headers according to spec - * @param headers - * @returns Joined headers - */ -export declare function joinHeaders(headers: Headers): Headers; diff --git a/lib/bare-server-modified/splitHeaderUtil.js b/lib/bare-server-modified/splitHeaderUtil.js deleted file mode 100644 index 26baa27..0000000 --- a/lib/bare-server-modified/splitHeaderUtil.js +++ /dev/null @@ -1,60 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.joinHeaders = exports.splitHeaders = void 0; -const headers_polyfill_1 = require("headers-polyfill"); -const BareServer_js_1 = require("./BareServer.js"); -const MAX_HEADER_VALUE = 3072; -/** - * - * Splits headers according to spec - * @param headers - * @returns Split headers - */ -function splitHeaders(headers) { - const output = new headers_polyfill_1.Headers(headers); - if (headers.has('x-bare-headers')) { - const value = headers.get('x-bare-headers'); - if (value.length > MAX_HEADER_VALUE) { - output.delete('x-bare-headers'); - let split = 0; - for (let i = 0; i < value.length; i += MAX_HEADER_VALUE) { - const part = value.slice(i, i + MAX_HEADER_VALUE); - const id = split++; - output.set(`x-bare-headers-${id}`, `;${part}`); - } - } - } - return output; -} -exports.splitHeaders = splitHeaders; -/** - * Joins headers according to spec - * @param headers - * @returns Joined headers - */ -function joinHeaders(headers) { - const output = new headers_polyfill_1.Headers(headers); - const prefix = 'x-bare-headers'; - if (headers.has(`${prefix}-0`)) { - const join = []; - for (const [header, value] of headers) { - if (!header.startsWith(prefix)) { - continue; - } - if (!value.startsWith(';')) { - throw new BareServer_js_1.BareError(400, { - code: 'INVALID_BARE_HEADER', - id: `request.headers.${header}`, - message: `Value didn't begin with semi-colon.`, - }); - } - const id = parseInt(header.slice(prefix.length + 1)); - join[id] = value.slice(1); - output.delete(header); - } - output.set(prefix, join.join('')); - } - return output; -} -exports.joinHeaders = joinHeaders; -//# sourceMappingURL=splitHeaderUtil.js.map \ No newline at end of file diff --git a/server/index.js b/server/index.js index e326d66..cf79443 100644 --- a/server/index.js +++ b/server/index.js @@ -1,4 +1,4 @@ -import { createBareServer } from '@tomphttp/bare-server-node'; +import { createBareServer } from '../lib/bare-server-modified/createServer.cjs'; import express from 'express'; import mime from 'mime'; import cors from 'cors';