f0ckv2/src/inc/lib.mjs
2022-05-18 03:43:17 +00:00

200 lines
5.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import crypto from "crypto";
import util from "util";
import db from "./sql.mjs";
import { exec as _exec } from "child_process";
const exec = util.promisify(_exec);
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);
let tmp = link.length === 0 ? '/' : link.join('/');
if(!tmp.endsWith('/'))
tmp = tmp + '/';
if(!tmp.startsWith('/'))
tmp = '/' + tmp;
return {
main: tmp,
path: env.path ? env.path : ''
};
};
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;
};
async detectNSFW(dest) {
const { stdout, stderr } = await exec(
`python -c "import sys\nfrom nsfw_detector import predict\nmodel = predict.load_model('./nsfw_model.h5')\nprint(predict.classify(model, './public/b/${dest}'))"`
);
const res = JSON.parse(stdout.replace(/\'/g, '"').split('\n').slice(1, -1));
const tmp = Object.values(res)[0];
let nsfw = false;
if(tmp.neutral >= .7)
nsfw = false;
else if((tmp.sexy + tmp.porn + tmp.hentai) >= .7)
nsfw = true;
else if(tmp.drawings >= .4)
nsfw = false;
else
nsfw = false;
return {
isNSFW: nsfw,
score: tmp.sexy + tmp.porn + tmp.hentai,
scores: tmp
};
};
async getDefaultAvatar() {
return (await db`
select column_default as avatar
from "information_schema"."columns"
where
TABLE_SCHEMA='public' and
TABLE_NAME='user_options' and
COLUMN_NAME = 'avatar'
`)[0].avatar;
}
};