preliminary work for guest account support

This commit is contained in:
waveringana 2022-12-05 17:50:38 +00:00
parent b6779a7d7c
commit bbc655b3f9
11 changed files with 132 additions and 50 deletions

View file

@ -15,9 +15,9 @@ import path from "path";
import authRouter from "./routes/auth"; import authRouter from "./routes/auth";
import indexRouter from "./routes/index"; import indexRouter from "./routes/index";
import adduserRouter from "./routes/adduser";
import {createUser} from "./db"; import {db, createUser} from "./db";
import db from "./db"
let app = express(); let app = express();
let server = http.createServer(app); let server = http.createServer(app);
@ -122,6 +122,7 @@ app.use(passport.authenticate("session"));
app.use("/", indexRouter); app.use("/", indexRouter);
app.use("/", authRouter); app.use("/", authRouter);
app.use("/", adduserRouter);
app.use("/uploads", express.static("uploads")); app.use("/uploads", express.static("uploads"));

View file

@ -1,13 +1,11 @@
import type {RequestHandler as Middleware} from 'express'; import sqlite3 from "sqlite3";
import mkdirp from "mkdirp";
const sqlite3 = require("sqlite3"); import crypto from "crypto";
const mkdirp = require("mkdirp");
const crypto = require("crypto");
mkdirp.sync("./uploads"); mkdirp.sync("./uploads");
mkdirp.sync("./var/db"); mkdirp.sync("./var/db");
let db = new sqlite3.Database("./var/db/media.db"); export const db = new sqlite3.Database("./var/db/media.db");
export function createUser(username: string, password: string) { export function createUser(username: string, password: string) {
var salt = crypto.randomBytes(16); var salt = crypto.randomBytes(16);
@ -16,6 +14,4 @@ export function createUser(username: string, password: string) {
crypto.pbkdf2Sync(password, salt, 310000, 32, "sha256"), crypto.pbkdf2Sync(password, salt, 310000, 32, "sha256"),
salt salt
]); ]);
} }
export default db;

View file

@ -41,7 +41,7 @@
/* background image by Cole Bemis <https://feathericons.com> */ /* background image by Cole Bemis <https://feathericons.com> */
.nav .user { .nav .user {
padding-left: 20px; padding-left: 20px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-user'%3E%3Cpath d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'%3E%3C/path%3E%3Ccircle cx='12' cy='7' r='4'%3E%3C/circle%3E%3C/svg%3E"); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-user'%3E%3Cpath d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'%3E%3C/path%3E%3Ccircle cx='12' cy='7' r='4'%3E%3C/circle%3E%3C/svg%3E");
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center left; background-position: center left;
} }
@ -49,7 +49,15 @@
/* background image by Cole Bemis <https://feathericons.com> */ /* background image by Cole Bemis <https://feathericons.com> */
.nav .logout { .nav .logout {
padding-left: 20px; padding-left: 20px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-log-out'%3E%3Cpath d='M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4'%3E%3C/path%3E%3Cpolyline points='16 17 21 12 16 7'%3E%3C/polyline%3E%3Cline x1='21' y1='12' x2='9' y2='12'%3E%3C/line%3E%3C/svg%3E%0A"); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-log-out'%3E%3Cpath d='M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4'%3E%3C/path%3E%3Cpolyline points='16 17 21 12 16 7'%3E%3C/polyline%3E%3Cline x1='21' y1='12' x2='9' y2='12'%3E%3C/line%3E%3C/svg%3E%0A");
background-repeat: no-repeat;
background-position: center left;
}
/* background image by Cole Bemis <https://feathericons.com> */
.nav .adduser {
padding-left: 20px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-user-plus'%3E%3Cpath d='M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2'%3E%3C/path%3E%3Ccircle cx='8.5' cy='7' r='4'%3E%3C/circle%3E%3Cline x1='20' y1='8' x2='20' y2='14'%3E%3C/line%3E%3Cline x1='23' y1='11' x2='17' y2='11'%3E%3C/line%3E%3C/svg%3E");
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center left; background-position: center left;
} }

View file

