Initial Commit
This commit is contained in:
commit
ac3d214b26
11
http-proxy.code-workspace
Normal file
11
http-proxy.code-workspace
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "proxy"
|
||||
},
|
||||
{
|
||||
"path": "ui"
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
}
|
136
proxy/.gitignore
vendored
Normal file
136
proxy/.gitignore
vendored
Normal file
@ -0,0 +1,136 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# vitepress build output
|
||||
**/.vitepress/dist
|
||||
|
||||
# vitepress cache directory
|
||||
**/.vitepress/cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
9
proxy/eslint.config.js
Normal file
9
proxy/eslint.config.js
Normal file
@ -0,0 +1,9 @@
|
||||
import globals from "globals";
|
||||
import pluginJs from "@eslint/js";
|
||||
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
{languageOptions: { globals: globals.node }},
|
||||
pluginJs.configs.recommended,
|
||||
];
|
4
proxy/examples/route.json
Normal file
4
proxy/examples/route.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"url": "backwards.dev",
|
||||
"server": "localhost:3000"
|
||||
}
|
2529
proxy/package-lock.json
generated
Normal file
2529
proxy/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
28
proxy/package.json
Normal file
28
proxy/package.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "proxy",
|
||||
"version": "1.0.0",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"dev": "nodemon .",
|
||||
"start": "NODE_ENV=\"PRODUCTION\" nodemon ."
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Backwards",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"chalk": "^5.4.1",
|
||||
"dotenv": "^16.4.7",
|
||||
"ejs": "^3.1.10",
|
||||
"express": "^4.21.2",
|
||||
"mongodb": "^6.14.2",
|
||||
"nodemon": "^3.1.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.21.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^9.21.0",
|
||||
"globals": "^16.0.0"
|
||||
}
|
||||
}
|
13
proxy/src/common.js
Normal file
13
proxy/src/common.js
Normal file
@ -0,0 +1,13 @@
|
||||
import { dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
export const __filename = fileURLToPath(import.meta.url);
|
||||
export const __dirname = dirname(__filename);
|
||||
|
||||
export function getDateTime() {
|
||||
return new Intl.DateTimeFormat('en-GB', {
|
||||
day: '2-digit', month: '2-digit', year: 'numeric',
|
||||
hour: '2-digit', minute: '2-digit', second: '2-digit',
|
||||
hour12: false
|
||||
}).format(new Date()).replace(',', '');
|
||||
}
|
6
proxy/src/data/down_codes.json
Normal file
6
proxy/src/data/down_codes.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"codes": [
|
||||
"500",
|
||||
"503"
|
||||
]
|
||||
}
|
19
proxy/src/data/messages.json
Normal file
19
proxy/src/data/messages.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"200": {
|
||||
"200": "Success!"
|
||||
},
|
||||
"400": {
|
||||
"400": "It seems we weren't prepared for that request.\nPlease try that another way...",
|
||||
"401": "It seems you aren't authenticated.\nTry authenticating and trying this request again.",
|
||||
"403": "It seems you don't have permission to access this.",
|
||||
"404": "It seems what you're looking for doesn't exist.\nCheck the URL or resource and try again.",
|
||||
"405": "The request method isn't allowed for this resource.\nCheck the API documentation for supported methods.",
|
||||
"408": "The request took too long to complete.\nPlease try again later."
|
||||
},
|
||||
"500": {
|
||||
"500": "Something went wrong on our end.\nTry again later or contact support if the issue persists.",
|
||||
"502": "Bad gateway.\nThe server received an invalid response from an upstream server.",
|
||||
"503": "The server is temporarily unavailable.\nPlease try again later.",
|
||||
"504": "Gateway timeout.\nThe server took too long to respond."
|
||||
}
|
||||
}
|
48
proxy/src/functions/app.js
Normal file
48
proxy/src/functions/app.js
Normal file
@ -0,0 +1,48 @@
|
||||
import { consoleFunctions } from "./console.js";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { MongoClient } from "mongodb";
|
||||
import dotenv from "dotenv";
|
||||
import { join } from "node:path";
|
||||
|
||||
import { __dirname } from "../common.js";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
export const appFunctions = {
|
||||
dbClient: new MongoClient(process.env.NODE_ENV == "PRODUCTION" ? process.env.MONGO_CONNECTION_STRING : process.env.MONGO_CONNECTION_STRING_DEV),
|
||||
async appInit(prod, port) {
|
||||
console.clear();
|
||||
|
||||
if (!this.dbClient || !this.dbClient.db)
|
||||
await this.dbClient.connect();
|
||||
const collection = this.dbClient.db("HTTP-Proxy").collection("Routes");
|
||||
const documents = await collection.find().toArray();
|
||||
|
||||
const routes = [];
|
||||
|
||||
documents.forEach((document, index) => {
|
||||
routes.push(`${index + 1}. From: ${document.url}, to ${document.server}.`);
|
||||
});
|
||||
|
||||
await this.dbClient.close();
|
||||
|
||||
console.log(consoleFunctions.init(prod, port, routes));
|
||||
|
||||
},
|
||||
findErrorRoute: (routes) => {
|
||||
console.log(routes);
|
||||
},
|
||||
messageFromCode: (code) => {
|
||||
const data = JSON.parse(readFileSync(join(__dirname, "data", "messages.json")));
|
||||
const codeClass = code.toString().split("").shift().padEnd("3", 0);
|
||||
return data[codeClass][code].replace("\n", "<br>");
|
||||
},
|
||||
sendError: async (code, res) => {
|
||||
console.log(code)
|
||||
if (code.toString().startsWith("/")) code = code.slice(0, 1);
|
||||
console.log(code)
|
||||
if (!code.toString().startsWith(5)) return res.redirect(`https://err.backwardshosting.ca/${code}`);
|
||||
const message = appFunctions.messageFromCode(code);
|
||||
res.render("index", { code, message });
|
||||
}
|
||||
}
|
32
proxy/src/functions/console.js
Normal file
32
proxy/src/functions/console.js
Normal file
@ -0,0 +1,32 @@
|
||||
import chalk from "chalk"
|
||||
import { getDateTime } from "../common.js"
|
||||
|
||||
const primary = chalk.cyan,
|
||||
bgPrimary = chalk.whiteBright.bgCyan,
|
||||
secondary = chalk.blue;
|
||||
|
||||
export const consoleFunctions = {
|
||||
ruler: () => "-".repeat(process.stdout.columns),
|
||||
init: function (prod, port, routes) {
|
||||
let output = [];
|
||||
if (!prod) {
|
||||
output.push(bgPrimary("DEVELOPMENT"));
|
||||
} else {
|
||||
output.push(bgPrimary("PRODUCTION"));
|
||||
}
|
||||
output.push(primary(`Proxy listening on port`) + " " + secondary.underline(port));
|
||||
output.push("");
|
||||
output.push(primary("Web Proxies"));
|
||||
output.push(routes.join("\n"));
|
||||
output.push("");
|
||||
output.push(primary("API Proxies"));
|
||||
output.push("...");
|
||||
output.push("");
|
||||
output.push("Logs");
|
||||
output.push(this.ruler());
|
||||
return output.join("\r\n")
|
||||
},
|
||||
log: function (content) {
|
||||
console.log(`(${getDateTime()}) ${content}`);
|
||||
}
|
||||
}
|
42
proxy/src/index.js
Normal file
42
proxy/src/index.js
Normal file
@ -0,0 +1,42 @@
|
||||
import { join } from "node:path";
|
||||
import express from"express";
|
||||
|
||||
import { __dirname } from "./common.js";
|
||||
import { appFunctions } from "./functions/app.js";
|
||||
import { consoleFunctions } from "./functions/console.js";
|
||||
|
||||
const app = express();
|
||||
const prod = process.env.NODE_ENV === "PRODUCTION";
|
||||
|
||||
const port = (prod) ? 80 : 2025; // Port 80 (HTTP) or 2025 in development.
|
||||
|
||||
app.listen(port, () => appFunctions.appInit(prod, port)); // Redirect console messages to dedicated consoleFunctions module.
|
||||
|
||||
app.set('view engine', 'ejs');
|
||||
app.set('views', join(__dirname, "view"));
|
||||
|
||||
|
||||
app.use(async function (req, res) {
|
||||
consoleFunctions.log("RECEIVED HTTP REQUEST");
|
||||
consoleFunctions.log("GETTING ROUTES FROM DATABASE");
|
||||
await appFunctions.dbClient.connect();
|
||||
const collection = appFunctions.dbClient.db("HTTP-Proxy").collection("Routes");
|
||||
const routes = await collection.find().toArray();
|
||||
await appFunctions.dbClient.close();
|
||||
|
||||
consoleFunctions.log(`REQUESTED: ${req.headers.host}`);
|
||||
const errorRoutes = routes.filter(route => route.url === req.headers.host && route.server === "ERROR");
|
||||
if (errorRoutes.length > 0) {
|
||||
appFunctions.sendError(req.url, res);
|
||||
}
|
||||
|
||||
|
||||
if (!routes) {
|
||||
appFunctions.sendError(500, res);
|
||||
}
|
||||
|
||||
appFunctions.findErrorRoute(routes);
|
||||
appFunctions.sendError(501, res);
|
||||
|
||||
|
||||
});
|
45
proxy/src/view/index.ejs
Normal file
45
proxy/src/view/index.ejs
Normal file
@ -0,0 +1,45 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-evenly;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
height: 100vh;
|
||||
background-image: linear-gradient(45deg, #1f1f24, #200d30);
|
||||
}
|
||||
|
||||
.content > * {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: "Poppins", sans-serif;
|
||||
color: white;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 6em;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 2em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="content">
|
||||
<h1><%= code %></h1>
|
||||
<h3><%- message %></h3>
|
||||
</div>
|
||||
<div class="spacer"></div>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user