2021-05-19 14:19:26 +02:00
|
|
|
|
import crypto from "crypto";
|
2021-12-04 12:19:47 +01:00
|
|
|
|
import util from "util";
|
2022-03-31 13:34:51 +02:00
|
|
|
|
import db from "./sql.mjs";
|
2022-05-05 16:02:17 +02:00
|
|
|
|
import { exec as _exec } from "child_process";
|
2021-12-04 12:19:47 +01:00
|
|
|
|
|
2022-05-05 16:02:17 +02:00
|
|
|
|
const exec = util.promisify(_exec);
|
2021-12-04 12:19:47 +01:00
|
|
|
|
const scrypt = util.promisify(crypto.scrypt);
|
2021-05-19 14:19:26 +02:00
|
|
|
|
|
2021-04-17 10:43:23 +02:00
|
|
|
|
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
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2020-04-03 13:12:35 +02:00
|
|
|
|
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];
|
2021-12-04 12:19:47 +01:00
|
|
|
|
};
|
2020-04-09 18:44:09 +02:00
|
|
|
|
calcSpeed(b, s) {
|
2021-01-25 20:30:39 +01:00
|
|
|
|
return (Math.round((b * 8 / s / 1e6) * 1e4) / 1e4);
|
2021-12-04 12:19:47 +01:00
|
|
|
|
};
|
2021-04-17 10:43:23 +02:00
|
|
|
|
timeAgo(date) {
|
|
|
|
|
const { interval, epoch } = getDuration(~~((new Date() - new Date(date)) / 1e3));
|
|
|
|
|
return `${interval} ${epoch}${interval === 1 ? "" : "s"} ago`;
|
2021-12-04 12:19:47 +01:00
|
|
|
|
};
|
2021-05-19 14:19:26 +02:00
|
|
|
|
md5(str) {
|
|
|
|
|
return crypto.createHash('md5').update(str).digest("hex");
|
2021-12-04 12:19:47 +01:00
|
|
|
|
};
|
|
|
|
|
getMode(mode) {
|
|
|
|
|
let tmp;
|
|
|
|
|
switch(mode) {
|
|
|
|
|
case 1: // nsfw
|
2021-12-18 19:52:38 +01:00
|
|
|
|
tmp = "items.id in (select item_id from tags_assign where tag_id = 2 group by item_id)";
|
2021-12-04 12:19:47 +01:00
|
|
|
|
break;
|
|
|
|
|
case 2: // untagged
|
2021-12-18 19:52:38 +01:00
|
|
|
|
tmp = "items.id not in (select item_id from tags_assign group by item_id)";
|
2021-12-04 12:19:47 +01:00
|
|
|
|
break;
|
|
|
|
|
case 3: // all
|
2022-03-31 13:34:51 +02:00
|
|
|
|
tmp = "1 = 1";
|
2021-12-04 12:19:47 +01:00
|
|
|
|
break;
|
|
|
|
|
default: // sfw
|
2021-12-18 19:52:38 +01:00
|
|
|
|
tmp = "items.id in (select item_id from tags_assign where tag_id = 1 group by item_id)";
|
2021-12-04 12:19:47 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return tmp;
|
|
|
|
|
};
|
|
|
|
|
createID() {
|
|
|
|
|
return crypto.randomBytes(16).toString("hex") + Date.now().toString(24);
|
|
|
|
|
};
|
2021-12-06 10:21:11 +01:00
|
|
|
|
genLink(env) {
|
|
|
|
|
const link = [];
|
2021-12-18 19:52:38 +01:00
|
|
|
|
if(env.tag) link.push("tag", env.tag);
|
2021-12-29 16:26:44 +01:00
|
|
|
|
if(env.user) link.push("user", env.user, env.type ?? 'f0cks');
|
2021-12-06 10:21:11 +01:00
|
|
|
|
if(env.mime.length > 2) link.push(env.mime);
|
2022-05-06 17:01:42 +02:00
|
|
|
|
|
|
|
|
|
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 : ''
|
|
|
|
|
};
|
2021-12-06 10:21:11 +01:00
|
|
|
|
};
|
2021-12-18 19:52:38 +01:00
|
|
|
|
parseTag(tag) {
|
2021-12-20 17:55:47 +01:00
|
|
|
|
if(!tag)
|
|
|
|
|
return null;
|
2021-12-29 05:48:04 +01:00
|
|
|
|
return decodeURI(tag);
|
2021-12-18 19:52:38 +01:00
|
|
|
|
}
|
2021-12-04 12:19:47 +01:00
|
|
|
|
|
|
|
|
|
// async funcs
|
|
|
|
|
async countf0cks() {
|
2022-03-31 13:34:51 +02:00
|
|
|
|
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;
|
2021-12-04 12:19:47 +01:00
|
|
|
|
return {
|
|
|
|
|
tagged,
|
|
|
|
|
untagged,
|
2022-01-02 06:52:47 +01:00
|
|
|
|
total: +tagged + +untagged,
|
2021-12-04 12:19:47 +01:00
|
|
|
|
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);
|
|
|
|
|
};
|
2022-03-27 16:37:16 +02:00
|
|
|
|
async auth(req, res, next) {
|
|
|
|
|
if(!req.session) {
|
|
|
|
|
return res.reply({
|
|
|
|
|
code: 401,
|
|
|
|
|
body: "401 - Unauthorized"
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return next();
|
|
|
|
|
};
|
2021-12-20 17:55:47 +01:00
|
|
|
|
async getTags(itemid) {
|
2022-03-31 13:34:51 +02:00
|
|
|
|
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
|
|
|
|
|
`;
|
2021-12-29 05:48:04 +01:00
|
|
|
|
for(let t = 0; t < tags.length; t++) {
|
|
|
|
|
if(tags[t].tag.startsWith(">"))
|
|
|
|
|
tags[t].badge = "badge-greentext badge-light";
|
2022-03-27 16:37:16 +02:00
|
|
|
|
else if(tags[t].normalized === "ukraine")
|
2022-03-24 20:29:36 +01:00
|
|
|
|
tags[t].badge = "badge-ukraine badge-light";
|
2022-03-27 16:37:16 +02:00
|
|
|
|
else if(/[а-яё]/.test(tags[t].normalized) || tags[t].normalized === "russia")
|
2021-12-29 05:48:04 +01:00
|
|
|
|
tags[t].badge = "badge-russia badge-light";
|
2022-03-27 16:37:16 +02:00
|
|
|
|
else if(tags[t].normalized === "german")
|
2021-12-29 05:48:04 +01:00
|
|
|
|
tags[t].badge = "badge-german badge-light";
|
2022-03-27 16:37:16 +02:00
|
|
|
|
else if(tags[t].normalized === "dutch")
|
2022-01-04 21:04:05 +01:00
|
|
|
|
tags[t].badge = "badge-dutch badge-light";
|
2022-03-27 16:37:16 +02:00
|
|
|
|
else if(tags[t].normalized === "sfw")
|
2021-12-29 05:48:04 +01:00
|
|
|
|
tags[t].badge = "badge-success";
|
2022-03-27 16:37:16 +02:00
|
|
|
|
else if(tags[t].normalized === "nsfw")
|
2021-12-29 05:48:04 +01:00
|
|
|
|
tags[t].badge = "badge-danger";
|
|
|
|
|
else
|
|
|
|
|
tags[t].badge = "badge-light";
|
|
|
|
|
}
|
2021-12-20 17:55:47 +01:00
|
|
|
|
return tags;
|
|
|
|
|
};
|
2022-05-05 16:02:17 +02:00
|
|
|
|
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
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
};
|
2022-05-18 03:43:17 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
2021-12-04 12:19:47 +01:00
|
|
|
|
|
2020-04-03 13:12:35 +02:00
|
|
|
|
};
|