import crypto from "crypto"; import util from "util"; import db from "./sql.mjs"; const scrypt = util.promisify(crypto.scrypt); const epochs = [ ["year", 31536000], ["month", 2592000], ["day", 86400], ["hour", 3600], ["minute", 60], ["second", 1] ]; const getDuration = timeAgoInSeconds => { for(let [name, seconds] of epochs) { const interval = ~~(timeAgoInSeconds / seconds); if(interval >= 1) return { interval: interval, epoch: name }; } }; export default new class { formatSize(size, i = ~~(Math.log(size) / Math.log(1024))) { return (size / Math.pow(1024, i)).toFixed(2) * 1 + " " + ["B", "kB", "MB", "GB", "TB"][i]; }; calcSpeed(b, s) { return (Math.round((b * 8 / s / 1e6) * 1e4) / 1e4); }; timeAgo(date) { const { interval, epoch } = getDuration(~~((new Date() - new Date(date)) / 1e3)); return `${interval} ${epoch}${interval === 1 ? "" : "s"} ago`; }; md5(str) { return crypto.createHash('md5').update(str).digest("hex"); }; getMode(mode) { let tmp; switch(mode) { case 1: // nsfw tmp = "items.id in (select item_id from tags_assign where tag_id = 2 group by item_id)"; break; case 2: // untagged tmp = "items.id not in (select item_id from tags_assign group by item_id)"; break; case 3: // all tmp = "1 = 1"; break; default: // sfw tmp = "items.id in (select item_id from tags_assign where tag_id = 1 group by item_id)"; break; } return tmp; }; createID() { return crypto.randomBytes(16).toString("hex") + Date.now().toString(24); }; genLink(env) { const link = []; if(env.tag) link.push("tag", env.tag); if(env.user) link.push("user", env.user, env.type ?? 'f0cks'); if(env.mime.length > 2) link.push(env.mime); if(env.page) link.push("p", env.page); return link.join("/"); }; parseTag(tag) { if(!tag) return null; return decodeURI(tag); } // async funcs async countf0cks() { const tagged = (await db` select count(*) as total from "items" where id in (select item_id from tags_assign group by item_id) `)[0].total; const untagged = (await db` select count(*) as total from "items" where id not in (select item_id from tags_assign group by item_id) `)[0].total; const sfw = (await db` select count(*) as total from "items" where id in (select item_id from tags_assign where tag_id = 1 group by item_id) `)[0].total; const nsfw = (await db` select count(*) as total from "items" where id in (select item_id from tags_assign where tag_id = 2 group by item_id) `)[0].total; return { tagged, untagged, total: +tagged + +untagged, sfw, nsfw }; }; async hash(str) { const salt = crypto.randomBytes(16).toString("hex"); const derivedKey = await scrypt(str, salt, 64); return "$f0ck$" + salt + ":" + derivedKey.toString("hex"); }; async verify(str, hash) { const [ salt, key ] = hash.substring(6).split(":"); const keyBuffer = Buffer.from(key, "hex"); const derivedKey = await scrypt(str, salt, 64); return crypto.timingSafeEqual(keyBuffer, derivedKey); }; async auth(req, res, next) { if(!req.session) { return res.reply({ code: 401, body: "401 - Unauthorized" }); } return next(); }; async getTags(itemid) { const tags = await db` select "tags".id, "tags".tag, "tags".normalized, "user".user from "tags_assign" left join "tags" on "tags".id = "tags_assign".tag_id left join "user" on "user".id = "tags_assign".user_id where "tags_assign".item_id = ${+itemid} order by "tags".id asc `; for(let t = 0; t < tags.length; t++) { if(tags[t].tag.startsWith(">")) tags[t].badge = "badge-greentext badge-light"; else if(tags[t].normalized === "ukraine") tags[t].badge = "badge-ukraine badge-light"; else if(/[а-яё]/.test(tags[t].normalized) || tags[t].normalized === "russia") tags[t].badge = "badge-russia badge-light"; else if(tags[t].normalized === "german") tags[t].badge = "badge-german badge-light"; else if(tags[t].normalized === "dutch") tags[t].badge = "badge-dutch badge-light"; else if(tags[t].normalized === "sfw") tags[t].badge = "badge-success"; else if(tags[t].normalized === "nsfw") tags[t].badge = "badge-danger"; else tags[t].badge = "badge-light"; } return tags; }; };