var cfg = require('../../cfg.json'); var fs = require('fs-extra'); var http = require('http'); var https = require('https'); var mysql = require('mysql'); var bot = require('coffea')(); var uuid = require('uuid'); var crypto = require('crypto'); var path = require('path'); var exec = require('child_process').exec; var swig = require('swig'); var templates = {}; var debug = false; var sql; var haDC = () => { sql = mysql.createConnection(cfg.mysql); sql.connect((err) => { if(err) setTimeout(haDC,2000); }); sql.on('error', (err) => { if(err.code === 'PROTOCOL_CONNECTION_LOST') haDC(); }); }; haDC(); cfg.server.forEach((e,i,a) => { bot.add({ "name": e.name, "host": e.host, "port": e.port, "ssl": e.ssl, "ssl_allow_invalid": e.ssl_allow_invalid, "pass": e.pass, "nick": e.nick, "username": e.username, "realname": e.realname }); console.log("Server "+e.name+" wurde geladen"); }); var log = (msg) => { if(debug) bot.send("#f0ck", msg, 'n0xy'); }; bot.on('motd', (e) => { console.log("motd von "+e.network+" erhalten"); bot.write('MODE f0ck +B', e.network, (c)=>{}); // Botflag }); bot.on('message', (e) => { var orig = e.message; if(orig.match(/https?:\/\/[\w-]+(\.[\w-]+)+\.?(:\d+)?(\/\S*)?/gi) && e.channel.getName() == "#f0ck") { // shitpostcatcher if(!orig.match(/\!ignore$/)) { var tmp = orig.match(/https?:\/\/[\w-]+(\.[\w-]+)+\.?(:\d+)?(\/\S*)?/gi); // get links tmp.forEach((entry,i,a) => { var tmpdest = uuid.v1().split('-')[0]; dl(entry, "./b/"+tmpdest, (cb) => { // download item if(cb.status === true) { var tmpuser = getUser(e.user.getNick(), e.network); getCheckSum("./b/"+tmpdest+"."+cb.infos.ext, (cbcs) => { checkRepostCheckSum(cbcs, (cbcrcs) => { if(cbcrcs) { sql.query("insert into `f0ck`.`items` (`src`,`dest`,`mime`,`size`,`checksum`,`username`,`userchannel`,`usernetwork`,`stamp`,`thumb`,`active`) values (?,?,?,?,?,?,?,?,?,?,?)", [ entry, "./b/"+tmpdest+"."+cb.infos.ext, cb.infos.mime, cb.infos.size, cbcs, tmpuser['nick'], e.channel.getName(), e.network, Math.floor(new Date() / 1000), '', 0 ]).on('result', (result) => { generateThumbs(); e.reply("https://f0ck.me/"+result.insertId+" - "+path.parse(entry).base+" ("+cb.infos.mime+", ~"+formatSize(cb.infos.size)+") from "+tmpuser['nick']+" ("+tmpuser['username']+"@"+tmpuser['hostname']+")"); }).on('error', (msg) => { e.reply(msg); }); } else { fs.unlink("./b/"+tmpdest+"."+cb.infos.ext); // delete repost e.reply("repost motherf0cker"); } }); }); } else if(cb.type == 1) e.reply(cb.msg); }); }); } } else if(orig.match(/^\.user/)) { // (debug) get userinfos var tmp = getUser(e.user.getNick(), e.network); setTimeout(()=>{ e.reply(tmp); }, 1500); } else if(orig.match(/^\!reload tpl$/)) { getTpls(); e.reply("templates reloaded"); } else if(orig.match(/^\!toggle debug$/)) { if(debug) { debug = false; e.reply("debugmessages deactivated"); } else { debug = true; e.reply("debugmessages activated"); } } }); var getUser = (u, n) => { bot.whois(u, n, (fn)=>{ }); // send whois var start = Date.now(); while(Date.now() < start + 1000) {} // block script for catch whois return bot.getUser(u, n); }; var dl = (url, dest, cb) => { var request = (url.match(/^https/)?https:http).get(url, (response) => { // type:1=post,type:2=stfu console.log(response.headers['content-type']); if(cfg.allowedMimes.hasOwnProperty(response.headers['content-type'])) { if(response.headers['content-length'] <= cfg.maxFileSize) { checkRepost(url, (cbcr) => { if(cbcr) { var file = fs.createWriteStream(dest+"."+cfg.allowedMimes[response.headers['content-type']]); response.pipe(file); file.on('finish', () => { file.close(); cb({'status':true, 'msg':'downloaded '+dest, 'type':1, 'infos':{'mime':response.headers['content-type'], 'size':response.headers['content-length'], 'ext':cfg.allowedMimes[response.headers['content-type']]}}); }); file.on('error', (err) => { fs.unlink(dest); file.close(); cb({'status':false, 'msg':err.message, 'type':1}); }); } else cb({'status':false, 'msg':'repost motherf0cker', 'type':1}); }); } else cb({'status':false, 'msg':'f0ck! your file is too big (~'+formatSize(response.headers['content-length'])+'), max '+formatSize(cfg.maxFileSize)+' allowed', 'type':1}); } else cb({'status':false, 'msg':'f0ck you', 'type':2}); }).on('error', (msg) => { cb({'status':false, 'msg':msg, 'type':2}); }); }; var checkRepost = (url, cbcr) => { sql.query("select count(*) as count from `f0ck`.`items` where `src` = ?", url, (err, rows, fields) => { cbcr((rows[0].count == 0)?true:false); }); }; var checkRepostCheckSum = (cs, cbcrcs) => { sql.query("select count(*) as count from `f0ck`.`items` where `checksum` = ?", cs, (err, rows, fields) => { cbcrcs((rows[0].count == 0)?true:false); }); }; var formatSize = (size) => { var i = Math.floor(Math.log(size) / Math.log(1024)); return (size / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i]; }; var getCheckSum = (file, cbcs) => { var sha256sum = crypto.createHash('sha256'); var s = fs.ReadStream(file); s.on('data', (d) => { sha256sum.update(d); }); s.on('end', () => { var generated_hash = sha256sum.digest('hex'); cbcs(generated_hash); }); }; // Webserver http.createServer((req, res) => { var filePath = '.' + req.url; var url = req.url.split("/")[1]; if(filePath == './') filePath = './index.html'; var extname = String(path.extname(filePath)).toLowerCase(); var contentType = 'text/html'; var mimeTypes = { '.html': 'text/html', '.js': 'text/javascript', '.css': 'text/css', '.png': 'image/png', '.jpg': 'image/jpg', '.gif': 'image/gif', '.mp3': 'audio/mpeg', '.mp4': 'video/mp4', '.webm': 'video/webm', '.css': 'text/css', '.ogg': 'audio/ogg' }; if(filePath == "./index.html") { // mainpage var tpl = swig.compile(templates.index); var data = { items: [] }; sql.query("select * from `f0ck`.`items` order by `id` desc", (err, rows, fields) => { rows.forEach((e,i,a) => { data.items.push( e.id ); }); res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(tpl(data), 'utf-8'); }); } else if(Number.isInteger(parseInt(url))) { // itempage sql.query("select * from `f0ck`.`items` where `id` = ? limit 1; select `id` from `f0ck`.`items` where `id` = (select min(`id`) from `f0ck`.`items` where `id` > ?); select `id` from `f0ck`.`items` where `id` = (select max(`id`) from `f0ck`.`items` where `id` < ?); select `id` from `f0ck`.`items` order by `id` asc limit 1; select `id` from `f0ck`.`items` order by `id` desc limit 1", [url, url, url], (err, rows, fields) => { var tpl = swig.compile(templates.item); var data = { id: '', username: '', item: '', src: '', dest: '', mime: '', size: '', userchannel: '', usernetwork: '', next: null, prev: null, first: null, last: null }; if(rows[0].length) { var e = rows[0][0]; switch(e.mime) { case "image/png": case "image/jpeg": case "image/gif": data.item = 'image'; break; case "video/webm": case "video/mp4": data.item = 'video'; break; case "audio/mpeg": case "audio/ogg": data.item = 'audio'; break; } data.id = e.id; data.username = e.username; data.src = e.src; data.dest = e.dest; data.mime = e.mime; data.size = formatSize(e.size); data.userchannel = e.userchannel; data.usernetwork = e.usernetwork; if(rows[1].length) data.next = rows[1][0].id; if(rows[2].length) data.prev = rows[2][0].id; if(rows[3].length) data.first = rows[3][0].id; if(rows[4].length) data.first = rows[4][0].id; } res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(tpl(data), 'utf-8'); }); } else if(filePath == "./random") { sql.query("select `id` from `f0ck`.`items` order by rand() limit 1", (err, rows, fields) => { res.writeHead(301, { 'Cache-Control': 'no-cache, public', 'Location': '/' + rows[0].id }); res.end(); }); } else if(filePath == "./how") { var tpl = swig.compile(templates.how); res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(tpl(), 'utf-8'); } else if(filePath == "./contact") { var tpl = swig.compile(templates.contact); res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(tpl(), 'utf-8'); } else if(filePath == "./scripts") { var tpl = swig.compile(templates.scripts); res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(tpl(), 'utf-8'); } else if(filePath.match(/^\.\/(b|s|t)\/.*/)) { // file contentType = mimeTypes[extname]; switch(contentType) { case "video/webm": case "video/mp4": case "audio/mpeg": case "audio/ogg": var start = 0; var end = 0; var range = req.headers['range']; var stat = fs.statSync(filePath); if(range != null) { start = parseInt(range.slice(range.indexOf('bytes=')+6, range.indexOf('-'))); end = parseInt(range.slice(range.indexOf('-')+1, range.length)); } if(isNaN(end) || end == 0) end = stat.size-1; if(start > end) return; res.writeHead(206, { 'Connection':'close', 'Content-Type':contentType, 'Content-Length':end - start, 'Content-Range':'bytes '+start+'-'+end+'/'+stat.size, 'Transfer-Encoding':'chunked' }); var stream = fs.createReadStream(filePath, { flags: 'r', start: start, end: end}); stream.pipe(res); break; default: fs.readFile(filePath, (error, content) => { if(error) { if(error.code == 'ENOENT') { res.writeHead(200, { 'Content-Type': contentType }); res.end('404 - f0ck you', 'utf-8'); } else { res.writeHead(500); res.end('Sorry, check with the site admin for error: '+error.code+' ..\n'); res.end(); } } else { res.writeHead(200, { 'Content-Type': contentType, 'Content-Length': content.length, 'Cache-Control': 'max-age=2592000, public' }); res.end(content, 'utf-8'); } }); break; } fs.readFile(filePath, (error, content) => { if(error) { if(error.code == 'ENOENT') { res.writeHead(200, { 'Content-Type': contentType }); res.end('404 - f0ck you', 'utf-8'); } else { res.writeHead(500); res.end('Sorry, check with the site admin for error: '+error.code+' ..\n'); res.end(); } } else { } }); } else { // errorpage res.writeHead(404); res.end('404 - f0ck you', 'utf-8'); } }).listen(cfg.webserver.port); var getTpls = () => { templates = { "index": fs.readFileSync("./s/index.tpl.html", "utf-8"), "item": fs.readFileSync("./s/item.tpl.html", "utf-8"), "how": fs.readFileSync("./s/how.tpl.html", "utf-8"), "contact": fs.readFileSync("./s/contact.tpl.html", "utf-8"), "scripts": fs.readFileSync("./s/scripts.tpl.html", "utf-8") }; }; getTpls(); // Thumbnailbackgroundworker setInterval(()=>{generateThumbs();}, 60000); // 1 minute setTimeout(()=>{generateThumbs();}, 5000); // 5 seconds (start) var generateThumbs = () => { var outdir = './t/'; sql.query("select * from `f0ck`.`items` where `thumb` = ''", (err, rows, fields) => { rows.forEach((e,i,a) => { if(!fs.existsSync(outdir+e.id+'.png')) { exec('ffmpegthumbnailer -i'+e.dest+' -o'+outdir+e.id+'.png -a', (error) => { if(error) { log("failed thumbnail for "+e.id+" ("+e.mime+")"); fs.unlink(outdir+e.id+'.png'); // fs.copySync('./s/mp3.png', outdir+e.id+'.png'); // copy standardthumbnail } else log("generated thumbnail for "+e.id+" ("+e.mime+")"); }); } }); }); };