feat: новая функция
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const { promisify } = require('util');
|
const { promisify } = require('util');
|
||||||
|
const { domainToASCII } = require('url');
|
||||||
const dns = require('dns');
|
const dns = require('dns');
|
||||||
const resolve4 = promisify(dns.resolve4);
|
const resolve4 = promisify(dns.resolve4);
|
||||||
|
|
||||||
@@ -30,10 +31,21 @@ router.get('/dns-check/:domain', async (req, res) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Checking DNS for domain: ${domain}`);
|
const normalizedDomain = domain.trim().toLowerCase();
|
||||||
|
const asciiDomain = domainToASCII(normalizedDomain);
|
||||||
|
|
||||||
|
if (!asciiDomain) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
domain,
|
||||||
|
message: `Некорректное доменное имя: ${domain}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Checking DNS for domain: ${domain} (ASCII: ${asciiDomain})`);
|
||||||
|
|
||||||
// Используем встроенный DNS resolver Node.js
|
// Используем встроенный DNS resolver Node.js
|
||||||
const addresses = await resolve4(domain);
|
const addresses = await resolve4(asciiDomain);
|
||||||
|
|
||||||
if (addresses && addresses.length > 0) {
|
if (addresses && addresses.length > 0) {
|
||||||
const ip = addresses[0];
|
const ip = addresses[0];
|
||||||
|
|||||||
@@ -1,21 +1,189 @@
|
|||||||
const winston = require('winston');
|
const winston = require('winston');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
|
const SENSITIVE_KEY_REGEX = /(address|wallet|signature|provider_id|private|secret|rpc|api(?:key)?|auth|token_address|contract)/i;
|
||||||
|
const IPV4_REGEX = /\b(\d{1,3}\.){3}\d{1,3}\b/g;
|
||||||
|
const IPV6_REGEX = /([a-f0-9]{1,4}:){1,7}[a-f0-9]{1,4}/gi;
|
||||||
|
const ETH_ADDRESS_REGEX = /0x[a-fA-F0-9]{40}/g;
|
||||||
|
const ETH_TX_REGEX = /0x[a-fA-F0-9]{64}/g;
|
||||||
|
const EMAIL_REGEX = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi;
|
||||||
|
|
||||||
|
const maskEthereumAddress = (value) => {
|
||||||
|
return value.replace(ETH_ADDRESS_REGEX, (match) => `${match.slice(0, 6)}...${match.slice(-4)}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const maskEthereumHash = (value) => {
|
||||||
|
return value.replace(ETH_TX_REGEX, (match) => `${match.slice(0, 10)}...${match.slice(-6)}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const maskIpAddresses = (value) => {
|
||||||
|
return value
|
||||||
|
.replace(IPV4_REGEX, '***.***.***.***')
|
||||||
|
.replace(IPV6_REGEX, '[REDACTED_IP]');
|
||||||
|
};
|
||||||
|
|
||||||
|
const maskEmails = (value) => {
|
||||||
|
return value.replace(EMAIL_REGEX, (match) => {
|
||||||
|
const [local, domain] = match.split('@');
|
||||||
|
if (!domain) {
|
||||||
|
return '[REDACTED_EMAIL]';
|
||||||
|
}
|
||||||
|
const hiddenLocal = local.length <= 2 ? '**' : `${local.slice(0, 2)}***`;
|
||||||
|
return `${hiddenLocal}@${domain}`;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const redactString = (value) => {
|
||||||
|
if (!value) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
let sanitized = value;
|
||||||
|
sanitized = maskEthereumAddress(sanitized);
|
||||||
|
sanitized = maskEthereumHash(sanitized);
|
||||||
|
sanitized = maskIpAddresses(sanitized);
|
||||||
|
sanitized = maskEmails(sanitized);
|
||||||
|
return sanitized;
|
||||||
|
};
|
||||||
|
|
||||||
|
const sanitizeValue = (value, keyPath = '', seen = new WeakSet()) => {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
if (SENSITIVE_KEY_REGEX.test(keyPath)) {
|
||||||
|
return '[REDACTED]';
|
||||||
|
}
|
||||||
|
return redactString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value === 'number') {
|
||||||
|
if (SENSITIVE_KEY_REGEX.test(keyPath)) {
|
||||||
|
return '[REDACTED]';
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!value || typeof value !== 'object') {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seen.has(value)) {
|
||||||
|
return '[REDACTED]';
|
||||||
|
}
|
||||||
|
seen.add(value);
|
||||||
|
|
||||||
|
if (value instanceof Error) {
|
||||||
|
const sanitizedError = {};
|
||||||
|
Object.getOwnPropertyNames(value).forEach((prop) => {
|
||||||
|
sanitizedError[prop] = sanitizeValue(value[prop], `${keyPath}.${prop}`, seen);
|
||||||
|
});
|
||||||
|
return sanitizedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.map((item, index) => sanitizeValue(item, `${keyPath}[${index}]`, seen));
|
||||||
|
}
|
||||||
|
|
||||||
|
const sanitizedObject = {};
|
||||||
|
Object.keys(value).forEach((key) => {
|
||||||
|
const nextPath = keyPath ? `${keyPath}.${key}` : key;
|
||||||
|
if (SENSITIVE_KEY_REGEX.test(key)) {
|
||||||
|
sanitizedObject[key] = '[REDACTED]';
|
||||||
|
} else {
|
||||||
|
sanitizedObject[key] = sanitizeValue(value[key], nextPath, seen);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return sanitizedObject;
|
||||||
|
};
|
||||||
|
|
||||||
|
const sanitizeInfo = (info) => {
|
||||||
|
const sanitizedInfo = { ...info };
|
||||||
|
sanitizedInfo.message = sanitizeValue(info.message, 'message');
|
||||||
|
const splat = Symbol.for('splat');
|
||||||
|
if (info[splat]) {
|
||||||
|
sanitizedInfo[splat] = info[splat].map((entry, index) => sanitizeValue(entry, `splat[${index}]`));
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(info).forEach((key) => {
|
||||||
|
if (['level', 'message', 'timestamp'].includes(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sanitizedInfo[key] = sanitizeValue(info[key], key);
|
||||||
|
});
|
||||||
|
|
||||||
|
return sanitizedInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
const sanitizeFormat = winston.format((info) => sanitizeInfo(info));
|
||||||
|
|
||||||
|
const jsonFormat = winston.format.combine(
|
||||||
|
sanitizeFormat(),
|
||||||
|
winston.format.timestamp(),
|
||||||
|
winston.format.json()
|
||||||
|
);
|
||||||
|
|
||||||
|
const consoleFormat = winston.format.combine(
|
||||||
|
sanitizeFormat(),
|
||||||
|
winston.format.timestamp(),
|
||||||
|
winston.format.colorize({ all: true }),
|
||||||
|
winston.format.printf((info) => {
|
||||||
|
const { timestamp, level, message, ...rest } = info;
|
||||||
|
const metaParts = [];
|
||||||
|
const splat = info[Symbol.for('splat')];
|
||||||
|
if (splat && Array.isArray(splat)) {
|
||||||
|
splat.forEach((entry) => {
|
||||||
|
if (entry === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof entry === 'string') {
|
||||||
|
metaParts.push(entry);
|
||||||
|
} else {
|
||||||
|
metaParts.push(JSON.stringify(entry));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(rest)
|
||||||
|
.filter((key) => !['level', 'message', 'timestamp'].includes(key))
|
||||||
|
.forEach((key) => {
|
||||||
|
if (key === Symbol.for('splat')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const value = rest[key];
|
||||||
|
if (value !== undefined) {
|
||||||
|
metaParts.push(`${key}=${JSON.stringify(value)}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const metaString = metaParts.length ? ` ${metaParts.join(' ')}` : '';
|
||||||
|
return `${timestamp} ${level}: ${message}${metaString}`;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const logger = winston.createLogger({
|
const logger = winston.createLogger({
|
||||||
level: process.env.LOG_LEVEL || 'info', // Уровень по умолчанию 'info' для показа логов ботов
|
level: process.env.LOG_LEVEL || 'info',
|
||||||
format: winston.format.combine(winston.format.timestamp(), winston.format.json()),
|
format: jsonFormat,
|
||||||
transports: [
|
transports: [
|
||||||
new winston.transports.Console({
|
new winston.transports.Console({
|
||||||
format: winston.format.combine(winston.format.colorize(), winston.format.simple()),
|
format: consoleFormat,
|
||||||
}),
|
}),
|
||||||
new winston.transports.File({
|
new winston.transports.File({
|
||||||
filename: path.join(__dirname, '../logs/error.log'),
|
filename: path.join(__dirname, '../logs/error.log'),
|
||||||
level: 'error',
|
level: 'error',
|
||||||
|
format: jsonFormat,
|
||||||
}),
|
}),
|
||||||
new winston.transports.File({
|
new winston.transports.File({
|
||||||
filename: path.join(__dirname, '../logs/combined.log'),
|
filename: path.join(__dirname, '../logs/combined.log'),
|
||||||
|
format: jsonFormat,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const wrapConsoleMethod = (methodName) => {
|
||||||
|
const original = console[methodName].bind(console);
|
||||||
|
console[methodName] = (...args) => {
|
||||||
|
const sanitizedArgs = args.map((arg, index) => sanitizeValue(arg, `${methodName}[${index}]`));
|
||||||
|
original(...sanitizedArgs);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
['log', 'info', 'warn', 'error', 'debug'].forEach(wrapConsoleMethod);
|
||||||
|
|
||||||
module.exports = logger;
|
module.exports = logger;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ const WebSocket = require('ws');
|
|||||||
const tokenBalanceService = require('./services/tokenBalanceService');
|
const tokenBalanceService = require('./services/tokenBalanceService');
|
||||||
const deploymentTracker = require('./utils/deploymentTracker');
|
const deploymentTracker = require('./utils/deploymentTracker');
|
||||||
const deploymentWebSocketService = require('./services/deploymentWebSocketService');
|
const deploymentWebSocketService = require('./services/deploymentWebSocketService');
|
||||||
|
const logger = require('./utils/logger');
|
||||||
|
|
||||||
let wss = null;
|
let wss = null;
|
||||||
// Храним клиентов по userId для персонализированных уведомлений
|
// Храним клиентов по userId для персонализированных уведомлений
|
||||||
@@ -29,7 +30,7 @@ const TAGS_UPDATE_DEBOUNCE = 100; // 100ms
|
|||||||
|
|
||||||
function initWSS(server) {
|
function initWSS(server) {
|
||||||
wss = new WebSocket.Server({ server, path: '/ws' });
|
wss = new WebSocket.Server({ server, path: '/ws' });
|
||||||
console.log('🔌 [WebSocket] Сервер инициализирован на пути /ws');
|
logger.info('🔌 [WebSocket] Сервер инициализирован на пути /ws');
|
||||||
|
|
||||||
// Инициализируем deploymentWebSocketService с WebSocket сервером после создания wss
|
// Инициализируем deploymentWebSocketService с WebSocket сервером после создания wss
|
||||||
deploymentWebSocketService.initialize(server, wss);
|
deploymentWebSocketService.initialize(server, wss);
|
||||||
@@ -40,15 +41,15 @@ function initWSS(server) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Дополнительная инициализация deploymentWebSocketService после создания wss
|
// Дополнительная инициализация deploymentWebSocketService после создания wss
|
||||||
console.log('[wsHub] Инициализируем deploymentWebSocketService с wss:', !!wss);
|
logger.debug('[wsHub] Инициализируем deploymentWebSocketService с wss:', !!wss);
|
||||||
deploymentWebSocketService.setWebSocketServer(wss);
|
deploymentWebSocketService.setWebSocketServer(wss);
|
||||||
console.log('[wsHub] deploymentWebSocketService инициализирован');
|
logger.debug('[wsHub] deploymentWebSocketService инициализирован');
|
||||||
|
|
||||||
wss.on('connection', (ws, req) => {
|
wss.on('connection', (ws, req) => {
|
||||||
console.log('🔌 [WebSocket] Новое подключение');
|
logger.debug('🔌 [WebSocket] Новое подключение');
|
||||||
console.log('🔌 [WebSocket] IP клиента:', req.socket.remoteAddress);
|
logger.debug('🔌 [WebSocket] IP клиента:', req.socket.remoteAddress);
|
||||||
console.log('🔌 [WebSocket] User-Agent:', req.headers['user-agent']);
|
logger.debug('🔌 [WebSocket] User-Agent:', req.headers['user-agent']);
|
||||||
console.log('🔌 [WebSocket] Origin:', req.headers.origin);
|
logger.debug('🔌 [WebSocket] Origin:', req.headers.origin);
|
||||||
|
|
||||||
// Добавляем клиента в общий список
|
// Добавляем клиента в общий список
|
||||||
if (!wsClients.has('anonymous')) {
|
if (!wsClients.has('anonymous')) {
|
||||||
@@ -77,7 +78,7 @@ function initWSS(server) {
|
|||||||
|
|
||||||
if (data.type === 'ollama_ready') {
|
if (data.type === 'ollama_ready') {
|
||||||
// Уведомление о готовности Ollama - запускаем инициализацию ботов
|
// Уведомление о готовности Ollama - запускаем инициализацию ботов
|
||||||
console.log('🚀 [WebSocket] Получено уведомление о готовности Ollama!');
|
logger.debug('🚀 [WebSocket] Получено уведомление о готовности Ollama!');
|
||||||
handleOllamaReady();
|
handleOllamaReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,11 +106,11 @@ function initWSS(server) {
|
|||||||
data.type === 'deployment_update') {
|
data.type === 'deployment_update') {
|
||||||
// Эти сообщения обрабатываются в deploymentWebSocketService
|
// Эти сообщения обрабатываются в deploymentWebSocketService
|
||||||
// Просто логируем для отладки
|
// Просто логируем для отладки
|
||||||
console.log(`[WebSocket] Получено сообщение деплоя: ${data.type}`);
|
logger.debug(`[WebSocket] Получено сообщение деплоя: ${data.type}`);
|
||||||
console.log(`[WebSocket] Данные:`, JSON.stringify(data, null, 2));
|
logger.debug('[WebSocket] Данные:', JSON.stringify(data, null, 2));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// console.error('❌ [WebSocket] Ошибка парсинга сообщения:', error);
|
logger.debug('❌ [WebSocket] Ошибка парсинга сообщения:', error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -128,7 +129,7 @@ function initWSS(server) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
ws.on('error', (error) => {
|
ws.on('error', (error) => {
|
||||||
// console.error('❌ [WebSocket] Ошибка соединения:', error.message);
|
logger.debug('❌ [WebSocket] Ошибка соединения:', error.message);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -503,14 +504,14 @@ function broadcastTokenBalanceChanged(userId, tokenAddress, newBalance, network)
|
|||||||
function broadcastDeploymentUpdate(data) {
|
function broadcastDeploymentUpdate(data) {
|
||||||
if (!wss) return;
|
if (!wss) return;
|
||||||
|
|
||||||
console.log(`📡 [WebSocket] broadcastDeploymentUpdate вызвана с данными:`, JSON.stringify(data, null, 2));
|
logger.debug('📡 [WebSocket] broadcastDeploymentUpdate вызвана с данными:', JSON.stringify(data, null, 2));
|
||||||
|
|
||||||
const message = JSON.stringify({
|
const message = JSON.stringify({
|
||||||
type: 'deployment_update',
|
type: 'deployment_update',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`📡 [WebSocket] Отправляем сообщение:`, message);
|
logger.debug('📡 [WebSocket] Отправляем сообщение:', message);
|
||||||
|
|
||||||
// Отправляем всем подключенным клиентам
|
// Отправляем всем подключенным клиентам
|
||||||
wss.clients.forEach(client => {
|
wss.clients.forEach(client => {
|
||||||
@@ -518,12 +519,12 @@ function broadcastDeploymentUpdate(data) {
|
|||||||
try {
|
try {
|
||||||
client.send(message);
|
client.send(message);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[WebSocket] Ошибка при отправке deployment update:', error);
|
logger.error('[WebSocket] Ошибка при отправке deployment update:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`📡 [WebSocket] Отправлено deployment update: deployment_update`);
|
logger.debug('📡 [WebSocket] Отправлено deployment update: deployment_update');
|
||||||
}
|
}
|
||||||
|
|
||||||
// broadcastModulesUpdate удалена - используем deploymentWebSocketService.broadcastToDLE
|
// broadcastModulesUpdate удалена - используем deploymentWebSocketService.broadcastToDLE
|
||||||
@@ -554,13 +555,13 @@ module.exports = {
|
|||||||
// Обработчик запроса балансов токенов
|
// Обработчик запроса балансов токенов
|
||||||
async function handleTokenBalancesRequest(ws, address, userId) {
|
async function handleTokenBalancesRequest(ws, address, userId) {
|
||||||
try {
|
try {
|
||||||
console.log(`[WebSocket] Запрос балансов для адреса: ${address}`);
|
logger.debug(`[WebSocket] Запрос балансов для адреса: ${address}`);
|
||||||
|
|
||||||
// Получаем балансы через отдельный сервис без зависимостей от wsHub
|
// Получаем балансы через отдельный сервис без зависимостей от wsHub
|
||||||
const balances = await tokenBalanceService.getUserTokenBalances(address);
|
const balances = await tokenBalanceService.getUserTokenBalances(address);
|
||||||
|
|
||||||
console.log(`[WebSocket] Получены балансы для ${address}:`, balances);
|
logger.debug(`[WebSocket] Получены балансы для ${address}:`, balances);
|
||||||
console.log(`[WebSocket] Количество токенов:`, balances?.length || 0);
|
logger.debug('[WebSocket] Количество токенов:', balances?.length || 0);
|
||||||
|
|
||||||
// Отправляем ответ клиенту
|
// Отправляем ответ клиенту
|
||||||
const response = {
|
const response = {
|
||||||
@@ -572,10 +573,10 @@ async function handleTokenBalancesRequest(ws, address, userId) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(`[WebSocket] Отправляем ответ:`, JSON.stringify(response, null, 2));
|
logger.debug('[WebSocket] Отправляем ответ:', JSON.stringify(response, null, 2));
|
||||||
ws.send(JSON.stringify(response));
|
ws.send(JSON.stringify(response));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[WebSocket] Ошибка при получении балансов:', error);
|
logger.error('[WebSocket] Ошибка при получении балансов:', error);
|
||||||
|
|
||||||
// Определяем тип ошибки для лучшей диагностики
|
// Определяем тип ошибки для лучшей диагностики
|
||||||
let errorType = 'Неизвестная ошибка';
|
let errorType = 'Неизвестная ошибка';
|
||||||
@@ -602,7 +603,7 @@ async function handleTokenBalancesRequest(ws, address, userId) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('[WebSocket] Отправляем ошибку клиенту:', JSON.stringify(errorResponse, null, 2));
|
logger.debug('[WebSocket] Отправляем ошибку клиенту:', JSON.stringify(errorResponse, null, 2));
|
||||||
ws.send(JSON.stringify(errorResponse));
|
ws.send(JSON.stringify(errorResponse));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -612,11 +613,11 @@ async function handleTokenBalancesRequest(ws, address, userId) {
|
|||||||
*/
|
*/
|
||||||
async function handleOllamaReady() {
|
async function handleOllamaReady() {
|
||||||
try {
|
try {
|
||||||
console.log('✅ [WebSocket] Ollama готов к работе');
|
logger.debug('✅ [WebSocket] Ollama готов к работе');
|
||||||
// Уведомляем всех подключенных клиентов о готовности системы
|
// Уведомляем всех подключенных клиентов о готовности системы
|
||||||
broadcastSystemReady();
|
broadcastSystemReady();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ [WebSocket] Ошибка обработки Ollama ready:', error);
|
logger.error('❌ [WebSocket] Ошибка обработки Ollama ready:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -642,5 +643,5 @@ function broadcastSystemReady() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('📢 [WebSocket] Уведомление о готовности системы отправлено всем клиентам');
|
logger.debug('📢 [WebSocket] Уведомление о готовности системы отправлено всем клиентам');
|
||||||
}
|
}
|
||||||
@@ -150,6 +150,7 @@ services:
|
|||||||
- OLLAMA_EMBEDDINGS_MODEL=${OLLAMA_EMBEDDINGS_MODEL:-mxbai-embed-large:latest}
|
- OLLAMA_EMBEDDINGS_MODEL=${OLLAMA_EMBEDDINGS_MODEL:-mxbai-embed-large:latest}
|
||||||
# FRONTEND_URL настраивается в коде, не через env
|
# FRONTEND_URL настраивается в коде, не через env
|
||||||
- VECTOR_SEARCH_URL=http://vector-search:8001
|
- VECTOR_SEARCH_URL=http://vector-search:8001
|
||||||
|
- LOG_LEVEL=${LOG_LEVEL:-warn}
|
||||||
# Factory адреса теперь хранятся в базе данных
|
# Factory адреса теперь хранятся в базе данных
|
||||||
# Убираем порты для продакшна - доступ только через nginx
|
# Убираем порты для продакшна - доступ только через nginx
|
||||||
# ports:
|
# ports:
|
||||||
|
|||||||
@@ -146,6 +146,19 @@ import { useWebSshLogs } from '../composables/useWebSshLogs';
|
|||||||
|
|
||||||
const webSshService = useWebSshService();
|
const webSshService = useWebSshService();
|
||||||
|
|
||||||
|
const encodeDomainForRequest = (domain) => {
|
||||||
|
if (!domain) return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const normalized = domain.trim().toLowerCase();
|
||||||
|
const url = new URL(`http://${normalized}`);
|
||||||
|
return url.hostname;
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('[WebSSH] Некорректное доменное имя:', domain, error.message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Используем композабл для real-time логов
|
// Используем композабл для real-time логов
|
||||||
const {
|
const {
|
||||||
logs,
|
logs,
|
||||||
@@ -196,8 +209,19 @@ const checkDomainDNS = async () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
domainStatus.value = { type: 'loading', message: 'Проверка DNS...' };
|
domainStatus.value = { type: 'loading', message: 'Проверка DNS...' };
|
||||||
|
|
||||||
const response = await fetch(`http://localhost:8000/api/dns-check/${form.domain}`);
|
const asciiDomain = encodeDomainForRequest(form.domain);
|
||||||
|
|
||||||
|
if (!asciiDomain) {
|
||||||
|
domainStatus.value = {
|
||||||
|
type: 'error',
|
||||||
|
message: '❌ Некорректное доменное имя'
|
||||||
|
};
|
||||||
|
addLog('error', `DNS ошибка: Некорректное доменное имя (${form.domain})`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(`/api/dns-check/${encodeURIComponent(asciiDomain)}`);
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
|
|||||||
@@ -16,6 +16,20 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const LOCAL_AGENT_URL = 'http://localhost:3000';
|
const LOCAL_AGENT_URL = 'http://localhost:3000';
|
||||||
|
const API_BASE_PATH = '/api';
|
||||||
|
|
||||||
|
const normalizeDomainToAscii = (domain) => {
|
||||||
|
if (!domain) return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const normalized = domain.trim().toLowerCase();
|
||||||
|
const url = new URL(`http://${normalized}`);
|
||||||
|
return url.hostname;
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('[WebSshService] Некорректное доменное имя:', domain, error.message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Функция для генерации nginx конфигурации
|
// Функция для генерации nginx конфигурации
|
||||||
function getNginxConfig(domain, serverPort) {
|
function getNginxConfig(domain, serverPort) {
|
||||||
@@ -274,7 +288,12 @@ EOF
|
|||||||
console.log(`Получение IP адреса для домена ${domain}...`);
|
console.log(`Получение IP адреса для домена ${domain}...`);
|
||||||
|
|
||||||
// Используем backend API для проверки DNS
|
// Используем backend API для проверки DNS
|
||||||
const response = await fetch(`http://localhost:8000/api/dns-check/${domain}`);
|
const asciiDomain = normalizeDomainToAscii(domain);
|
||||||
|
if (!asciiDomain) {
|
||||||
|
return { success: false, error: 'Некорректное доменное имя' };
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(`${API_BASE_PATH}/dns-check/${encodeURIComponent(asciiDomain)}`);
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
|
|||||||
Reference in New Issue
Block a user