@ -131,8 +131,6 @@ function uploadFile(file) {
}); });
if (file == null || file == undefined) { if (file == null || file == undefined) {
//file = reader.readAsDataURL(document.getElementById("fileupload").files[0]);
//file = reader.readAsDataURL(document.querySelector("#fileupload").files[0]);
file = document.querySelector("#fileupload").files[0]; file = document.querySelector("#fileupload").files[0];
} }

30
app/routes/adduser.ts Normal file
View file

@ -0,0 +1,30 @@
import type {RequestHandler as Middleware, Router, Request, Response, NextFunction} from 'express';
import express from "express";
import {db, createUser} from "../db";
const router: Router = express.Router();
const adminCheck: Middleware = (req: Request, res: Response, next: NextFunction) => {
//@ts-ignore
if (!req.user)
return res.status(403).send("You are not authorized to perform this action");
else {
//@ts-ignore
if (req.user.username != "admin")
return res.status(403).send("You are not authorized to perform this action");
next();
}
}
router.get("/adduser", adminCheck, (req: Request, res: Response, next: NextFunction) => {
res.locals.filter = null;
res.render("adduser", { user: req.user });
});
router.post("/adduser", adminCheck, (req: Request, res: Response, next: NextFunction) => {
createUser(req.body.username, req.body.password);
res.redirect('/');
});
export default router;

View file

@ -1,13 +1,11 @@
import type {MediaRow, UserRow} from '../types'; import type {UserRow} from '../types';
import type {RequestHandler as Middleware} from 'express';
import crypto from "crypto"; import crypto from "crypto";
import express from "express"; import express from "express";
import passport from "passport"; import passport from "passport";
import {Strategy as LocalStrategy} from "passport-local";
import { Strategy as LocalStrategy } from "passport-local"; import {db} from "../db";
import db from "../db";
let router = express.Router(); let router = express.Router();

View file

