Functional

This commit is contained in:
bingus_violet 2024-07-13 05:53:26 -05:00
parent 2fc92cedd4
commit 9ece56849d
12 changed files with 411 additions and 8 deletions

1
.gitignore vendored
View file

@ -130,3 +130,4 @@ dist
.yarn/install-state.gz
.pnp.*
/data

View file

@ -1,14 +1,17 @@
const express = require("express"),
path = require("path")
bodyParser = require("body-parser"),
paths = require("./fileHandler.js").paths
const PORT = process.env.PORT || 8080
const app = express()
const staticPath = path.join(__dirname, "static")
app.use(express.static(staticPath))
app.use(express.static(paths.static))
app.listen(PORT, () => {
console.log("QuickURL now listening for PORT: " + PORT)
})
})
module.exports = {
app: app
}

69
fileHandler.js Normal file
View file

@ -0,0 +1,69 @@
const path = require("path"),
chokidar = require("chokidar"),
fs = require("fs")
var paths = {
static: path.join(__dirname, "static"),
postUrl: path.join(__dirname, "resources/html/postUrl.html"),
redirWarn: path.join(__dirname, "resources/html/redirWarn.html"),
data: path.join(__dirname, "data"),
config: path.join(__dirname, "data/config.json"),
defaultConfig: path.join(__dirname, "resources/json/config.json"),
urls: path.join(__dirname, "data/urls.json")
}
module.exports = {
paths,
config: undefined,
urls: [],
writeUrls: function (props) {
var urls = module.exports.urls
props.shortCode = 0
for (var i in urls) {
props.shortCode = urls[i].shortCode + 1
}
if (props.shortCode > 100000) {
props.shortCode = 0
}
urls.push(props)
var expirePoint = 0
for (var i in urls) {
var url = urls[i]
if (url.expire < Date.now()) {
expirePoint = i
continue
}
}
urls.splice(0, expirePoint)
fs.writeFileSync(paths.urls, JSON.stringify(module.exports.urls))
return props
}
}
var currentConfig = JSON.parse(fs.readFileSync(paths.config))
var defaultConfig = JSON.parse(fs.readFileSync(paths.defaultConfig))
currentConfig = Object.assign({}, defaultConfig, currentConfig)
fs.writeFileSync(paths.config, JSON.stringify(currentConfig))
var watcher = chokidar.watch(paths.data)
function dataUpdate() {
module.exports.config = JSON.parse(fs.readFileSync(paths.config))
}
watcher
.on("change", dataUpdate)
.on("add", dataUpdate)
if (!fs.existsSync(paths.urls)) {
fs.writeFileSync(paths.urls, "[]")
}
module.exports.urls = JSON.parse(fs.readFileSync(paths.urls))

View file

@ -1 +1,3 @@
require("./expressHandler.js")
require("./fileHandler.js")
require("./expressHandler.js")
require("./shortener.js")

187
package-lock.json generated
View file

@ -9,6 +9,7 @@
"version": "0.0.1",
"license": "Unlicense",
"dependencies": {
"chokidar": "^3.6.0",
"express": "^4.19.2"
}
},
@ -25,12 +26,37 @@
"node": ">= 0.6"
}
},
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"license": "ISC",
"dependencies": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
"license": "MIT"
},
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
"license": "MIT",
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/body-parser": {
"version": "1.20.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
@ -55,6 +81,18 @@
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@ -83,6 +121,30 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"license": "MIT",
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
"glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.6.0"
},
"engines": {
"node": ">= 8.10.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
@ -257,6 +319,18 @@
"node": ">= 0.10.0"
}
},
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/finalhandler": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
@ -293,6 +367,20 @@
"node": ">= 0.6"
}
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@ -321,6 +409,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/gopd": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
@ -424,6 +524,48 @@
"node": ">= 0.10"
}
},
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"license": "MIT",
"dependencies": {
"binary-extensions": "^2.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"license": "MIT",
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@ -496,6 +638,15 @@
"node": ">= 0.6"
}
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/object-inspect": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
@ -535,6 +686,18 @@
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
"license": "MIT"
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"license": "MIT",
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@ -587,6 +750,18 @@
"node": ">= 0.8"
}
},
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"license": "MIT",
"dependencies": {
"picomatch": "^2.2.1"
},
"engines": {
"node": ">=8.10.0"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@ -708,6 +883,18 @@
"node": ">= 0.8"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},
"engines": {
"node": ">=8.0"
}
},
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",

