💾 Archived View for iich.space › src › app › post.ts captured on 2021-12-03 at 14:04:38.
-=-=-=-=-=-=-
import { Request, Status } from '@/gemini'; import { Handler, Router } from '@/mission-control'; import { BoardType, Thread } from '~/db/models'; import { createReply, createThread, getBoardByName, getPartialThreadById, hasBan, } from '~/db/queries'; import withCertificateIfSigning from '~/middleware/withCertificateIfSigning'; import withQuery from '~/middleware/withQuery'; import withThrottling from '~/middleware/withThrottling'; import { getFingerprint } from '~/util/identity'; import { processImageUpload } from '~/util/images'; import { withValidToken } from '~/util/tokens'; import { hasProfanity } from '~/util/word-filter'; const boardExists: Handler = (_, res, { params }) => { const board = getBoardByName(params.name); if (board === undefined) { res.sendStatus(Status.NOT_FOUND); res.end(); } }; const isImageBoard: Handler = (_, res, { params }) => { const board = getBoardByName(params.name); if (board.type !== BoardType.Image) { res.sendStatus(Status.NOT_FOUND); res.end(); } }; const shouldRefuse = (req: Request, comment: string) => hasProfanity(comment) || hasBan(req.remote); const isLocked = (thread: Thread) => thread.locked === 1; const router = new Router<Handler>(); router.use( '/:name/threads/:id/:signed/:token/text', boardExists, withCertificateIfSigning, withQuery('Comment'), withThrottling, withValidToken, async (req, res, { params }) => { const comment = req.query!; if (shouldRefuse(req, comment)) { res.sendStatus(Status.BAD_REQUEST); return res.end(); } const thread = getPartialThreadById(parseInt(params.id, 10)); const fingerprint = getFingerprint(req, params.signed); if (isLocked(thread)) { res.sendStatus(Status.BAD_REQUEST); return res.end(); } createReply(thread.id, comment, fingerprint, null, req.remote); res.redirect(thread.path); }, ); router.use( '/:name/threads/:id/:signed/:token/image', isImageBoard, withCertificateIfSigning, withThrottling, withValidToken, async (req, res, { params }) => { const file = req.file!; const comment = file.token || '[Image]'; if (shouldRefuse(req, comment)) { res.sendStatus(Status.BAD_REQUEST); return res.end(); } const board = getBoardByName(params.name); const sha = await processImageUpload(file); const thread = getPartialThreadById(parseInt(params.id, 10)); const fingerprint = getFingerprint(req, params.signed); if (isLocked(thread)) { res.sendStatus(Status.BAD_REQUEST); return res.end(); } createReply(thread.id, comment, fingerprint, sha, req.remote); res.redirect(`gemini://${req.url.host}/${board.name}/threads/${thread.id}`); }, ); router.use( '/:name/:signed/:token/text', boardExists, withCertificateIfSigning, withQuery('Comment'), withThrottling, withValidToken, async (req, res, { params }) => { const comment = req.query!; if (shouldRefuse(req, comment)) { res.sendStatus(Status.BAD_REQUEST); return res.end(); } if (hasBan(req.remote)) { res.sendStatus(Status.BAD_REQUEST); return res.end(); } const board = getBoardByName(params.name); const fingerprint = getFingerprint(req, params.signed); const thread = createThread( board.id, comment, fingerprint, null, req.remote, ); res.redirect(thread.path); }, ); router.use( '/:name/:signed/:token/image', isImageBoard, withCertificateIfSigning, async (req, res) => { const file = req.file!; if (file.token === '') { res.sendStatus( Status.BAD_REQUEST, 'A comment is required for new image threads using the token field', ); return res.end(); } }, withThrottling, withValidToken, async (req, res, { params }) => { const file = req.file!; const comment = file.token; if (shouldRefuse(req, comment)) { res.sendStatus(Status.BAD_REQUEST); return res.end(); } const board = getBoardByName(params.name); const sha = await processImageUpload(file); const fingerprint = getFingerprint(req, params.signed); const thread = createThread( board.id, comment, fingerprint, sha, req.remote, ); res.redirect(`gemini://${req.url.host}/${board.name}/threads/${thread.id}`); }, ); export default router;