Saving of logs and users in SQLite Database. Added detailed logging

This commit is contained in:
Dennis Heinrich 2024-04-28 07:53:14 +02:00
parent 9ce846800e
commit 242144698b
8 changed files with 1082 additions and 24 deletions

3
.gitignore vendored
View file

@ -1,3 +1,4 @@
config.json config.json
node_modules node_modules
package-lock.json package-lock.json
database.sqlite

70
modules/database/index.js Normal file
View file

@ -0,0 +1,70 @@
const sqlite3 = require('sqlite3').verbose();
const { resolve } = require('path');
class Database {
constructor() {
this.db = new sqlite3.Database(resolve(__dirname, '../../database.sqlite'), (err) => {
if (err) {
console.error(err.message);
} else {
console.log('Connected to the database');
}
});
this.db.run('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, discord_id TEXT, discord_guild_id TEXT, ip TEXT, timestamp INTEGER)');
this.db.run('CREATE TABLE IF NOT EXISTS attempts (id INTEGER PRIMARY KEY, discord_id TEXT, discord_guild_id TEXT, ip TEXT, timestamp INTEGER, reason TEXT)');
}
async addAttempt(discordId, discordGuildId, ip, reason) {
return new Promise((resolve, reject) => {
this.db.run('INSERT INTO attempts (discord_id, discord_guild_id, ip, timestamp, reason) VALUES (?, ?, ?, ?, ?)', [discordId, discordGuildId, ip, Date.now(), reason], (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
async addUser(discordId, discordGuildId, ip) {
return new Promise((resolve, reject) => {
this.db.run('INSERT INTO users (discord_id, discord_guild_id, ip, timestamp) VALUES (?, ?, ?, ?)', [discordId, discordGuildId, ip, Date.now()], (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
async ipUsedInLastDay(ip) {
return new Promise((resolve, reject) => {
this.db.get('SELECT * FROM users WHERE ip = ? AND timestamp >= ?', [ip, Date.now() - 86400000], (err, row) => {
if (err) {
reject(err);
} else {
resolve(row !== undefined);
}
});
});
}
async isUserVerified(discordId, discordGuildId) {
return new Promise((resolve, reject) => {
this.db.get('SELECT * FROM users WHERE discord_id = ? AND discord_guild_id = ?', [discordId, discordGuildId], (err, row) => {
if (err) {
reject(err);
} else {
resolve(row !== undefined);
}
});
});
}
getDatabase() {
return this.db;
}
}
module.exports = new Database();

View file

@ -38,7 +38,7 @@ client.once(Events.ClientReady, readyClient => {
let embedBuilder = new EmbedBuilder() let embedBuilder = new EmbedBuilder()
.setTitle('Verifizierung erforderlich') .setTitle('Verifizierung erforderlich')
.setDescription('Um diesen Server nutzen zu können, musst du dich verifizieren. Dies kannst du tun, indem du auf den Button klickst.') .setDescription('Um diesen Server nutzen zu können, musst du dich verifizieren. Dies kannst du tun, indem du auf den Button klickst. Wurdest du in der Vergangenheit bereits einmal verifiziert, musst du dich durch einen Administrator manuell freischalten lassen.')
.setColor('#FF0000'); .setColor('#FF0000');
targetChannel.send({ embeds: [embedBuilder], components: [actionRow] }); targetChannel.send({ embeds: [embedBuilder], components: [actionRow] });

View file

@ -4,21 +4,27 @@ const express = require('express');
const expressApp = express(); const expressApp = express();
const event = require('../events/index').eventBus; const event = require('../events/index').eventBus;
const blacklist = require('../network/blacklist'); const blacklist = require('../network/blacklist');
const database = require('../database/index');
// This will load the blacklist and start the webserver when it's done // This will load the blacklist and start the webserver when it's done
blacklist.loadBlacklist().then(blacklist => { blacklist.loadBlacklist().then(blacklist => {
console.log('Network-Blacklist has been loaded') console.log('Network-Blacklist has been loaded')
expressApp.use('/', express.static(__dirname + '/public')); expressApp.use('/', express.static(__dirname + '/public'));
expressApp.use(IpFilter(blacklist)); expressApp.use(IpFilter(blacklist, { mode: 'allow' }));
expressApp.use(express.json()) expressApp.use(express.json())
expressApp.use((err, req, res, _next) => { expressApp.use((err, req, res, _next) => {
if (err instanceof IpDeniedError) { if(req.query) {
res.status(401) if(req.query.data && err instanceof IpDeniedError) {
res.json({ networkBlacklisted: err.message }) req.body = JSON.parse(Buffer.from(req.query.data, 'base64').toString('utf-8'));
} else { database.addAttempt(req.body.userId, req.body.guildId, req.headers['x-forwarded-for'] || req.socket.remoteAddress, "NETWORK_BLOCKED").then(() => {
res.status(err.status || 500) res.status(401)
res.json({ networkBlacklisted: err.message })
})
return;
}
} }
res.status(err.status || 500)
}) })
@ -37,20 +43,48 @@ blacklist.loadBlacklist().then(blacklist => {
formData.append('secret', turnstileSecret); formData.append('secret', turnstileSecret);
formData.append('response', turnstileToken); formData.append('response', turnstileToken);
fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify", { database.ipUsedInLastDay(internetProtocolAddress).then(ipUsed => {
body: formData, console.log('Verification request received, (IP, Discord-ID, Guild-ID)');
method: 'POST', console.info(internetProtocolAddress, authenticationObject.userId, authenticationObject.guildId);
}).then(response => response.json()).then(data => { if(ipUsed) {
if (data.success) { database.addAttempt(authenticationObject.userId, authenticationObject.guildId, internetProtocolAddress, "IP_USED").then(() => {
event.emit('verification:success', authenticationObject, internetProtocolAddress); console.log('IP-Address has been used in the last 24 hours');
res.json({ success: true }); res.json({ success: false, message: 'Die von dir genutzte IP-Adresse wurde erst kürzlich registriert. Probiere es später erneut.' });
});
} else { } else {
console.log('Verification failed'); database.isUserVerified(authenticationObject.userId, authenticationObject.guildId).then(userExists => {
res.json({ success: false }); if(!userExists) {
fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify", {
body: formData,
method: 'POST',
}).then(response => response.json()).then(data => {
if (data.success) {
// Add the user to the database and emit the verification success event
database.addUser(authenticationObject.userId, authenticationObject.guildId, internetProtocolAddress).then(() => {
event.emit('verification:success', authenticationObject, internetProtocolAddress);
res.json({ success: true, message: 'Die Authentifizierung war erfolgreich' });
});
} else {
database.addAttempt(authenticationObject.userId, authenticationObject.guildId, internetProtocolAddress, "CAPTCHA_FAIL").then(() => {
console.log('Verification failed');
res.json({ success: false, message: 'Das Captcha wurde nicht korrekt gelöst.' });
})
}
}).catch(error => {
database.addAttempt(authenticationObject.userId, authenticationObject.guildId, internetProtocolAddress, "ERROR").then(() => {
console.error(error);
res.json({ success: false, message: 'Bitte probiere es später erneut.' });
})
});
} else {
database.addAttempt(authenticationObject.userId, authenticationObject.guildId, internetProtocolAddress, "USER_VERIFIED_ALREADY").then(() => {
console.log('User already verified, potential risk');
res.json({ success: false, message: 'Das Konto wurde bereits in der Vergangenheit verifiziert. Wende dich an einen Admin um dich manuell freischalten zu lassen.' });
})
}
});
} }
}).catch(error => {
console.error(error);
res.json({ success: false });
}); });
}); });

View file

@ -6,7 +6,6 @@
<title>Verifizierung abschließen</title> <title>Verifizierung abschließen</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🔒</text></svg>"> <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🔒</text></svg>">
<link rel="stylesheet" href="./stylesheet/output.css"> <link rel="stylesheet" href="./stylesheet/output.css">
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback" defer></script>
<script src="./script.js"></script> <script src="./script.js"></script>
</head> </head>
<body class="bg-slate-900 text-white"> <body class="bg-slate-900 text-white">

View file

@ -1,5 +1,7 @@
function inititalize() { function inititalize() {
fetch('/turnstile/id') fetch(`/turnstile/id?data=${btoa(JSON.stringify(getUserData()))}`, {
method: 'GET',
})
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
if(data.networkBlacklisted) { if(data.networkBlacklisted) {
@ -10,6 +12,7 @@ function inititalize() {
failed('Kein Benutzer gefunden. Bitte versuchen Sie es erneut.'); failed('Kein Benutzer gefunden. Bitte versuchen Sie es erneut.');
return; return;
} }
window.onloadTurnstileCallback = function () { window.onloadTurnstileCallback = function () {
turnstile.render('#turnstile-container', { turnstile.render('#turnstile-container', {
sitekey: data.id, sitekey: data.id,
@ -18,6 +21,12 @@ function inititalize() {
}, },
}); });
}; };
// Load the turnstile script from Cloudflare, so that the callback function is available in the global scope
let newScriptElement = document.createElement('script');
newScriptElement.src = 'https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback';
newScriptElement.defer = true;
document.body.appendChild(newScriptElement);
}).catch((error) => { }).catch((error) => {
failed(error); failed(error);
}); });
@ -73,7 +82,7 @@ function sendVerification(turnstileToken, userData) {
success(); success();
// Check if the response was really successful (turnstile verification on the server side) // Check if the response was really successful (turnstile verification on the server side)
if(!data.success) { if(!data.success) {
failed(); failed(data.message);
} }
}) })
.catch((error) => { .catch((error) => {

View file

@ -18,7 +18,8 @@
"body-parser": "^1.20.2", "body-parser": "^1.20.2",
"discord.js": "^14.14.1", "discord.js": "^14.14.1",
"express": "^4.19.2", "express": "^4.19.2",
"express-ipfilter": "^1.3.2" "express-ipfilter": "^1.3.2",
"sqlite3": "^5.1.7"
}, },
"devDependencies": { "devDependencies": {
"tailwindcss": "^3.4.3" "tailwindcss": "^3.4.3"

File diff suppressed because it is too large Load diff