View file

@ -1,6 +1,6 @@
{
"name": "quickurl",
"version": "0.0.1",
"version": "1.0.0",
"description": "An extremely generic privacy & security focused URL shortener.",
"main": "index.js",
"scripts": {
@ -14,6 +14,7 @@
"author": "Violet",
"license": "Unlicense",
"dependencies": {
"chokidar": "^3.6.0",
"express": "^4.19.2"
}
}

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/style.css">
<title>QuickURL</title>
</head>
<body>
<div class="mainDiv">
<h1>QuickURL<hr></h1>
{CONTENT}
<a href="/">Go Back</a>
</div>
</body>
</html>

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/style.css">
<title>QuickURL</title>
</head>
<body>
<div class="mainDiv">
<h1>QuickURL<hr></h1>
<p>This link redirects you to: <br>{REDIRECT_URL}<br> Are you sure you want to continue?</p>
<a href="{REDIRECT_URL}">Continue</a>
</div>
</body>
</html>

View file

@ -0,0 +1,4 @@
{
"trust": [],
"blacklist": []
}

88
shortener.js Normal file
View file

@ -0,0 +1,88 @@
const expressHandler = require("./expressHandler"),
fileHandler = require("./fileHandler.js")
paths = fileHandler.paths,
fs = require("fs")
const app = expressHandler.app
app.get("/makeURL", (req, res) => {
function writep(inp) {
return res.write("<p>" + inp + "</p>")
}
function finishHtml() {
res.write(html.substring(html.indexOf("{CONTENT}") + 9), () => {
res.end()
})
}
res.setHeader("X-Accel-Buffering", "no")
var html = fs.readFileSync(paths.postUrl).toString()
res.write(html.substring(0, html.indexOf("{CONTENT}")))
var config = fileHandler.config
writep("HTML Loaded.")
var url = req.query.url.toLowerCase()
if (!url.includes("http://") && !url.includes("https://")) {
writep("Error: URL is missing protocol! Please include http:// or https:// in the URL for it to be valid.")
finishHtml()
return
}
var domain = url.substring(url.indexOf("://") + 3)
if (domain.charAt(-1) != "/") {
domain += "/"
}
domain = domain.substring(0, domain.indexOf("/"))
domain = domain.substring(domain.lastIndexOf(".", domain.lastIndexOf(".") - 1) + 1)
writep("Input URL: " + url)
writep("Domain: " + domain)
var trust = config.trust.includes(domain)
var blacklisted = config.blacklist.includes(domain)
writep("Domain on blacklist: " + blacklisted)
writep("Domain on trust list: " + trust)
if (blacklisted) {
writep("Error: Domain found on the blacklist! This URL is not allowed.")
finishHtml()
return
}
var shortURL = fileHandler.writeUrls({
"trusted": trust,
"expire": Date.now() + (7 * 24 * 60 * 60 * 1000),
"url": url
})
writep(`Done! Find your URL at: <a href="/url/${shortURL.shortCode}">${req.hostname + "/url/" + shortURL.shortCode}</a>`)
finishHtml()
})
app.get("/url/:shortCode*", (req, res) => {
var shortCode = req.params.shortCode
var urls = fileHandler.urls
for (var i in urls) {
var data = urls[i]
if (data.shortCode == shortCode) {
if (data.trusted) {
res.redirect(data.url)
} else {
var html = fs.readFileSync(paths.redirWarn).toString()
html = html.replaceAll("{REDIRECT_URL}", data.url)
res.send(html)
}
continue
}
}
})

View file

@ -19,7 +19,7 @@
<div class="mainDiv">
<h1>QuickURL<hr></h1>
<form action="/makeURL" method="post">
<form action="/makeURL" method="get">
<input required type="url" id="url" placeholder="Enter URL" name="url">
<br><br>

View file

@ -89,4 +89,8 @@ input[type="url"] {
select:hover,
input:hover {
border-color: var(--text-color)
}
a {
color: rgb(125, 125, 255)
}