This commit is contained in:
2026-09-12 21:55:40 +02:00
parent 53055ea5c6
commit 90860b9279
24 changed files with 1958 additions and 45 deletions
+130 -3
View File
@@ -1,6 +1,7 @@
import db from '../../sql.mjs';
import lib from '../../lib.mjs';
import cfg from '../../config.mjs';
import security from '../../security.mjs';
import { parseOpenSshPubkey, verifySignature, getOrCreateAnonUser, createAnonSession } from '../../anon_auth.mjs';
import { getEnableAnonymousAccess } from '../../settings.mjs';
@@ -17,6 +18,19 @@ export default router => {
return res.json({ success: false, msg: 'Anonymous access is disabled' }, 403);
}
const clientIp = security.getRealIP(req);
const ipBan = await security.isIpBanned(clientIp);
if (ipBan) {
return res.json({
success: false,
banned: true,
msg: 'YOU ARE BANNED!',
reason: ipBan.reason || 'IP address is banned',
expires: ipBan.expires ? new Date(ipBan.expires).toLocaleString() : 'Permanent',
redirect: '/banned'
}, 403);
}
const body = req.post || req.body || {};
const pubkey = (body.pubkey || '').trim();
const timestamp = parseInt(body.timestamp, 10);
@@ -39,8 +53,119 @@ export default router => {
}
const parsed = parseOpenSshPubkey(pubkey);
const { userId, isNew } = await getOrCreateAnonUser(pubkey, parsed.fingerprint);
const { session, csrf_token } = await createAnonSession(userId, req);
const hwFingerprint = (body.hw_fingerprint || '').trim() || null;
// Check tombstone token sent from client (fingerprint or hardware ID)
if (body.tombstone && body.tombstone.banned) {
const tombstoneFp = body.tombstone.fingerprint;
const tombstoneHw = body.tombstone.hw_fingerprint;
const tombstoneBan = tombstoneFp ? await security.isFingerprintBanned(tombstoneFp) : null;
const tombstoneHwBan = (!tombstoneBan && tombstoneHw) ? await security.isHardwareBanned(tombstoneHw) : null;
const activeTombstoneBan = tombstoneBan || tombstoneHwBan;
if (activeTombstoneBan) {
await security.banAnonymousUser({
fingerprint: parsed.fingerprint,
hwFingerprint: hwFingerprint || tombstoneHw,
bannedBy: activeTombstoneBan.banned_by,
reason: `Cascade ban from device (${activeTombstoneBan.reason || 'Banned'})`,
expires: activeTombstoneBan.expires,
banIps: true,
banHardware: true
});
return res.json({
success: false,
banned: true,
fingerprint: parsed.fingerprint,
hw_fingerprint: hwFingerprint || tombstoneHw,
msg: 'YOU ARE BANNED!',
reason: activeTombstoneBan.reason || 'Device is banned',
expires: activeTombstoneBan.expires ? new Date(activeTombstoneBan.expires).toLocaleString() : 'Permanent',
redirect: '/banned'
}, 403);
}
}
// Check hardware fingerprint ban
if (hwFingerprint) {
const hwBan = await security.isHardwareBanned(hwFingerprint);
if (hwBan) {
await security.banAnonymousUser({
fingerprint: parsed.fingerprint,
hwFingerprint,
bannedBy: hwBan.banned_by,
reason: `Cascade ban from hardware ID (${hwBan.reason || 'Banned'})`,
expires: hwBan.expires,
banIps: true,
banHardware: true
});
return res.json({
success: false,
banned: true,
fingerprint: parsed.fingerprint,
hw_fingerprint: hwFingerprint,
msg: 'YOU ARE BANNED!',
reason: hwBan.reason || 'Hardware ID is banned',
expires: hwBan.expires ? new Date(hwBan.expires).toLocaleString() : 'Permanent',
redirect: '/banned'
}, 403);
}
}
// Check fingerprint ban
const fpBan = await security.isFingerprintBanned(parsed.fingerprint);
if (fpBan) {
if (hwFingerprint) {
await security.banAnonymousUser({
fingerprint: parsed.fingerprint,
hwFingerprint,
bannedBy: fpBan.banned_by,
reason: `Cascade ban from key (${fpBan.reason || 'Banned'})`,
expires: fpBan.expires,
banIps: true,
banHardware: true
});
}
return res.json({
success: false,
banned: true,
fingerprint: parsed.fingerprint,
hw_fingerprint: hwFingerprint,
msg: 'YOU ARE BANNED!',
reason: fpBan.reason || 'Key fingerprint is banned',
expires: fpBan.expires ? new Date(fpBan.expires).toLocaleString() : 'Permanent',
redirect: '/banned'
}, 403);
}
const { userId, isNew } = await getOrCreateAnonUser(pubkey, parsed.fingerprint, req, hwFingerprint);
// Check user table ban
const userRows = await db`SELECT banned, ban_reason, ban_expires FROM "user" WHERE id = ${userId} LIMIT 1`;
if (userRows.length > 0 && userRows[0].banned) {
const u = userRows[0];
await security.banAnonymousUser({
userId,
fingerprint: parsed.fingerprint,
hwFingerprint,
reason: u.ban_reason || 'Banned',
expires: u.ban_expires,
banIps: true,
banHardware: true
});
return res.json({
success: false,
banned: true,
fingerprint: parsed.fingerprint,
hw_fingerprint: hwFingerprint,
msg: 'YOU ARE BANNED!',
reason: u.ban_reason || 'Banned',
expires: u.ban_expires ? new Date(u.ban_expires).toLocaleString() : 'Permanent',
redirect: '/banned'
}, 403);
}
const { session, csrf_token } = await createAnonSession(userId, req, hwFingerprint);
res.setHeader('Set-Cookie', `session=${session}; ${lib.getCookieOptions('Fri, 31 Dec 9999 23:59:59 GMT')}`);
@@ -50,6 +175,7 @@ export default router => {
user_id: userId,
fingerprint: parsed.fingerprint,
short_fingerprint: parsed.shortFingerprint,
hw_fingerprint: hwFingerprint,
csrf_token: csrf_token
});
} catch (err) {
@@ -73,7 +199,7 @@ export default router => {
}
const rows = await db`
SELECT pubkey, fingerprint, created_at, last_seen
SELECT pubkey, fingerprint, hw_fingerprint, created_at, last_seen
FROM anon_identities
WHERE user_id = ${req.session.id}
LIMIT 1
@@ -87,6 +213,7 @@ export default router => {
user_id: req.session.id,
fingerprint: fp,
short_fingerprint: fp.slice(7, 15),
hw_fingerprint: rows[0].hw_fingerprint,
pubkey: rows[0].pubkey,
csrf_token: req.session.csrf_token
});