You've already forked fm-dx-webserver
mirror of
https://github.com/KubaPro010/fm-dx-webserver.git
synced 2026-02-26 22:13:53 +01:00
banlist & config fixes
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "fm-dx-webserver",
|
"name": "fm-dx-webserver",
|
||||||
"version": "1.3.2",
|
"version": "1.3.3",
|
||||||
"description": "FM DX Webserver",
|
"description": "FM DX Webserver",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ const { allPluginConfigs } = require('./plugins');
|
|||||||
// Endpoints
|
// Endpoints
|
||||||
router.get('/', (req, res) => {
|
router.get('/', (req, res) => {
|
||||||
let requestIp = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
let requestIp = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
||||||
if(serverConfig.webserver.banlist.includes(requestIp)) {
|
const normalizedIp = requestIp.replace(/^::ffff:/, '');
|
||||||
|
const isBanned = serverConfig.webserver.banlist.some(banEntry => banEntry[0] === normalizedIp);
|
||||||
|
|
||||||
|
if (isBanned) {
|
||||||
res.render('403');
|
res.render('403');
|
||||||
logInfo(`Web client (${requestIp}) is banned`);
|
logInfo(`Web client (${requestIp}) is banned`);
|
||||||
return;
|
return;
|
||||||
@@ -164,7 +167,12 @@ router.get('/rdsspy', (req, res) => {
|
|||||||
|
|
||||||
router.get('/api', (req, res) => {
|
router.get('/api', (req, res) => {
|
||||||
const { ps_errors, rt0_errors, rt1_errors, ims, eq, ant, st_forced, previousFreq, txInfo, ...dataToSend } = dataHandler.dataToSend;
|
const { ps_errors, rt0_errors, rt1_errors, ims, eq, ant, st_forced, previousFreq, txInfo, ...dataToSend } = dataHandler.dataToSend;
|
||||||
res.json(dataToSend);
|
res.json({
|
||||||
|
...dataToSend,
|
||||||
|
txInfo: txInfo,
|
||||||
|
ps_errors: ps_errors,
|
||||||
|
ant: ant
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -212,16 +220,47 @@ router.get('/kick', (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.get('/addToBanlist', (req, res) => {
|
router.get('/addToBanlist', (req, res) => {
|
||||||
const ipAddress = req.query.ip; // Extract the IP address parameter from the query string
|
const ipAddress = req.query.ip;
|
||||||
// Terminate the WebSocket connection for the specified IP address
|
const location = 'Unknown';
|
||||||
if(req.session.isAdminAuthenticated) {
|
const date = Date.now();
|
||||||
helpers.kickClient(ipAddress);
|
const reason = req.query.reason;
|
||||||
|
|
||||||
|
userBanData = [ipAddress, location, date, reason];
|
||||||
|
|
||||||
|
if (typeof serverConfig.webserver.banlist !== 'object') {
|
||||||
|
serverConfig.webserver.banlist = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.session.isAdminAuthenticated) {
|
||||||
|
serverConfig.webserver.banlist.push(userBanData);
|
||||||
|
configSave();
|
||||||
|
res.json({ success: true, message: 'IP address added to banlist.' });
|
||||||
|
helpers.kickClient(ipAddress);
|
||||||
|
} else {
|
||||||
|
res.status(403).json({ success: false, message: 'Unauthorized access.' });
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
|
||||||
res.redirect('/setup');
|
|
||||||
}, 500);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/removeFromBanlist', (req, res) => {
|
||||||
|
const ipAddress = req.query.ip;
|
||||||
|
|
||||||
|
if (typeof serverConfig.webserver.banlist !== 'object') {
|
||||||
|
serverConfig.webserver.banlist = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const banIndex = serverConfig.webserver.banlist.findIndex(ban => ban[0] === ipAddress);
|
||||||
|
|
||||||
|
if (banIndex === -1) {
|
||||||
|
return res.status(404).json({ success: false, message: 'IP address not found in banlist.' });
|
||||||
|
}
|
||||||
|
|
||||||
|
serverConfig.webserver.banlist.splice(banIndex, 1);
|
||||||
|
configSave();
|
||||||
|
|
||||||
|
res.json({ success: true, message: 'IP address removed from banlist.' });
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
router.post('/saveData', (req, res) => {
|
router.post('/saveData', (req, res) => {
|
||||||
const data = req.body;
|
const data = req.body;
|
||||||
let firstSetup;
|
let firstSetup;
|
||||||
@@ -290,6 +329,7 @@ router.get('/static_data', (req, res) => {
|
|||||||
rdsMode: serverConfig.webserver.rdsMode || false,
|
rdsMode: serverConfig.webserver.rdsMode || false,
|
||||||
tunerName: serverConfig.identification.tunerName || '',
|
tunerName: serverConfig.identification.tunerName || '',
|
||||||
tunerDesc: serverConfig.identification.tunerDesc || '',
|
tunerDesc: serverConfig.identification.tunerDesc || '',
|
||||||
|
ant: serverConfig.antennas || {}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -181,12 +181,15 @@ function antispamProtection(message, clientIp, ws, userCommands, lastWarn, userC
|
|||||||
if (userCommandHistory[clientIp].length >= 8) {
|
if (userCommandHistory[clientIp].length >= 8) {
|
||||||
consoleCmd.logWarn(`User \x1b[90m${clientIp}\x1b[0m is spamming with rapid commands. Connection will be terminated and user will be banned.`);
|
consoleCmd.logWarn(`User \x1b[90m${clientIp}\x1b[0m is spamming with rapid commands. Connection will be terminated and user will be banned.`);
|
||||||
|
|
||||||
// Add to banlist if not already banned
|
// Check if the normalized IP is already in the banlist
|
||||||
if (!serverConfig.webserver.banlist.includes(clientIp)) {
|
const isAlreadyBanned = serverConfig.webserver.banlist.some(banEntry => banEntry[0] === normalizedClientIp);
|
||||||
serverConfig.webserver.banlist.push(clientIp);
|
|
||||||
consoleCmd.logInfo(`User \x1b[90m${clientIp}\x1b[0m has been added to the banlist due to extreme spam.`);
|
if (!isAlreadyBanned) {
|
||||||
configSave();
|
// Add the normalized IP to the banlist
|
||||||
}
|
serverConfig.webserver.banlist.push([normalizedClientIp, 'Unknown', Date.now(), '[Auto ban] Spam']);
|
||||||
|
consoleCmd.logInfo(`User \x1b[90m${normalizedClientIp}\x1b[0m has been added to the banlist due to extreme spam.`);
|
||||||
|
configSave();
|
||||||
|
}
|
||||||
|
|
||||||
ws.close(1008, 'Bot-like behavior detected');
|
ws.close(1008, 'Bot-like behavior detected');
|
||||||
return command; // Return command value before closing connection
|
return command; // Return command value before closing connection
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ let configName = 'config';
|
|||||||
const index = process.argv.indexOf('--config');
|
const index = process.argv.indexOf('--config');
|
||||||
if (index !== -1 && index + 1 < process.argv.length) {
|
if (index !== -1 && index + 1 < process.argv.length) {
|
||||||
configName = process.argv[index + 1];
|
configName = process.argv[index + 1];
|
||||||
logInfo('Loading with a custom config file:', configName + '.json')
|
logInfo('Loading with a custom config file:', configName + '.json');
|
||||||
}
|
}
|
||||||
|
|
||||||
const configPath = path.join(__dirname, '../' + configName + '.json');
|
const configPath = path.join(__dirname, '../' + configName + '.json');
|
||||||
@@ -99,16 +99,19 @@ let serverConfig = {
|
|||||||
lockToAdmin: false,
|
lockToAdmin: false,
|
||||||
autoShutdown: false,
|
autoShutdown: false,
|
||||||
enableDefaultFreq: false,
|
enableDefaultFreq: false,
|
||||||
defaultFreq: "87.5"
|
defaultFreq: "87.5",
|
||||||
|
testThing: "yes it works"
|
||||||
};
|
};
|
||||||
|
|
||||||
function deepMerge(target, source)
|
function deepMerge(target, source) {
|
||||||
{
|
|
||||||
Object.keys(source).forEach(function(key) {
|
Object.keys(source).forEach(function(key) {
|
||||||
if (typeof target[key] === 'object' && target[key] !== null) {
|
if (typeof source[key] === 'object' && source[key] !== null) {
|
||||||
deepMerge(target[key], source[key]);
|
if (!target[key]) target[key] = {}; // Create missing object
|
||||||
|
deepMerge(target[key], source[key]); // Recursively merge
|
||||||
} else {
|
} else {
|
||||||
target[key] = source[key];
|
if (target[key] === undefined) {
|
||||||
|
target[key] = source[key]; // Add missing fields
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -124,7 +127,6 @@ function configUpdate(newConfig) {
|
|||||||
deepMerge(serverConfig, newConfig);
|
deepMerge(serverConfig, newConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function configSave() {
|
function configSave() {
|
||||||
fs.writeFile(configPath, JSON.stringify(serverConfig, null, 2), (err) => {
|
fs.writeFile(configPath, JSON.stringify(serverConfig, null, 2), (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -139,9 +141,16 @@ function configExists() {
|
|||||||
return fs.existsSync(configPath);
|
return fs.existsSync(configPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fs.existsSync(configPath)) {
|
if (configExists()) {
|
||||||
const configFileContents = fs.readFileSync(configPath, 'utf8');
|
const configFileContents = fs.readFileSync(configPath, 'utf8');
|
||||||
serverConfig = JSON.parse(configFileContents);
|
try {
|
||||||
|
const configFile = JSON.parse(configFileContents);
|
||||||
|
deepMerge(configFile, serverConfig);
|
||||||
|
serverConfig = configFile;
|
||||||
|
configSave();
|
||||||
|
} catch (err) {
|
||||||
|
logError('Error parsing config file:', err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -112,6 +112,10 @@ label {
|
|||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table .form-group {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
#settings, #back-btn, #users-online-container {
|
#settings, #back-btn, #users-online-container {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: 0;
|
border: 0;
|
||||||
|
|||||||
@@ -210,6 +210,10 @@
|
|||||||
background-color: var(--color-2) !important;
|
background-color: var(--color-2) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table .input-text {
|
||||||
|
background-color: var(--color-1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
.pointer {
|
.pointer {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
var currentDate = new Date('Nov 5, 2024 21:00:00');
|
var currentDate = new Date('Jan 11, 2025 21:00:00');
|
||||||
var day = currentDate.getDate();
|
var day = currentDate.getDate();
|
||||||
var month = currentDate.getMonth() + 1; // Months are zero-indexed, so add 1
|
var month = currentDate.getMonth() + 1; // Months are zero-indexed, so add 1
|
||||||
var year = currentDate.getFullYear();
|
var year = currentDate.getFullYear();
|
||||||
var formattedDate = day + '/' + month + '/' + year;
|
var formattedDate = day + '/' + month + '/' + year;
|
||||||
var currentVersion = 'v1.3.2 [' + formattedDate + ']';
|
var currentVersion = 'v1.3.3 [' + formattedDate + ']';
|
||||||
|
|
||||||
getInitialSettings();
|
getInitialSettings();
|
||||||
removeUrlParameters();
|
removeUrlParameters();
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
showPanelFromHash();
|
showPanelFromHash();
|
||||||
initNav();
|
initNav();
|
||||||
|
initBanlist();
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,6 +86,54 @@ function initNav() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initBanlist() {
|
||||||
|
$('.banlist-add').on('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const ipAddress = $('#banlist-add-ip').val();
|
||||||
|
const reason = $('#banlist-add-reason').val();
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: '/addToBanlist',
|
||||||
|
method: 'GET',
|
||||||
|
data: { ip: ipAddress, reason: reason },
|
||||||
|
success: function(response) {
|
||||||
|
// Refresh the page if the request was successful
|
||||||
|
if (response.success) {
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
console.error('Failed to add to banlist');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
console.error('Error occurred during the request');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.banlist-remove').on('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const ipAddress = $(this).closest('tr').find('td').first().text();
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: '/removeFromBanlist',
|
||||||
|
method: 'GET',
|
||||||
|
data: { ip: ipAddress },
|
||||||
|
success: function(response) {
|
||||||
|
if (response.success) {
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
console.error('Failed to remove from banlist');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
console.error('Error occurred during the request');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function toggleNav() {
|
function toggleNav() {
|
||||||
const navOpen = $("#navigation").css('margin-left') === '0px';
|
const navOpen = $("#navigation").css('margin-left') === '0px';
|
||||||
const isMobile = window.innerWidth <= 768;
|
const isMobile = window.innerWidth <= 768;
|
||||||
|
|||||||
148
web/setup.ejs
148
web/setup.ejs
@@ -101,7 +101,11 @@
|
|||||||
<% if (connectedUsers.length > 0) { %>
|
<% if (connectedUsers.length > 0) { %>
|
||||||
<% connectedUsers.forEach(user => { %>
|
<% connectedUsers.forEach(user => { %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="https://dnschecker.org/ip-location.php?ip=<%= user.ip %>" target="_blank"><%= user.ip %></a></td>
|
<td>
|
||||||
|
<a href="https://dnschecker.org/ip-location.php?ip=<%= user.ip.replace('::ffff:', '') %>" target="_blank">
|
||||||
|
<%= user.ip.replace('::ffff:', '') %>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
<td><%= user.location %></td>
|
<td><%= user.location %></td>
|
||||||
<td><%= user.time %></td>
|
<td><%= user.time %></td>
|
||||||
<td><a href="./kick?ip=<%= user.ip %>">Kick</a></td>
|
<td><a href="./kick?ip=<%= user.ip %>">Kick</a></td>
|
||||||
@@ -288,23 +292,6 @@
|
|||||||
<h3>RDS Mode</h3>
|
<h3>RDS Mode</h3>
|
||||||
<p>You can switch between American (RBDS) / Global (RDS) mode here.</p>
|
<p>You can switch between American (RBDS) / Global (RDS) mode here.</p>
|
||||||
<%- include('_components', {component: 'checkbox', cssClass: 'bottom-20', iconClass: '', label: 'American RDS mode (RBDS)', id: 'webserver-rdsMode'}) %><br>
|
<%- include('_components', {component: 'checkbox', cssClass: 'bottom-20', iconClass: '', label: 'American RDS mode (RBDS)', id: 'webserver-rdsMode'}) %><br>
|
||||||
<<<<<<< HEAD
|
|
||||||
</div>
|
|
||||||
<div class="panel-33">
|
|
||||||
<h3>Chat options</h3>
|
|
||||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Chat', id: 'webserver-chatEnabled'}) %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel-33 p-bottom-20" style="padding-left: 20px; padding-right: 20px;">
|
|
||||||
<h3>Banlist</h3>
|
|
||||||
<p>If you have users that don't behave on your server, you can choose to ban them by their IP address.<br>
|
|
||||||
<span class="text-gray">You can see their IP address by hovering over their nickname. One IP per row.</span></p>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="preset1">Banned users:</label>
|
|
||||||
<textarea id="webserver-banlist" placeholder="123.45.67.8"></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
=======
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -324,7 +311,6 @@
|
|||||||
<% }); %>
|
<% }); %>
|
||||||
</select><br><br>
|
</select><br><br>
|
||||||
<a href="https://github.com/NoobishSVK/fm-dx-webserver/wiki/Plugin-List" target="_blank">Download new plugins here!</a>
|
<a href="https://github.com/NoobishSVK/fm-dx-webserver/wiki/Plugin-List" target="_blank">Download new plugins here!</a>
|
||||||
>>>>>>> 4b6d011 (rewrite update)
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel-100 p-bottom-20">
|
<div class="panel-100 p-bottom-20">
|
||||||
@@ -444,98 +430,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel-full m-0 tab-content no-bg" id="tuner" role="tabpanel">
|
|
||||||
<h2>Tuner settings</h2>
|
|
||||||
<div class="flex-container contains-dropdown">
|
|
||||||
<div class="panel-33 p-bottom-20">
|
|
||||||
<h3>Device type</h3>
|
|
||||||
<%- include('_components', { component: 'dropdown', id: 'device-selector', inputId: 'device', label: 'Device', cssClass: '', placeholder: 'TEF668x / TEA685x',
|
|
||||||
options: [
|
|
||||||
{ value: 'tef', label: 'TEF668x / TEA685x' },
|
|
||||||
{ value: 'xdr', label: 'XDR (F1HD / S10HDiP)' },
|
|
||||||
{ value: 'sdr', label: 'SDR (RTL-SDR / AirSpy)' },
|
|
||||||
{ value: 'other', label: 'Other' }
|
|
||||||
]
|
|
||||||
}) %><br>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel-33 p-bottom-20" style="padding-right: 20px; padding-left: 20px;">
|
|
||||||
<h3>Connection type</h3>
|
|
||||||
<p class="text-gray">If you want to choose the COM port directly, choose "Direct".<br>If you use xdrd or your receiver is connected via Wi-Fi, choose TCP/IP.</p>
|
|
||||||
<div class="auto top-10">
|
|
||||||
<label class="toggleSwitch nolabel" onclick="">
|
|
||||||
<input id="xdrd-wirelessConnection" type="checkbox" tabindex="0" aria-label="Connection type"/>
|
|
||||||
<a></a>
|
|
||||||
<span>
|
|
||||||
<span class="left-span">Direct</span>
|
|
||||||
<span class="right-span">TCP/IP</span>
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="panel-33 p-bottom-20">
|
|
||||||
<h3>Device / Server</h3>
|
|
||||||
|
|
||||||
<div id="tuner-usb">
|
|
||||||
<p class="text-gray">Choose your desired <strong>COM port</strong><br> </p>
|
|
||||||
<%- include('_components', {
|
|
||||||
component: 'dropdown',
|
|
||||||
id: 'deviceList',
|
|
||||||
inputId: 'xdrd-comPort',
|
|
||||||
label: 'USB Device',
|
|
||||||
cssClass: '',
|
|
||||||
placeholder: 'Choose your USB device',
|
|
||||||
options: serialPorts.map(serialPort => ({
|
|
||||||
value: serialPort.path,
|
|
||||||
label: `${serialPort.path} - ${serialPort.friendlyName}`
|
|
||||||
}))
|
|
||||||
}) %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<div id="tuner-wireless">
|
|
||||||
<p class="text-gray">If you are connecting your tuner <strong>wirelessly</strong>, enter the tuner IP. <br> If you use <strong>xdrd</strong>, use 127.0.0.1 as your IP.</p>
|
|
||||||
<%- include('_components', {component: 'text', cssClass: 'w-150', label: 'xdrd IP address', id: 'xdrd-xdrdIp'}) %>
|
|
||||||
<%- include('_components', {component: 'text', cssClass: 'w-100', label: 'xdrd port', id: 'xdrd-xdrdPort'}) %>
|
|
||||||
<%- include('_components', {component: 'text', cssClass: 'w-150', label: 'xdrd password', id: 'xdrd-xdrdPassword', password: true}) %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex-container">
|
|
||||||
<div class="panel-50 p-bottom-20">
|
|
||||||
<h3>Startup</h3>
|
|
||||||
<h4>Startup volume</h4>
|
|
||||||
<div class="panel-75 auto" style="height: 48px;">
|
|
||||||
<input type="range" id="audio-startupVolume" min="0" max="1" step="0.01" value="1" aria-label="Startup Volume slider">
|
|
||||||
</div>
|
|
||||||
<h4 class="top-10 text-gray" id="volume-percentage-value"></h4>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<h4 class="bottom-20">Default frequency</h4>
|
|
||||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Default frequency for first client', id: 'enableDefaultFreq'}) %><br>
|
|
||||||
<%- include('_components', {component: 'text', cssClass: 'w-100', placeholder: '87.5', label: 'Default frequency', id: 'defaultFreq'}) %>
|
|
||||||
</div>
|
|
||||||
<div class="panel-50 p-bottom-20">
|
|
||||||
<h3>Miscellaneous</h3>
|
|
||||||
<div class="flex-container">
|
|
||||||
<div class="panel-50 no-bg">
|
|
||||||
<h4>Bandwidth switch</h4>
|
|
||||||
<p>Bandwidth switch allows the user to set the bandwidth manually.</p>
|
|
||||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Bandwidth switch', id: 'bwSwitch'}) %><br>
|
|
||||||
</div>
|
|
||||||
<div class="panel-50 no-bg">
|
|
||||||
<h4>Automatic shutdown</h4>
|
|
||||||
<p>Toggling this option will put the tuner to sleep when no clients are connected.</p>
|
|
||||||
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Auto-shutdown', id: 'autoShutdown'}) %><br>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
=======
|
|
||||||
>>>>>>> 4b6d011 (rewrite update)
|
|
||||||
<div class="panel-full m-0 tab-content no-bg" id="identification" role="tabpanel">
|
<div class="panel-full m-0 tab-content no-bg" id="identification" role="tabpanel">
|
||||||
<h2>Identification & Map</h2>
|
<h2>Identification & Map</h2>
|
||||||
|
|
||||||
@@ -578,16 +472,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<div class="panel-full m-0 tab-content no-bg" id="extras" role="tabpanel">
|
|
||||||
<h2>Extras</h2>
|
|
||||||
<div class="panel-100 p-bottom-20">
|
|
||||||
<h3>FMLIST Integration</h3>
|
|
||||||
<p>FMLIST integration allows you to get potential DXes logged on the <a href="http://fmlist.org/fm_logmap.php?hours=900" target="_blank" class="text-bold color-4">FMLIST Visual Logbook</a>.<br>
|
|
||||||
Your server also needs to have a valid UUID, which is obtained by registering on maps in the <strong>Identification & Map</strong> tab.</p>
|
|
||||||
<%- include('_components', {component: 'checkbox', cssClass: 'm-right-10', label: 'FMLIST integration', id: 'extras-fmlistIntegration'}) %><br>
|
|
||||||
|
|
||||||
=======
|
|
||||||
<div class="panel-full m-0 tab-content no-bg" id="users" role="tabpanel">
|
<div class="panel-full m-0 tab-content no-bg" id="users" role="tabpanel">
|
||||||
<h2>User management</h2>
|
<h2>User management</h2>
|
||||||
<div class="panel-100">
|
<div class="panel-100">
|
||||||
@@ -607,32 +491,41 @@
|
|||||||
<th>Location</th>
|
<th>Location</th>
|
||||||
<th>Ban date</th>
|
<th>Ban date</th>
|
||||||
<th>Reason</th>
|
<th>Reason</th>
|
||||||
<th class="color-5"><i class="fa-solid fa-plus-circle"></i></th>
|
<th class="color-5"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><%- include('_components', {component: 'text', cssClass: 'w-100', placeholder: 'IP address', label: '', id: 'banlist-add-ip'}) %></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td><%- include('_components', {component: 'text', cssClass: 'w-150', placeholder: 'Ban reason (note)', label: '', id: 'banlist-add-reason'}) %></td>
|
||||||
|
<td class="color-5">
|
||||||
|
<a href="#" id="banlist-add-link"><i class="fa-solid fa-plus-circle banlist-add"></i></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<% if (banlist.length > 0) { %>
|
<% if (banlist.length > 0) { %>
|
||||||
<% banlist.forEach(bannedUser => { %>
|
<% banlist.forEach(bannedUser => { %>
|
||||||
<tr>
|
<tr>
|
||||||
<% if (Array.isArray(bannedUser)) { %>
|
<% if (Array.isArray(bannedUser)) { %>
|
||||||
<!-- If it's an array, use its values -->
|
<!-- If it's an array, use its values -->
|
||||||
<td><a href="https://dnschecker.org/ip-location.php?ip=<%= bannedUser[0] %>" target="_blank"><%= bannedUser[0] %></a></td>
|
<td style="text-align: center !important;"><a href="https://dnschecker.org/ip-location.php?ip=<%= bannedUser[0] %>" target="_blank"><%= bannedUser[0] %></a></td>
|
||||||
<td><%= bannedUser[1] %></td>
|
<td><%= bannedUser[1] %></td>
|
||||||
<td class="text-bold"><%= new Date(parseInt(bannedUser[2]) * 1000).toLocaleString() %></td> <!-- Assuming the ban date is a timestamp in seconds -->
|
<td class="text-bold"><%= new Date(parseInt(bannedUser[2])).toLocaleString() %></td> <!-- Assuming the ban date is a timestamp in seconds -->
|
||||||
<td><%= bannedUser[3] %></td>
|
<td><%= bannedUser[3] %></td>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<!-- If it's just an IP address without additional data, show it as is -->
|
<!-- If it's just an IP address without additional data, show it as is -->
|
||||||
<td><a href="https://dnschecker.org/ip-location.php?ip=<%= bannedUser %>" target="_blank"><%= bannedUser %></a></td>
|
<td style="text-align: center !important;"><a href="https://dnschecker.org/ip-location.php?ip=<%= bannedUser %>" target="_blank"><%= bannedUser %></a></td>
|
||||||
<td>Unknown</td>
|
<td>Unknown</td>
|
||||||
<td class="text-bold">Unknown</td>
|
<td class="text-bold">Unknown</td>
|
||||||
<td>Unknown</td>
|
<td>Unknown</td>
|
||||||
<% } %>
|
<% } %>
|
||||||
<td><a href="./kick?ip=<%= Array.isArray(bannedUser) ? bannedUser[0] : bannedUser %>"><i class="fa-solid fa-lock-open text-gray"></i></a></td>
|
<td><a href="#" class="banlist-remove"><i class="fa-solid fa-lock-open text-gray"></i></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<% }); %>
|
<% }); %>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="6" style="text-align: center">The banlist is empty.</td>
|
<td colspan="5" style="text-align: center">The banlist is empty.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<% } %>
|
<% } %>
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -648,7 +541,6 @@
|
|||||||
Your server also needs to have a valid UUID, which is obtained by registering on maps in the <strong>Identification & Map</strong> tab.</p>
|
Your server also needs to have a valid UUID, which is obtained by registering on maps in the <strong>Identification & Map</strong> tab.</p>
|
||||||
<%- include('_components', {component: 'checkbox', cssClass: 'm-right-10', label: 'FMLIST integration', id: 'extras-fmlistIntegration'}) %><br>
|
<%- include('_components', {component: 'checkbox', cssClass: 'm-right-10', label: 'FMLIST integration', id: 'extras-fmlistIntegration'}) %><br>
|
||||||
|
|
||||||
>>>>>>> 4b6d011 (rewrite update)
|
|
||||||
<p>You can also fill in your OMID from FMLIST.org, if you want the logs to be saved to your account.</p>
|
<p>You can also fill in your OMID from FMLIST.org, if you want the logs to be saved to your account.</p>
|
||||||
<%- include('_components', {component: 'text', cssClass: 'w-100', placeholder: '', label: 'OMID', id: 'extras-fmlistOmid'}) %>
|
<%- include('_components', {component: 'text', cssClass: 'w-100', placeholder: '', label: 'OMID', id: 'extras-fmlistOmid'}) %>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user