import { Hono } from 'hono'
import { serve } from '@hono/node-server'
import { stream, streamText, streamSSE } from 'hono/streaming'
import {
deleteCookie,
getCookie,
setCookie,
} from 'hono/cookie'
import * as fs from 'node:fs'
import * as fsPromises from 'node:fs/promises'
var port = parseInt(process.argv[2]) || 15345;
var prefix = process.argv[3] || "/84/_verify";
var cookie_name = process.argv[4] || "_cgwall_token";
var dirname = import.meta.dirname ?? new URL('.', import.meta.url).pathname;
var auths = new Map();
var auths_dirty = false;
try {
for (let [k,v] of Object.entries(JSON.parse(fs.readFileSync(dirname+'/cookies.json')))) {
auths.set(k, v);
}
auths_dirty = true;
} catch {}
async function saveCache() {
if (!auths_dirty) return;
glog("Saving cookies");
await fsPromises.writeFile(dirname+'/cookies.json', JSON.stringify(Object.fromEntries(
[...auths.entries()].filter(([_,v]) => !v.prepping)
)));
auths_dirty = false;
}
glog('sigmawall', dirname)
function randstr() {
return [...crypto.getRandomValues(new Uint8Array(32))].map(e=>e.toString(16).padStart(2,0)).join('');
}
var app = Object.assign(new Hono(), {
port
});
function glog(...msg) {
console.log(`[${(new Date()).toGMTString()}]`, ...msg);
}
function log(key, ...msg) {
glog(`[${(key??'?'.repeat(64)).substr(0,8)}]`, ...msg)
}
app.get(`${prefix}/reset`, async (c) => {
var key, auth;
if ((auth = auths.get(key = getCookie(c, cookie_name)))) {
auth.expire = Date.now();
keyValid(key);
}
return c.text("meow");
});
app.all("*", async (c, next) => {
var key;
keyValid(getCookie(c, cookie_name));
log(getCookie(c, cookie_name), 'Checking req', auths.get(getCookie(c, cookie_name)));
if ((key = auths.get(getCookie(c, cookie_name))) && key.status) {
keyValid(getCookie(c, cookie_name), 10000);
c.status(421);
return c.text("Success");
}
log(getCookie(c, cookie_name), 'Verification required');
if (c.req.method != "GET") {
log(getCookie(c, cookie_name), 'Non-GET denied');
c.status(403);
return c.text("Unauthorized");
}
return next();
});
var templ = str => `
anti-scraper protection
${str}`;
var funcs = new Map();
app.get(`${prefix}/:key`, async (c) => {
let fn = funcs.get(c.req.param('key'));
if (fn) {
try {
await fn(c);
} catch(e) {
console.error(e);
}
c.status(200);
return c.text('if you see this, Go Back');
}
c.status(404);
return c.text("wack");
});
function newfunc(fn) {
var key = randstr();
var obj;
funcs.set(key, (...args) => obj.fn(...args));
return obj = {
fn,
remove() {
funcs.delete(key);
},
key
};
}
function keyValid(key, extend) {
var auth;
if (!(auth = auths.get(key)))
return false;
if (Date.now() >= auth.expire) {
if (!auth.prepping) {
auths_dirty = true;
}
expsig(key);
auths.delete(key);
return false;
}
if (extend != null) {
if (auth.real_expire == null && Date.now()+extend >= auth.expire) {
auth.real_expire = auth.expire;
auth.expire = Date.now()+extend;
}
}
return true;
}
function on_expire(key) {
var auth;
if (!(auth = auths.get(key)))
return false;
auth.expsigs = auth.expsigs ?? new Set();
var fn;
return Object.assign(new Promise(succ => auth.expsigs.add(fn = succ)), {
remove() {
auth.expsigs.delete(fn);
}
});
}
function expsig(key) {
var auth;
if (!(auth = auths.get(key)))
return false;
for (let fn of (auth.expsigs ?? new Set())) {
fn(); auth.expsigs.delete(fn);
}
return true;
}
var conns = 0;
app.get("*", async (c) => {
return streamText(c, async(stream) => { conns++; try {
c.header('X-Accel-Buffering', 'no');
c.header('Content-Type', 'text/html; charset=utf-8');
if ((!(c.req.header('User-Agent')||''+'').match(/^Links /))
&&(!((c.req.header('Accept')||'')+'').match(/^text\/html/))) {
return;
}
var closed = false;
var banned = false;
var pass;
var key;
var auth = auths.get(key = getCookie(c, cookie_name));
function boop() {
var oauth = auths.get(key);
if (oauth && !oauth.prepping)
throw new Error("can't boop non-prep");
auths.set(key, auth = Object.assign(oauth ?? {}, {
prepping: true, expire: Date.now() + 1000*60*5
}));
}
var finp, finf;
function nfinp() {
finp = new Promise((succ) => finf = succ);
}
if (auth && (!auth.prepping)) {
log(key, 'Rejected due to ban');
await stream.write(templ(`Sorry but you pressed the get banned button return in ${(auth.expire - Date.now())/1000} seconds.`));
return;
} else if (!auth) {
key = randstr()
log(getCookie(c, cookie_name), 'Setting cookie', key);
setCookie(c, cookie_name, key);
c.req.raw.signal.addEventListener('abort', () => {
running = false;
closed = true;
stream.abort();
});
boop();
(o => (o.users = 0, o.expire = Date.now() + 30*1000))(auths.get(key));
if (!closed)
await stream.write(templ(
` `+
`
redirecting...
`
));
log(key, 'Cookie set complete');
return;
}
pass = -2;
if ((o => o.users)(auths.get(key))) {
await stream.write(templ(`Verification ongoing in another window. Waiting... `));
return;
} else {
(o => o.users = (o.users ?? 0) + 1)(auths.get(key));
}
boop();
nfinp();
c.req.raw.signal.addEventListener('abort', () => {
log(key, 'Aborted');
closed = true;
finf();
if (keyValid(key) && (o => o.prepping && !--o.users)(auths.get(key))) {
log(key, 'Deleted');
auths.delete(key);
}
stream.abort();
});
var banner = newfunc(function() {
banned = true;
finf();
log(key, 'Foolish user banned');
auths_dirty = true;
expsig(key);
auths.set(key, { expire: Date.now()+1000*30, status: false });
if (verb)
verb.remove();
this.remove();
banner = null;
});
await stream.write(templ(`
click here if you want to get banned for 30 seconds.
otherwise, click the Verify button when it appears.
`));
await stream.write(`
Please ignore the following text: { ${`dummy content for webkit `.repeat(20)} }
`);
var lastonly_i = 0;
async function lastonly_b() {
await stream.write(``);
}
await lastonly_b();
async function dumpflush(i) {}
await dumpflush();
async function fakebusy(time = 500) {
await lastonly_b();
await stream.write(`
Processing`);
for (let i=0; i<10; i++) {
await stream.sleep(time / 10);
await stream.write('.');
}
await stream.write(`
`);
}
await fakebusy(1000);
function fincookie() {
auths.set(key, { expire: Date.now()+1000*60*60, status: true }); // 1 hour
auths_dirty = true;
}
var verb = newfunc(function () {
pass=3;
finf();
fincookie();
log(key, 'Checks passed');
this.remove();
verb = null;
});
var msg = 'Challenge failed. Refresh page.';
var imgl = false;
var imgls = false;
var imge = Date.now() + 50;
while ((!closed) && keyValid(key) && auths.get(key).prepping) {
var exp;
await Promise.race([
new Promise(succ => setTimeout(succ, Math.min(Math.max(auths.get(key).expire - Date.now(), 50), 5000))),
...((!imgl) ? [(new Promise(succ => setTimeout(succ, Math.max(imge - Date.now(), 0)))).then(_ => imgl=true)] : []),
finp.then(nfinp),
exp = on_expire(key)
]);
if ((imgl && !imgls) && !closed) {
imgls = true;
log(key, 'Serving enter button');
await lastonly_b();
await stream.write(`
`);
}
exp.remove();
if (!closed)
await stream.write(' ');
if (banned) {
msg = 'You are now banned for 30 seconds';
break;
}
if (pass == 3) {
log(key, auths.get(key));
msg = 'You are in. Redirecting...
';
break;
}
}
if (banner)
banner.remove();
if (verb)
verb.remove()
if (!closed)
await stream.write('
'+msg);
} finally { conns--; } });
});
setInterval(async function() {
for (let [k,v] of auths.entries()) {
keyValid(k);
}
await saveCache();
}, 5000)
var lastconns=-1;
setInterval(function() {
let prepauths = new Map([...auths.entries()].filter(e=>e[1].prepping)).size;
let connsc = conns | prepauths | funcs.size;
if (!(connsc == 0 && lastconns == 0))
glog(`${conns} connections.. ${prepauths} prepauths.. ${funcs.size} funcs`);
lastconns = connsc;
}, 5000);
serve(app);