import db from "../sql.mjs"; import lib from "../lib.mjs"; import { exec } from "child_process"; import { promises as fs } from "fs"; export default (router, tpl) => { router.get(/^\/login(\/)?$/, async (req, res) => { if (req.cookies.session) { return res.reply({ body: tpl.render('error', { message: "you're already logged in lol", tmp: null }, req) }); } res.reply({ body: tpl.render("login", { theme: req.cookies.theme ?? "f0ck" }) }); }); router.post(/^\/login(\/)?$/, async (req, res) => { const user = await db` select * from "user" where "login" = ${req.post.username.toLowerCase()} limit 1 `; if (user.length === 0) return res.reply({ body: "user doesn't exist or wrong password" }); if (!(await lib.verify(req.post.password, user[0].password))) return res.reply({ body: "user doesn't exist or wrong password" }); const stamp = ~~(Date.now() / 1e3); await db` delete from user_sessions where last_action <= ${(Date.now() - 6048e5)} and kmsi = 0 `; const session = lib.md5(lib.createID()); const blah = { user_id: user[0].id, session: lib.md5(session), browser: req.headers["user-agent"], created_at: stamp, last_used: stamp, last_action: "/login", kmsi: typeof req.post.kmsi !== 'undefined' ? 1 : 0 }; await db` insert into "user_sessions" ${db(blah, 'user_id', 'session', 'browser', 'created_at', 'last_used', 'last_action', 'kmsi') } `; return res.writeHead(301, { "Cache-Control": "no-cache, public", "Set-Cookie": `session=${session}; Path=/; Expires=Fri, 31 Dec 9999 23:59:59 GMT`, "Location": "/" }).end(); }); router.get(/^\/logout$/, lib.loggedin, async (req, res) => { const usersession = await db` select * from "user_sessions" where id = ${+req.session.sess_id} `; if (usersession.length === 0) return res.reply({ body: "nope 2" }); await db` delete from "user_sessions" where id = ${+req.session.sess_id} `; return res.writeHead(301, { "Cache-Control": "no-cache, public", "Set-Cookie": "session=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT", "Location": "/" }).end(); }); router.get(/^\/login\/pwdgen$/, async (req, res) => { res.reply({ body: "
" }); }); router.post(/^\/login\/pwdgen$/, async (req, res) => { res.reply({ body: await lib.hash(req.post.pwd) }); }); router.get(/^\/admin(\/)?$/, lib.auth, async (req, res) => { // frontpage res.reply({ body: tpl.render("admin", { totals: await lib.countf0cks(), session: req.session, tmp: null }, req) }); }); router.get(/^\/admin\/sessions(\/)?$/, lib.auth, async (req, res) => { const rows = await db` select "user_sessions".*, "user".user from "user_sessions" left join "user" on "user".id = "user_sessions".user_id order by "user_sessions".last_used desc `; res.reply({ body: tpl.render("admin/sessions", { session: req.session, sessions: rows, totals: await lib.countf0cks(), tmp: null }, req) }); }); router.get(/^\/admin\/approve\/?/, lib.auth, async (req, res) => { if (req.url.qs?.id) { const id = +req.url.qs.id; const f0ck = await db` select dest, mime from "items" where id = ${id} and active = 'false' limit 1 `; if (f0ck.length === 0) { return res.reply({ body: `f0ck ${id}: f0ck not found` }); } await db`update "items" set active = 'true' where id = ${id}`; // Check if files need moving (if they are in deleted/) try { await fs.access(`./public/b/${f0ck[0].dest}`); // Exists in public, good (new upload) } catch { // Not in public, likely a deleted item being recovered await fs.copyFile(`./deleted/b/${f0ck[0].dest}`, `./public/b/${f0ck[0].dest}`).catch(_ => { }); await fs.copyFile(`./deleted/t/${id}.webp`, `./public/t/${id}.webp`).catch(_ => { }); await fs.unlink(`./deleted/b/${f0ck[0].dest}`).catch(_ => { }); await fs.unlink(`./deleted/t/${id}.webp`).catch(_ => { }); if (f0ck[0].mime.startsWith('audio')) { await fs.copyFile(`./deleted/ca/${id}.webp`, `./public/ca/${id}.webp`).catch(_ => { }); await fs.unlink(`./deleted/ca/${id}.webp`).catch(_ => { }); } } return res.writeHead(302, { "Location": `/${id}` }).end(); } const page = +req.url.qs.page || 1; const limit = 50; const offset = (page - 1) * limit; const total = (await db`select count(*) as c from "items" where active = 'false'`)[0].c; const pages = Math.ceil(total / limit); const _posts = await db` select id, mime, username, dest from "items" where active = 'false' order by id desc limit ${limit} offset ${offset} `; if (_posts.length === 0 && page > 1) { // if page empty, maybe redirect to last page or page 1? // Just render empty for now } if (_posts.length === 0) { return res.reply({ body: tpl.render('admin/approve', { posts: [], pages: 0, page: 1, tmp: null }, req) }); } const posts = await Promise.all(_posts.map(async p => { // Try to get thumbnail from public or deleted let thumb; try { // Try public first thumb = (await fs.readFile(`./public/t/${p.id}.webp`)).toString('base64'); } catch { try { thumb = (await fs.readFile(`./deleted/t/${p.id}.webp`)).toString('base64'); } catch { thumb = ""; // No thumbnail? } } return { ...p, thumbnail: thumb }; })); res.reply({ body: tpl.render('admin/approve', { posts, page, pages, stats: { total: posts.length }, tmp: null }, req) }); }); const deleteItem = async (id) => { const f0ck = await db` select dest, mime from "items" where id = ${id} limit 1 `; if (f0ck.length > 0) { console.log(`[ADMIN DENY] Found item, deleting files: ${f0ck[0].dest}`); // Delete files await fs.unlink(`./public/b/${f0ck[0].dest}`).catch(e => console.log('File error pub/b:', e.message)); await fs.unlink(`./public/t/${id}.webp`).catch(e => console.log('File error pub/t:', e.message)); await fs.unlink(`./deleted/b/${f0ck[0].dest}`).catch(e => console.log('File error del/b:', e.message)); await fs.unlink(`./deleted/t/${id}.webp`).catch(e => console.log('File error del/t:', e.message)); if (f0ck[0].mime.startsWith('audio')) { await fs.unlink(`./public/ca/${id}.webp`).catch(() => { }); await fs.unlink(`./deleted/ca/${id}.webp`).catch(() => { }); } // Delete DB entries console.log('[ADMIN DENY] Deleting DB entries...'); try { await db`delete from "tags_assign" where item_id = ${id}`; await db`delete from "favorites" where item_id = ${id}`; await db`delete from "comments" where item_id = ${id}`.catch(() => { }); await db`delete from "items" where id = ${id}`; console.log('[ADMIN DENY] Deleted successfully'); return true; } catch (dbErr) { console.error('[ADMIN DENY DB ERROR]', dbErr); return false; } } else { console.log('[ADMIN DENY] Item not found in DB'); return false; } }; router.get(/^\/admin\/deny\/?/, lib.auth, async (req, res) => { console.log('[ADMIN DENY] Logs initiated'); if (req.url.qs?.id) { const id = +req.url.qs.id; console.log(`[ADMIN DENY] Denying ID: ${id}`); await deleteItem(id); return res.writeHead(302, { "Location": `/admin/approve` }).end(); } console.log('[ADMIN DENY] No ID provided'); return res.writeHead(302, { "Location": "/admin/approve" }).end(); }); router.post(/^\/admin\/deny-multi\/?/, lib.auth, async (req, res) => { try { const ids = req.post.ids; if (!Array.isArray(ids)) throw new Error('ids must be an array'); console.log(`[ADMIN DENY MULTI] Denying ${ids.length} items`); for (const id of ids) { await deleteItem(+id); } return res.reply({ success: true }); } catch (err) { console.error('[ADMIN DENY MULTI ERROR]', err); return res.reply({ success: false, msg: err.message }, 500); } }); return router; };