const whiskers = require('whiskers'); const fs = require('fs'); const PasteContent = require('../models/pasteContent.js').PasteContent; const mCrypto = require('../src/crypto.js'); const Security = require('../src/security.js'); async function renderRawPage(app, req, res, entity) { if (entity.type === 'paste') return await app.routerUtils.staticServe(res, app.getData(entity.privId)); else if (entity.type === 'file') { let data = JSON.parse(entity.data); return await app.routerUtils.staticDownload(res, app.getData(entity.privId), data.name, data.type); } else if (entity.type === 'short') return res.end(entity.data); // FIXME stats + ?rel app.routerUtils.onInternalError(res, "Unknown type: " +entity.type); } async function renderPublicPage(app, req, res, entity) { if (entity.type === 'paste') return await app.routerUtils.staticServe(res, app.getData(entity.privId)); else if (entity.type === 'file') { let data = JSON.parse(entity.data); return await app.routerUtils.staticDownload(res, app.getData(entity.privId), data.name, data.type); } else if (entity.type === 'short') return res.end(entity.data); // FIXME stats + ?rel app.routerUtils.onInternalError(res, "Unknown type: " +entity.type); } function renderPrivatePage(app, res, entity) { let stat; try { stat = fs.statSync(app.dataDir+entity.privId); } catch (e) { stat = { error: e }; } app.routerUtils.jsonResponse(res, { ...entity.describe(), ...stat, ...{ path: app.getData(entity.privId) } }); } module.exports = { register: app => { // Root app.router.get("/", (req, res) => { app.routerUtils.redirect(res, '/pastit'); }); // Access page app.router.get("/x/:id", async (req, res) => { let entity = await app.databaseHelper.findOne(PasteContent, { privId: req.params.id, publicId: req.params.id }, " or "); if (entity && entity.privId === req.params.id) return renderPrivatePage(app, res, entity); if (entity && !entity.expired) return renderPublicPage(app, req, res, entity); app.routerUtils.onPageNotFound(res); }); app.router.get("/x/raw/:id", async (req, res) => { let entity = await app.databaseHelper.findOne(PasteContent, { privId: req.params.id, publicId: req.params.id }, " or "); if (entity && !entity.expired) return renderRawPage(app, req, res, entity); app.routerUtils.onPageNotFound(res); }); // pastebin tool app.router.get("/pastit", (req, res) => { let context = app.routerUtils.commonRenderInfos(); context.page_title += " - Pastit"; res.end(whiskers.render(require('../templates/pastit.js'), context)); }); app.router.post("/pastit", async (req, res) => { const content = req.body.content; const privId = mCrypto.string(content); const captchaOk = await Security.captchaCheck(req.body['g-recaptcha-response'], req.headers['x-forwarded-for'] || req.socket.remoteAddress); let entity = await app.databaseHelper.findOne(PasteContent, { privId: privId }); if (!captchaOk) return app.routerUtils.jsonResponse(res, { err: "Invalid captcha input", id: null }); if (!content || !content.length) return app.routerUtils.jsonResponse(res, { err: "Empty input", id: null }); if (entity && !entity.expired) { entity.renew(); await app.databaseHelper.update({privId: privId}, entity); } else { entity = entity || new PasteContent(privId, "paste"); entity.expired = false; entity.renew(); fs.writeFileSync(app.getData(privId), content); await app.databaseHelper.upsertOne(entity); } app.routerUtils.jsonResponse(res, { err: null, id: entity.publicId }); }); // URL shortener tool app.router.get("/short", (req, res) => { let context = app.routerUtils.commonRenderInfos(); context.page_title += " - Shortener"; res.end(whiskers.render(require('../templates/short.js'), context)); }); app.router.post("/short", async (req, res) => { const link = req.body.content; const privId = mCrypto.string(await app.databaseHelper.count(PasteContent) + link); const captchaOk = await Security.captchaCheck(req.body['g-recaptcha-response'], req.headers['x-forwarded-for'] || req.socket.remoteAddress); if (!captchaOk) return app.routerUtils.jsonResponse(res, { err: "Invalid captcha input", id: null }); if (!link || !link.length) return app.routerUtils.jsonResponse(res, { err: "Empty input", id: null }); entity = new PasteContent(privId, "short"); entity.data = link; await app.databaseHelper.insertOne(entity); app.routerUtils.jsonResponse(res, { err: null, id: entity.privId }); }); // Files tool app.router.get("/files", (req, res) => { let context = app.routerUtils.commonRenderInfos(); context.page_title += " - File host"; res.end(whiskers.render(require('../templates/files.js'), context)); }); app.router.post("/files", async (req, res) => { const formData = (req.body["multipart-data"] || []).reduce((res, x) => { res[x.fieldName] = x; return res; }, {}); const privId = mCrypto.string(await app.databaseHelper.count(PasteContent) + (req.content?.fileName || "")); const captchaOk = await Security.captchaCheck(formData["g-recaptcha-response"]?.fileData, req.headers['x-forwarded-for'] || req.socket.remoteAddress); if (!captchaOk) return app.routerUtils.jsonResponse(res, { err: "Invalid captcha input", id: null }); if (!formData.content?.fileData || !formData.content.fileData.length) return app.routerUtils.jsonResponse(res, { err: "Empty input", id: null }); const entity = new PasteContent(privId, "file"); entity.data = JSON.stringify({ name: formData.content.fileName, type: formData.content.fileType }); fs.writeFileSync(app.getData(privId), formData.content.fileData, {encoding: formData.content.fileType.indexOf('text') >= 0 ? 'utf8' : 'binary'}); await app.databaseHelper.insertOne(entity); app.routerUtils.jsonResponse(res, { err: null, id: entity.privId }); }); }};