feat(MikrotikConnection): add MikroTik connection testing functionality in ServerModal; update API routes and README for new encryption key and connection endpoint
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 2m13s

This commit is contained in:
2026-02-03 19:12:32 +07:00
parent 0ea0f376a6
commit 1a27217676
7 changed files with 350 additions and 52 deletions
+5 -45
View File
@@ -302,51 +302,10 @@ app.post('/api/ip-ranges', writeLimiter, ipRangesRoutes.post);
// === JSON DATA ROUTES (используют фабрики) ===
// Servers
const SERVER_TYPES = ['jumphost', 'exit', 'bgp', 'dns', 'home'];
const TYPES_NEED_TUNNEL = ['jumphost', 'exit']; // Типы, которым нужен туннель
const TYPES_NEED_GATEWAYS = ['jumphost', 'exit']; // Типы, которым нужны gateways
const serversRoutes = createJsonDataRoutes('servers.json', (server, i) => {
// Базовые обязательные поля
if (!server.ip || !server.dns || !server.country || !server.provider) {
return `Server at index ${i} is missing required fields (ip, dns, country, provider)`;
}
const normalizedType = String(server.type || '').toLowerCase();
if (!SERVER_TYPES.includes(normalizedType)) {
return `Server at index ${i} has invalid type (allowed: ${SERVER_TYPES.join(', ')})`;
}
// Туннель обязателен только для jumphost и exit
if (TYPES_NEED_TUNNEL.includes(normalizedType) && !server.tunnel) {
return `Server at index ${i} (${normalizedType}) requires tunnel type`;
}
// Gateways обязательны только для jumphost и exit
if (TYPES_NEED_GATEWAYS.includes(normalizedType)) {
if (!Array.isArray(server.gateways) || server.gateways.length === 0) {
return `Server at index ${i} must have gateways for type ${normalizedType}`;
}
const primaries = server.gateways.filter(g => g && g.primary);
if (primaries.length !== 1) {
return `Server at index ${i} must have exactly one primary gateway`;
}
for (let j = 0; j < server.gateways.length; j++) {
const gw = server.gateways[j] || {};
if (!gw.name || String(gw.name).trim().length === 0) {
return `Server at index ${i} gateway at index ${j} is missing name`;
}
}
}
// Нормализуем тип, чтобы в S3 всегда лежали одинаковые значения
server.type = normalizedType;
return null;
});
app.get('/api/servers', serversRoutes.get);
app.post('/api/servers', serversRoutes.post);
// Servers (кастомные роуты с поддержкой зашифрованных MikroTik учётных данных для jumphost)
const serversRoutes = require('./routes/serversRoutes');
app.get('/api/servers', serversRoutes.getServers);
app.post('/api/servers', serversRoutes.postServers);
// Server connections for topology graph
const serverConnectionsRoutes = createJsonDataRoutes('server-connections.json', (conn, i) => {
@@ -490,6 +449,7 @@ app.delete('/api/ipsec-passwords/:id', writeLimiter, ipsecPasswordsRoutes.delete
app.post('/api/mikrotik/generate', mikrotikConfigRoutes.generateMikrotikConfig);
app.get('/api/mikrotik/generate-interfaces', mikrotikConfigRoutes.generateInterfaces);
app.get('/api/mikrotik/generate-recursive-routes', mikrotikConfigRoutes.generateRecursiveRoutes);
app.post('/api/mikrotik/test-connection', mikrotikConfigRoutes.testMikrotikConnection);
// === MIKROTIK VALIDATION ===
app.post('/api/mikrotik/validate', async (req, res) => {