@ -1,5 +1,4 @@
import type {RequestHandler as Middleware, Router, Request, Response} from 'express'; import type {RequestHandler as Middleware, Router, Request, Response, NextFunction} from 'express';
import types from 'multer';
import multer from "multer"; import multer from "multer";
import express from "express"; import express from "express";
@ -14,8 +13,8 @@ ffmpeg.setFfprobePath(ffprobepath.path);
import fs from "fs"; import fs from "fs";
import db from "../db"; import {db, createUser} from "../db";
import {checkAuth, convert, handleUpload} from "./middleware"; import {checkAuth, checkSharexAuth, createEmbedData, handleUpload} from "./middleware";
import { MediaRow } from '../types'; import { MediaRow } from '../types';
function extension(str: String){ function extension(str: String){
@ -89,13 +88,12 @@ const fetchMedia: Middleware = (req, res, next) => {
let router = express.Router(); let router = express.Router();
router.get("/", (req, res, next) => { router.get("/", (req: Request, res: Response, next: NextFunction) => {
// @ts-ignore, user is part of req header if (!req.user)
if (!req.user) { return res.render("home"); } return res.render("home")
next(); next();
}, fetchMedia, (req, res) => { }, fetchMedia, (req: Request, res: Response) => {
res.locals.filter = null; res.locals.filter = null;
// @ts-ignore, user is part of req header
res.render("index", { user: req.user }); res.render("index", { user: req.user });
}); });
@ -103,10 +101,10 @@ router.get("/gifv/:file", async (req, res, next) => {
let url = `${req.protocol}://${req.get("host")}/uploads/${req.params.file}`; let url = `${req.protocol}://${req.get("host")}/uploads/${req.params.file}`;
let width; let height; let width; let height;
let nameAndExtension = extension("uploads/" + req.params.file); let nameAndExtension = extension(`uploads/${req.params.file}`);
if (nameAndExtension[1] == ".mp4" || nameAndExtension[1] == ".mov" || nameAndExtension[1] == ".webm") { if (nameAndExtension[1] == ".mp4" || nameAndExtension[1] == ".mov" || nameAndExtension[1] == ".webm") {
ffmpeg() ffmpeg()
.input("uploads/" + req.params.file) .input(`uploads/${req.params.file}`)
.inputFormat(nameAndExtension[1].substring(1)) .inputFormat(nameAndExtension[1].substring(1))
.ffprobe((err: Error, data: ffmpeg.FfprobeData) => { .ffprobe((err: Error, data: ffmpeg.FfprobeData) => {
if (err) return next(err); if (err) return next(err);
@ -116,7 +114,7 @@ router.get("/gifv/:file", async (req, res, next) => {
}); });
} else if (nameAndExtension[1] == ".gif") { } else if (nameAndExtension[1] == ".gif") {
ffmpeg() ffmpeg()
.input("uploads/" + req.params.file) .input(`uploads/${req.params.file}`)
.inputFormat("gif") .inputFormat("gif")
.ffprobe((err: Error, data: ffmpeg.FfprobeData) => { .ffprobe((err: Error, data: ffmpeg.FfprobeData) => {
if (err) return next(err); if (err) return next(err);
@ -130,16 +128,16 @@ router.get("/gifv/:file", async (req, res, next) => {
} }
}); });
router.post("/", [upload.array("fileupload"), convert, handleUpload], (req: Request, res: Response) => { router.post("/", [checkAuth, upload.array("fileupload"), createEmbedData, handleUpload], (req: Request, res: Response) => {
return res.redirect("/"); res.redirect("/")
}); });
router.post("/sharex", [checkAuth, upload.array("fileupload"), convert, handleUpload], (req: Request, res: Response) => { router.post("/sharex", [checkSharexAuth, upload.array("fileupload"), createEmbedData, handleUpload], (req: Request, res: Response) => {
// @ts-ignore // @ts-ignore
return res.send(`${req.protocol}://${req.get("host")}/uploads/${req.files[0].filename}`); return res.send(`${req.protocol}://${req.get("host")}/uploads/${req.files[0].filename}`);
}); });
router.post("/:id(\\d+)/delete", (req, res, next) => { router.post("/:id(\\d+)/delete", [checkAuth], (req: Request, res: Response, next: NextFunction) => {
db.all("SELECT path FROM media WHERE id = ?", [ req.params.id ], (err: Error, path: Array<any>) => { db.all("SELECT path FROM media WHERE id = ?", [ req.params.id ], (err: Error, path: Array<any>) => {
if (err) { return next(err); } if (err) { return next(err); }
fs.unlink(`uploads/${path[0].path}`, (err => { fs.unlink(`uploads/${path[0].path}`, (err => {

View file

@ -10,15 +10,21 @@ ffmpeg.setFfprobePath(ffprobepath.path);
import fs from "fs"; import fs from "fs";
import process from "process"; import process from "process";
import db from "../db"; import {db} from "../db";
function extension(str: String){ function extension(str: String){
let file = str.split("/").pop(); let file = str.split("/").pop();
return [file.substr(0,file.lastIndexOf(".")),file.substr(file.lastIndexOf("."),file.length).toLowerCase()]; return [file.substr(0,file.lastIndexOf(".")),file.substr(file.lastIndexOf("."),file.length).toLowerCase()];
} }
//Checks ShareX key export const checkAuth: Middleware = (req, res, next) => {
export const checkAuth: Middleware = (req: Request, res: Response, next: Function) => { if (!req.user) {
return res.status(401);
}
next();
}
export const checkSharexAuth: Middleware = (req, res, next) => {
let auth = process.env.EBAPI_KEY || process.env.EBPASS || "pleaseSetAPI_KEY"; let auth = process.env.EBAPI_KEY || process.env.EBPASS || "pleaseSetAPI_KEY";
let key = null; let key = null;
@ -38,8 +44,8 @@ export const checkAuth: Middleware = (req: Request, res: Response, next: Functio
next(); next();
} }
//Converts mp4 to gif and vice versa with ffmpeg //createEmbedDatas mp4 to gif and vice versa with ffmpeg
export const convert: Middleware = (req: Request, res: Response, next: Function) => { export const createEmbedData: Middleware = (req, res, next) => {
for (let file in req.files) { for (let file in req.files) {
// @ts-ignore // @ts-ignore
let nameAndExtension = extension(req.files[file].originalname); let nameAndExtension = extension(req.files[file].originalname);
@ -58,13 +64,20 @@ export const convert: Middleware = (req: Request, res: Response, next: Function)
if (err) return next(err); if (err) return next(err);
console.log(`oembed file created ${nameAndExtension[0]}${nameAndExtension[1]}.json`); console.log(`oembed file created ${nameAndExtension[0]}${nameAndExtension[1]}.json`);
}); });
}
/**if (nameAndExtension[1] == ".mp4") { next();
}
export const convert: Middleware = (req, res, next) => {
for (let file in req.files) {
// @ts-ignore
let nameAndExtension = extension(req.files[file].originalname);
if (nameAndExtension[1] == ".mp4" || nameAndExtension[1] == ".webm" || nameAndExtension[1] == ".mkv" || nameAndExtension[1] == ".avi" || nameAndExtension[1] == ".mov") {
console.log("Converting " + nameAndExtension[0] + nameAndExtension[1] + " to gif"); console.log("Converting " + nameAndExtension[0] + nameAndExtension[1] + " to gif");
console.log(nameAndExtension[0] + nameAndExtension[1]); console.log(nameAndExtension[0] + nameAndExtension[1]);
ffmpeg() ffmpeg()
.input(`uploads/${nameAndExtension[0]}${nameAndExtension[1]}`) .input(`uploads/${nameAndExtension[0]}${nameAndExtension[1]}`)
.inputFormat("mp4") .inputFormat(nameAndExtension[1].substring(1))
.outputFormat("gif") .outputFormat("gif")
.output(`uploads/${nameAndExtension[0]}.gif`) .output(`uploads/${nameAndExtension[0]}.gif`)
.on("end", function() { .on("end", function() {
@ -90,13 +103,11 @@ export const convert: Middleware = (req: Request, res: Response, next: Function)
console.log(`Uploaded to uploads/${nameAndExtension[0]}.mp4`); console.log(`Uploaded to uploads/${nameAndExtension[0]}.mp4`);
}) })
.run(); .run();
}**/ }
} }
next();
} }
export const handleUpload: Middleware = (req: Request, res: Response, next: Function) => { export const handleUpload: Middleware = (req, res, next) => {
if (!req.files || Object.keys(req.files).length === 0) { if (!req.files || Object.keys(req.files).length === 0) {
console.log("No files were uploaded"); console.log("No files were uploaded");
return res.status(400).send("No files were uploaded."); return res.status(400).send("No files were uploaded.");

37
app/views/adduser.ejs Normal file
View file

@ -0,0 +1,37 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Embedder</title>
<link rel="stylesheet" href="/css/base.css">
<link rel="stylesheet" href="/css/index.css">
<link rel="stylesheet" href="/css/login.css">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
</head>
<body>
<section class="prompt">
<h3>Embedder</h3>
<h1>Add User</h1>
<form action="/adduser" method="post">
<section>
<label for="username">Username</label>
<input id="username" name="username" type="text" autocomplete="username" required autofocus>
</section>
<section>
<label for="current-password">Password</label>
<input id="current-password" name="password" type="password" autocomplete="current-password" required>
</section>
<button type="submit">Add User</button>
</form>
<hr>
</section>
<footer class="info">
<p><a href="https://l.nekomimi.pet/project">Created by Wavering Ana</a></p>
<p><a href="https://github.com/WaveringAna/Embedder">Github</a></p>
</footer>
</body>
</html>

View file

@ -27,6 +27,11 @@ return string.slice((string.lastIndexOf(".") - 2 >>> 0) + 2);
<button class="logout" type="submit">Sign out</button> <button class="logout" type="submit">Sign out</button>
</form> </form>
</li> </li>
<% if (user.name == "admin" || user.username == "admin") { %>
<li>
<button class="adduser" onclick="location.href='/adduser';">Add user</a></button>
</li>
<% } %>
</ul> </ul>
</nav> </nav>
<header class="header"> <header class="header">

View file

@ -26,7 +26,7 @@
"copy-files": "copyfiles -a -u 1 app/public/* app/views/* app/public/**/* app/views/**/* dist/", "copy-files": "copyfiles -a -u 1 app/public/* app/views/* app/public/**/* app/views/**/* dist/",
"tsc": "tsc", "tsc": "tsc",
"postinstall": "npm run tsc && npm run copy-files", "postinstall": "npm run tsc && npm run copy-files",
"dev": "tsc-node-dev --respawn --pretty --transpile-only index.ts" "build": "npm run clean && npm run copy-files && npm run tsc"
}, },
"dependencies": { "dependencies": {
"@ffmpeg-installer/ffmpeg": "^1.1.0", "@ffmpeg-installer/ffmpeg": "^1.1.0",