import { RouterContext } from "https://deno.land/x/oak/mod.ts" import "https://deno.land/std@0.178.0/dotenv/load.ts"; import { writeFileSync, copy } from "https://deno.land/std/fs/mod.ts"; import { renderFileToString } from "https://deno.land/x/dejs/mod.ts"; import getFileHash from './getFileHash.ts'; import allowedFiletypes from './fileTypes.ts'; import db from './mongodb.ts'; const imageCollection = db.collection('images'); const userTable = db.collection('users'); export const site = async (ctx: RouterContext) => { if(ctx.params.filename == "sw.js" || ctx.params.filename == "script.js"){ ctx.response.type = "text/javascript" } ctx.response.body = await renderFileToString(`${Deno.cwd()}/site/${ctx.params.filename}`, {}) } export const icons = async (ctx: RouterContext, next: any) => { const identifier = ctx.params.filename console.log(["t_192.png", "t_48.png", "t_96.png"].indexOf(identifier)) if (["t_192.png", "t_48.png", "t_96.png"].indexOf(identifier) != -1){ const img = await Deno.readFile(`${Deno.cwd()}/site/i/${ctx.params.filename}`); ctx.response.type = "image/png"; ctx.response.body = img; } else { next() } } export const announce = async (ctx: RouterContext) => { const body = await ctx.request.body({ type: 'json'}).value; const count = await imageCollection.findOne({hash:body.hash}); if(body.size >= 50000000 && body.usercode == "anonymous"){ ctx.response.status = 403 } else if(count){ ctx.response.body = {file: count.filename}; ctx.response.status = 409 }else{ if(body.size >= 50000000){ const users = await userTable.findOne({token:body.usercode}); if(users){ ctx.response.status = 200 }else{ ctx.response.status = 403 } }else{ ctx.response.status = 200 } } } export const chunks = async (ctx: RouterContext) => { const hash = ctx.request.headers.get("file-hash"); const number = ctx.request.headers.get("file-hash"); const body = await ctx.request.body({ type: 'form-data'}); const formData = await body.value.read(); const size = ctx.request.headers.get("content-range").split("/")[1] const data = await Deno.readFile(formData.files[0].filename) Deno.writeFileSync(`${Deno.env.get("TMPPATH")}${hash}.${ctx.request.headers.get("content-number")}.temp`, data) ctx.response.status = 200 } export const mergeChunks = async (ctx: RouterContext) => { const body = await ctx.request.body({ type: 'json'}).value; const ts = new Date(); let newname = `${ts.valueOf()}${allowedFiletypes.get(body.type)}` let files = [] for await (const dirEntry of Deno.readDir(Deno.env.get("TMPPATH"))) { if(dirEntry.name.includes(body.hash) && dirEntry.isFile){ files.push(dirEntry.name) } } const tempFile = await Deno.makeTempFile(); for (let i = 0; i < files.length; i++) { let file = files.find(elem => elem.includes(`.${i}.temp`)) const data = await Deno.readFileSync(`${Deno.env.get("TMPPATH")}${file}`) await Deno.writeFileSync(tempFile, data, {"append": true}) Deno.remove(`${Deno.env.get("TMPPATH")}${file}`); } await copy(tempFile, `${Deno.env.get("IMAGEPATH")}${newname}`) const id = await imageCollection.insertOne({ hash:body.hash, mime:body.type, filename:newname, usercode:body.usercode, time:ts }); const newhash = await getFileHash(tempFile) if(body.hash == newhash){ ctx.response.body = {"file":newname} ctx.response.status = 201 }else{ ctx.response.status = 418 } } export const getImage = async (ctx: RouterContext) => { const identifier = ctx.params.filename; const info = await imageCollection.findOne({filename:identifier}); if(!info){ ctx.response.status = 404; ctx.response.body = {message: 'image does not exist'}; return }else{ const img = await Deno.readFile(`${Deno.env.get("IMAGEPATH")}${identifier}`); ctx.response.type = info.mime; ctx.response.body = img; } } export const deleteImage = async (ctx: RouterContext) => { const identifier = ctx.params.filename; const count = await imageCollection.findOne({filename:identifier}); if(!count){ ctx.response.status = 404; ctx.response.body = {message: 'image does not exist'}; return }else{ console.log(count) if(ctx.request.headers.get("usercode")==count.usercode){ const deleted = await imageCollection.deleteOne({_id:count._id}) if(!deleted){ ctx.response.status = 500; }else{ await Deno.remove(`${Deno.env.get("IMAGEPATH")}${count.filename}`); ctx.response.status = 204 } }else{ ctx.response.body = {message: 'Unauthorized'}; ctx.response.status = 401 } } } export const uploadImage = async (ctx: RouterContext) => { const body = await ctx.request.body({ type: 'form-data'}).value; const formData = await body.read(); const usercode = ctx.request.headers.get("usercode") ? ctx.request.headers.get("usercode") : "anonymous"; let promises = []; let files = []; formData.files.forEach(file => promises.push(new Promise(async (resolve, reject)=>{ if(!allowedFiletypes.get(file.contentType)){ reject("rejected filetype") }else{ const timestamp = new Date() const hash = getFileHash(file.filename) const count = await imageCollection.findOne({hash:hash}); if(!count){ const newFilename = `${timestamp.valueOf()}${allowedFiletypes.get(file.contentType)}` copy(file.filename, `${Deno.env.get("IMAGEPATH")}${newFilename}`, {overwrite: true}) const id = await imageCollection.insertOne({ hash:hash, mime:file.contentType, filename:newFilename, usercode:usercode, time:timestamp }); files.push(newFilename) resolve(newFilename) }else{ files.push(count.filename) resolve(count.filename) } } }))) const result = await Promise.allSettled(promises) const rejected = await result.filter(obj => Object.keys(obj).some(key => obj[key].includes("rejected"))) if(rejected.length >= 1){ ctx.response.status = 405; ctx.response.body = {message:rejected[0].reason} }else{ if(files.length > 1){ ctx.response.body = files }else{ ctx.response.body = {"img":files[0]} } ctx.response.status = 201 } }