diff --git a/.gitignore b/.gitignore index e3a97cd..28f2860 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /node_modules -/db \ No newline at end of file +/db +/uploads \ No newline at end of file diff --git a/db.js b/db.js new file mode 100644 index 0000000..739bb16 --- /dev/null +++ b/db.js @@ -0,0 +1,28 @@ +import sqlite3 from 'sqlite3' +import { open } from 'sqlite' + +let db; + +const sql = `CREATE TABLE IF NOT EXISTS auth (username TEXT, password TEXT); +CREATE TABLE IF NOT EXISTS token (username TEXT, token TEXT); +CREATE TABLE IF NOT EXISTS feeder (parentType TEXT, parentId TEXT, childType text, childId TEXT, sortId REAL); +CREATE TABLE IF NOT EXISTS comment (username TEXT, date REAL, content TEXT, id TEXT);` + +async function initDb() { + if (db) return db; + + db = await open({ + filename: `${process.cwd()}/db/main.db`, + driver: sqlite3.Database + }); + + let sqlCmds = sql.split('\n'); + + for (let cmd of sqlCmds) { + await db.run(cmd); + } + + return db; +} + +export { initDb }; \ No newline at end of file diff --git a/index.js b/index.js index 92b9268..1159b1a 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ import express from "express"; -import { doInit } from "./init.js"; +import { doInit } from "./routes/init.js"; const app = express() const port = 3000; @@ -12,4 +12,6 @@ app.listen(port, () => { console.log(`Example app listening on port ${port}`) }) -doInit(app); \ No newline at end of file +doInit(app); + +// TODO: rate limit stuff \ No newline at end of file diff --git a/init.js b/init.js deleted file mode 100644 index 303a3db..0000000 --- a/init.js +++ /dev/null @@ -1,55 +0,0 @@ -import { importRouters } from "./lib.js"; - -const aliases = { - '/': '/walls/get/home' -}; - -const routers = { - '/you': './you.js' -} - -function doAliases(app) { - for (let alias in aliases) { - app.all(alias, (req, res, next) => { - res.redirect(aliases[alias]) - }) - } -} - -async function doInit(app) { - app.use((req, res, next) => { - let headerCtx = [ - { link: '/walls/get/home', icon: '/icon.svg', name: 'DervNet' }, - { link: '/walls/list', icon: '/walls.svg', name: 'Explore' }, - { link: '/you/logout', icon: '/logout.svg', name: 'Leave' } // fix icon - ]; - - if (!res.auth || !res.auth.valid) { - headerCtx = [ - { link: '/walls/get/home', icon: '/icon.svg', name: 'DervNet' }, - { link: '/you/login', icon: '/walls.svg', name: 'Log in' } - ]; - } - - res.ctx = { - mainPage: '404.ejs', - mainCtx: {}, - headerCtx - }; - next(); - }) - - doAliases(app); - - await importRouters(app,routers); - - app.use('/api', (req, res, next) => { - res.send(res.ctx); - }) - - app.use((req, res, next) => { - res.render('root.ejs', res.ctx) - }) -} - -export { doInit }; \ No newline at end of file diff --git a/lib.js b/lib.js index f77c0fd..c477aef 100644 --- a/lib.js +++ b/lib.js @@ -1,8 +1,12 @@ async function importRouters(app, routers) { for (let router in routers) { - console.log(router) await app.use(router, (await import(routers[router])).default) } } -export { importRouters }; \ No newline at end of file +function apiStat(res, next, message, success = false, redirect = '/') { + res.api = { success, message, redirect }; + next(); +} + +export { importRouters, apiStat }; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 41efa95..a844107 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,8 @@ "version": "1.0.0", "license": "GPL-3.0-or-later", "dependencies": { + "bcrypt": "^5.1.1", + "cookie-parser": "^1.4.7", "ejs": "^3.1.10", "express": "^4.21.2", "multer": "^1.4.5-lts.1", @@ -23,6 +25,88 @@ "license": "MIT", "optional": true }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "license": "BSD-3-Clause", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/@npmcli/fs": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", @@ -76,8 +160,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/accepts": { "version": "1.3.8", @@ -97,7 +180,6 @@ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "license": "MIT", - "optional": true, "dependencies": { "debug": "4" }, @@ -110,7 +192,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "license": "MIT", - "optional": true, "dependencies": { "ms": "^2.1.3" }, @@ -127,8 +208,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/agentkeepalive": { "version": "4.6.0", @@ -162,7 +242,6 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", - "optional": true, "engines": { "node": ">=8" } @@ -192,8 +271,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/are-we-there-yet": { "version": "3.0.1", @@ -263,6 +341,26 @@ ], "license": "MIT" }, + "node_modules/bcrypt": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", + "integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.11", + "node-addon-api": "^5.0.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/bcrypt/node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", + "license": "MIT" + }, "node_modules/bindings": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", @@ -511,7 +609,6 @@ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "license": "ISC", - "optional": true, "bin": { "color-support": "bin.js" } @@ -541,8 +638,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/content-disposition": { "version": "0.5.4", @@ -574,6 +670,28 @@ "node": ">= 0.6" } }, + "node_modules/cookie-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "license": "MIT", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -623,8 +741,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/depd": { "version": "2.0.0", @@ -693,8 +810,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/encodeurl": { "version": "2.0.0", @@ -948,8 +1064,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/function-bind": { "version": "1.1.2", @@ -1030,7 +1145,6 @@ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", "license": "ISC", - "optional": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1090,8 +1204,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/hasown": { "version": "2.0.2", @@ -1173,7 +1286,6 @@ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "license": "MIT", - "optional": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -1187,7 +1299,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "license": "MIT", - "optional": true, "dependencies": { "ms": "^2.1.3" }, @@ -1204,8 +1315,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/humanize-ms": { "version": "1.2.1", @@ -1282,7 +1392,6 @@ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "license": "ISC", - "optional": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -1328,7 +1437,6 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "license": "MIT", - "optional": true, "engines": { "node": ">=8" } @@ -1391,6 +1499,30 @@ "node": ">=10" } }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/make-fetch-happen": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", @@ -1691,6 +1823,26 @@ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "license": "MIT" }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-gyp": { "version": "8.4.1", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", @@ -1721,7 +1873,6 @@ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", "license": "ISC", - "optional": true, "dependencies": { "abbrev": "1" }, @@ -1821,7 +1972,6 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } @@ -1999,7 +2149,6 @@ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "license": "ISC", - "optional": true, "dependencies": { "glob": "^7.1.3" }, @@ -2106,8 +2255,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/setprototypeof": { "version": "1.2.0", @@ -2191,8 +2339,7 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/simple-concat": { "version": "1.0.1", @@ -2392,7 +2539,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", - "optional": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2407,7 +2553,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", - "optional": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2531,6 +2676,12 @@ "node": ">=0.6" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -2615,6 +2766,22 @@ "node": ">= 0.8" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2636,7 +2803,6 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "license": "ISC", - "optional": true, "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } diff --git a/package.json b/package.json index b92f44e..3a5c814 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,8 @@ "author": "BiglyDerv", "license": "GPL-3.0-or-later", "dependencies": { + "bcrypt": "^5.1.1", + "cookie-parser": "^1.4.7", "ejs": "^3.1.10", "express": "^4.21.2", "multer": "^1.4.5-lts.1", diff --git a/public/index.css b/public/index.css index 0e662dc..1a09355 100644 --- a/public/index.css +++ b/public/index.css @@ -28,10 +28,22 @@ body { border-radius: 20px; } -.header { +.header, +.header-big { color: var(--main-4); } +.header-big { + width: 800px; + margin: -10px; + padding: 10px; + background: var(--main-5); + border-top-left-radius: 10px; + border-top-right-radius: 10px; + max-width: calc(100vw - 40px); + margin-bottom: 10px; +} + .scroller { display: flex; justify-content: start; @@ -137,7 +149,7 @@ body { display: grid; } -.form-heading, +form .header-big, .form-message, .form-button { grid-column: span 2; diff --git a/public/index.js b/public/index.js new file mode 100644 index 0000000..0b49900 --- /dev/null +++ b/public/index.js @@ -0,0 +1,30 @@ +async function formClick(ev) { + ev.preventDefault(); + + let { target } = ev; + + let fData = new FormData(target); + + let file = target.querySelector('input[type=file]'); + if (file) + file.value = null; + + let fetched = await fetch(target.action, { + 'method': 'POST', + 'body': fData + }); + + let json = await fetched.json(); + + target.querySelector('.form-message').textContent = json.message; + + if (json.redirect && json.success) { + setTimeout(function () { + window.location.href = json.redirect; + }, 2000); + } +} + +window.onload = function () { + document.addEventListener('submit', formClick); +} \ No newline at end of file diff --git a/routes/init.js b/routes/init.js new file mode 100644 index 0000000..a5457a6 --- /dev/null +++ b/routes/init.js @@ -0,0 +1,98 @@ +import { importRouters } from "../lib.js"; +import multer from "multer"; +import cookieParser from "cookie-parser"; +import { initDb } from "../db.js"; + +let db = await initDb(); + +const upload = multer({ dest: 'uploads/' }); + +const aliases = { + '/': '/walls/get/home' +}; + +const routers = { + '/you': './routes/you.js', + '/api/form/you': './routes/youApi.js' +} + +function doAliases(app) { + for (let alias in aliases) { + app.all(alias, (req, res, next) => { + res.redirect(aliases[alias]) + }) + } + +} + +async function auther(req, res, next) { + let body = { ...req.cookies, ...req.body }; + + let { token } = body; + + let match = await db.all('SELECT * FROM token WHERE token = ?', [ + token || 'blah' + ]); + + let username = match[0] ? match[0].username : '!nobody'; + + let valid = await db.all('SELECT * FROM auth WHERE username = ?', [ + username + ]); + + res.auth = { + username, + valid: valid[0], + rootUrl: process.env.URL, + }; + + next(); +} + +function initr(req, res, next) { + let headerCtx = [ + { link: '/walls/get/home', icon: '/icon.svg', name: 'DervNet' }, + { link: '/walls/list', icon: '/walls.svg', name: 'Explore' }, + { link: '/you/logout', icon: '/logout.svg', name: 'Leave' } // fix icon + ]; + + if (!res.auth || !res.auth.valid) { + headerCtx = [ + { link: '/walls/get/home', icon: '/icon.svg', name: 'DervNet' }, + { link: '/you/login', icon: '/walls.svg', name: 'Log in' }, + { link: '/you/new', icon: '/walls.svg', name: 'Join' } + ]; + } + + res.ctx = { + mainPage: '404.ejs', + mainCtx: {}, + headerCtx + }; + next(); +} + +async function doInit(app) { + app.use(cookieParser()); + + app.use(auther) + + app.use(initr) + + app.use('/api/form', upload.none()); + app.use('/api/file', upload.single('file')); + + doAliases(app); + + await importRouters(app, routers); + + app.use('/api', (req, res, next) => { + res.send(res.api); + }) + + app.use((req, res, next) => { + res.render('root.ejs', res.ctx) + }) +} + +export { doInit }; \ No newline at end of file diff --git a/you.js b/routes/you.js similarity index 85% rename from you.js rename to routes/you.js index 42337ba..c7cb30e 100644 --- a/you.js +++ b/routes/you.js @@ -5,8 +5,8 @@ router.get('/login', (req, res, next) => { res.ctx.mainPage = 'form' res.ctx.mainCtx = { title: "Log in", - message: "hi", - action: "/api/you/login", + message: 'Log into an existing account.', + action: "/api/form/you/login", inputs: [ { "key": "Username", @@ -29,8 +29,8 @@ router.get('/new', (req, res, next) => { res.ctx.mainPage = 'form' res.ctx.mainCtx = { title: "Register", - message: "hi", - action: "/api/you/new", + message: 'Create an account and join the community!', + action: "/api/form/you/new", inputs: [ { "key": "Username", diff --git a/routes/youApi.js b/routes/youApi.js new file mode 100644 index 0000000..6656e75 --- /dev/null +++ b/routes/youApi.js @@ -0,0 +1,101 @@ +import { Router } from "express"; +import { apiStat } from "../lib.js"; +import { hash, compare } from "bcrypt"; +import { initDb } from "../db.js"; +import { randomBytes } from 'node:crypto'; + +let db = await initDb(); + +const router = Router(); +const minChar = 1; +const maxChar = 32; + +function legalName(user) { + return user.search(/[^A-Za-z0-9\-\_]/g) == -1; +} + +async function login(req, res, next) { + let { user, pass } = req.body; + + if (!pass || !user) { + apiStat(res, next, 'Fields are missing.') + return; + } + + let isExist = await db.all('SELECT * FROM auth WHERE UPPER(username) LIKE UPPER(?)', [ + user + ]); // TODO: dont use all + + if (isExist.length < 1) { + apiStat(res, next, `Username wasn't taken.`) + return; + } + + let passHash = await compare(pass, isExist[0].password); + + if (!passHash) { + apiStat(res, next, `Password is wrong.`); + return; + } + + let token = randomBytes(32).toString('hex'); + + await db.run('INSERT INTO token (username, token) VALUES (?, ?)', [ + user, + token + ]) + + res.cookie('token', token); + + let stat = `Login succeeded.`; + apiStat(res, next, stat, '/'); + return stat; +} + +router.post('/login', login) + +router.post('/new', async (req, res, next) => { + let { user, pass, pass2 } = req.body; + + if (pass != pass2) { + apiStat(res, next, "Passwords don't match.") + return; + } + + if (!pass || !user || !pass2) { + apiStat(res, next, 'Fields are missing.') + return; + } + + if (!legalName(user)) { + apiStat(res, next, 'Username is invalid.') + return; + } + + if (user.length < minChar || user.length > maxChar) { + apiStat(res, next, `Username length isn't ${minChar} to ${maxChar} characters.`) + return; + } // TODO: fix this horrible logic chain thing + + let isExist = await db.all('SELECT * FROM auth WHERE UPPER(username) LIKE UPPER(?)', [ + user + ]); // TODO: dont use all + + if (isExist.length > 0) { + apiStat(res, next, `Username was taken.`) + return; + } + + var passHash = await hash(pass, 10); + + await db.run('INSERT INTO auth (username, password) VALUES (?, ?)', [ + user, + passHash + ]); + + let testLogin = await login(req, res, () => { }); + + apiStat(res, next, `Account created. Login status: ${testLogin}`, '/') +}) + +export default router; \ No newline at end of file diff --git a/views/404.ejs b/views/404.ejs index e66effc..9ea831a 100644 --- a/views/404.ejs +++ b/views/404.ejs @@ -1,4 +1,4 @@
-

Oops!

+

Oops!

Something went wrong; this page couldn't be found.

\ No newline at end of file diff --git a/views/form.ejs b/views/form.ejs index d7775e2..e41e9b5 100644 --- a/views/form.ejs +++ b/views/form.ejs @@ -1,5 +1,5 @@
-

+

<%= title %>

diff --git a/views/root.ejs b/views/root.ejs index 5922a27..a12e4d6 100644 --- a/views/root.ejs +++ b/views/root.ejs @@ -5,7 +5,8 @@ DervNet - + +