Упрощено логирование действий пользователя и удалены функции получения IP-адреса

- Удалена функция получения IP-адреса клиента, так как она больше не используется.
- Обновлена функция логирования действий пользователя для исключения параметра IP-адреса.
- Обновлены все вызовы логирования в коде, чтобы соответствовать новым изменениям.
- Удалены ссылки на IP-адрес в интерфейсе отображения логов действий.
This commit is contained in:
Fovway 2025-10-29 23:15:46 +07:00
parent 84291aac91
commit 5306122a7d
3 changed files with 19 additions and 185 deletions

View File

@ -302,7 +302,6 @@
<th>Дата и время</th>
<th>Действие</th>
<th>Детали</th>
<th>IP-адрес</th>
</tr>
</thead>
<tbody id="logsTableBody">

View File

@ -823,7 +823,6 @@ async function loadLogs(reset = false) {
log.action_type
}">${actionText}</span></td>
<td>${log.details || "-"}</td>
<td>${log.ip_address || "-"}</td>
`;
tbody.appendChild(row);

202
server.js
View File

@ -360,114 +360,18 @@ function createIndexes() {
}
// Функция для логирования действий пользователя
function logAction(userId, actionType, details, ipAddress) {
function logAction(userId, actionType, details) {
const sql = `
INSERT INTO action_logs (user_id, action_type, details, ip_address)
VALUES (?, ?, ?, ?)
VALUES (?, ?, ?, NULL)
`;
db.run(sql, [userId, actionType, details, ipAddress], (err) => {
db.run(sql, [userId, actionType, details], (err) => {
if (err) {
console.error("Ошибка логирования действия:", err.message);
}
});
}
// Функция для получения IP-адреса клиента
function getClientIP(req) {
// Логируем все заголовки для отладки
console.log("=== IP Headers Debug ===");
console.log("req.ip:", req.ip);
console.log("x-forwarded-for:", req.headers["x-forwarded-for"]);
console.log("x-real-ip:", req.headers["x-real-ip"]);
console.log("x-client-ip:", req.headers["x-client-ip"]);
console.log("cf-connecting-ip:", req.headers["cf-connecting-ip"]); // Cloudflare
console.log("x-forwarded:", req.headers["x-forwarded"]);
console.log("forwarded:", req.headers["forwarded"]);
console.log("req.connection.remoteAddress:", req.connection?.remoteAddress);
console.log("req.socket.remoteAddress:", req.socket?.remoteAddress);
console.log("ALL HEADERS:", JSON.stringify(req.headers, null, 2));
console.log("========================");
// Приоритет для получения реального IP клиента:
// 1. req.socket.remoteAddress (для случаев с дополнительными прокси)
// 2. X-Real-IP (часто используется nginx)
// 3. X-Forwarded-For (стандартный заголовок)
// 4. CF-Connecting-IP (если используется Cloudflare)
// 5. X-Client-IP
// 6. req.ip (Express с trust proxy)
let ip = null;
// Проверяем socket_remoteAddress в первую очередь (для случаев с дополнительными прокси)
if (
req.socket?.remoteAddress &&
req.socket.remoteAddress !== "::1" &&
req.socket.remoteAddress !== "127.0.0.1"
) {
ip = req.socket.remoteAddress;
}
// Проверяем X-Real-IP (nginx часто использует этот заголовок)
else if (req.headers["x-real-ip"]) {
ip = req.headers["x-real-ip"];
}
// Проверяем X-Forwarded-For (берем первый IP из списка)
else if (req.headers["x-forwarded-for"]) {
ip = req.headers["x-forwarded-for"].split(",")[0].trim();
}
// Проверяем CF-Connecting-IP (Cloudflare)
else if (req.headers["cf-connecting-ip"]) {
ip = req.headers["cf-connecting-ip"];
}
// Проверяем X-Client-IP
else if (req.headers["x-client-ip"]) {
ip = req.headers["x-client-ip"];
}
// Проверяем Forwarded заголовок (RFC 7239)
else if (req.headers["forwarded"]) {
const forwarded = req.headers["forwarded"];
const forMatch = forwarded.match(/for=([^;,\s]+)/);
if (forMatch) {
ip = forMatch[1];
}
}
// Используем req.ip (Express с trust proxy)
else if (req.ip && req.ip !== "::1" && req.ip !== "127.0.0.1") {
ip = req.ip;
}
// Очищаем IP от скобок IPv6, портов и кавычек
if (ip && ip !== "unknown") {
// Убираем скобки IPv6
ip = ip.replace(/[[\]]/g, "");
// Убираем кавычки если есть
ip = ip.replace(/['"]/g, "");
// Обрабатываем IPv6 адреса
if (ip.startsWith("::ffff:")) {
// IPv4-mapped IPv6 address (::ffff:192.168.1.1)
ip = ip.substring(7); // Убираем "::ffff:"
} else if (ip.includes("::")) {
const ipv6Match = ip.match(/^(\[)?([^\]]+)(\])?(:(\d+))?$/);
if (ipv6Match) {
ip = ipv6Match[2];
}
} else if (ip.includes(":")) {
// IPv4 с портом
const parts = ip.split(":");
if (parts.length === 2 && /^\d+$/.test(parts[1])) {
ip = parts[0];
}
}
}
// Конвертируем IPv6 localhost в IPv4
if (ip === "::1" || ip === "::ffff:127.0.0.1") {
ip = "127.0.0.1";
}
return ip || "unknown";
}
// Миграции базы данных
function runMigrations() {
// Создаем таблицу логов действий, если её нет
@ -744,13 +648,7 @@ app.post("/api/register", async (req, res) => {
req.session.authenticated = true;
// Логируем регистрацию
const clientIP = getClientIP(req);
logAction(
this.lastID,
"register",
`Регистрация нового пользователя`,
clientIP
);
logAction(this.lastID, "register", `Регистрация нового пользователя`);
res.json({ success: true, message: "Регистрация успешна" });
});
@ -792,8 +690,7 @@ app.post("/api/login", async (req, res) => {
req.session.authenticated = true;
// Логируем вход
const clientIP = getClientIP(req);
logAction(user.id, "login", `Вход в систему`, clientIP);
logAction(user.id, "login", `Вход в систему`);
res.json({ success: true, message: "Вход успешен" });
} catch (err) {
@ -851,29 +748,6 @@ app.get("/api/user", requireApiAuth, (req, res) => {
});
});
// Тестовый эндпоинт для проверки IP-адресов (только для отладки)
app.get("/api/debug/ip", (req, res) => {
const clientIP = getClientIP(req);
res.json({
detected_ip: clientIP,
headers: {
"x-forwarded-for": req.headers["x-forwarded-for"],
"x-real-ip": req.headers["x-real-ip"],
"x-client-ip": req.headers["x-client-ip"],
"cf-connecting-ip": req.headers["cf-connecting-ip"],
"x-forwarded": req.headers["x-forwarded"],
forwarded: req.headers["forwarded"],
},
express: {
req_ip: req.ip,
socket_remoteAddress: req.socket?.remoteAddress,
connection_remoteAddress: req.connection?.remoteAddress,
},
all_headers: req.headers,
});
});
// Страница с заметками (требует аутентификации)
app.get("/notes", requireAuth, (req, res) => {
// Получаем цвет пользователя для предотвращения FOUC
@ -1070,14 +944,8 @@ app.post("/api/notes", requireApiAuth, (req, res) => {
}
// Логируем создание заметки
const clientIP = getClientIP(req);
const noteId = this.lastID;
logAction(
req.session.userId,
"note_create",
`Создана заметка #${noteId}`,
clientIP
);
logAction(req.session.userId, "note_create", `Создана заметка #${noteId}`);
res.json({ id: noteId, content, date, time });
});
@ -1122,13 +990,7 @@ app.put("/api/notes/:id", requireApiAuth, (req, res) => {
}
// Логируем обновление заметки
const clientIP = getClientIP(req);
logAction(
req.session.userId,
"note_update",
`Обновлена заметка #${id}`,
clientIP
);
logAction(req.session.userId, "note_update", `Обновлена заметка #${id}`);
res.json({ id, content, date: row.date, time: row.time });
});
@ -1213,12 +1075,10 @@ app.delete("/api/notes/:id", requireApiAuth, (req, res) => {
}
// Логируем удаление заметки
const clientIP = getClientIP(req);
logAction(
req.session.userId,
"note_delete",
`Удалена заметка #${id}`,
clientIP
`Удалена заметка #${id}`
);
res.json({ message: "Заметка удалена" });
@ -1730,14 +1590,13 @@ app.put("/api/user/profile", requireApiAuth, async (req, res) => {
}
// Логируем обновление профиля
const clientIP = getClientIP(req);
const changes = [];
if (username && username !== user.username) changes.push("логин");
if (email !== undefined) changes.push("email");
if (accent_color !== undefined) changes.push("цвет темы");
if (newPassword) changes.push("пароль");
const details = `Обновлен профиль: ${changes.join(", ")}`;
logAction(userId, "profile_update", details, clientIP);
logAction(userId, "profile_update", details);
res.json({ success: true, message: "Профиль успешно обновлен" });
});
@ -1857,14 +1716,8 @@ app.put("/api/notes/:id/pin", requireApiAuth, (req, res) => {
}
// Логируем действие
const clientIP = getClientIP(req);
const action = newPinState ? "закреплена" : "откреплена";
logAction(
req.session.userId,
"note_pin",
`Заметка #${id} ${action}`,
clientIP
);
logAction(req.session.userId, "note_pin", `Заметка #${id} ${action}`);
res.json({ success: true, is_pinned: newPinState });
});
@ -1901,12 +1754,10 @@ app.put("/api/notes/:id/archive", requireApiAuth, (req, res) => {
}
// Логируем действие
const clientIP = getClientIP(req);
logAction(
req.session.userId,
"note_archive",
`Заметка #${id} архивирована`,
clientIP
`Заметка #${id} архивирована`
);
res.json({ success: true, message: "Заметка архивирована" });
@ -1943,12 +1794,10 @@ app.put("/api/notes/:id/unarchive", requireApiAuth, (req, res) => {
}
// Логируем действие
const clientIP = getClientIP(req);
logAction(
req.session.userId,
"note_unarchive",
`Заметка #${id} восстановлена из архива`,
clientIP
`Заметка #${id} восстановлена из архива`
);
res.json({ success: true, message: "Заметка восстановлена" });
@ -2125,12 +1974,10 @@ app.delete("/api/notes/archived/all", requireApiAuth, async (req, res) => {
const deletedCount = this.changes;
// Логируем действие
const clientIP = getClientIP(req);
logAction(
req.session.userId,
"note_delete_permanent",
`Удалены все архивные заметки (${deletedCount} шт.)`,
clientIP
`Удалены все архивные заметки (${deletedCount} шт.)`
);
res.json({
@ -2228,12 +2075,10 @@ app.delete("/api/notes/archived/:id", requireApiAuth, (req, res) => {
}
// Логируем действие
const clientIP = getClientIP(req);
logAction(
req.session.userId,
"note_delete_permanent",
`Заметка #${id} окончательно удалена из архива`,
clientIP
`Заметка #${id} окончательно удалена из архива`
);
res.json({ success: true, message: "Заметка удалена окончательно" });
@ -2248,7 +2093,7 @@ app.get("/api/logs", requireApiAuth, (req, res) => {
const { action_type, limit = 100, offset = 0 } = req.query;
let sql = `
SELECT id, action_type, details, ip_address, created_at
SELECT id, action_type, details, created_at
FROM action_logs
WHERE user_id = ?
`;
@ -2359,8 +2204,7 @@ app.put("/api/user/ai-settings", requireApiAuth, (req, res) => {
}
// Логируем обновление AI настроек
const clientIP = getClientIP(req);
logAction(userId, "profile_update", "Изменен статус AI", clientIP);
logAction(userId, "profile_update", "Изменен статус AI");
res.json({ success: true, message: "Настройки AI успешно сохранены" });
});
@ -2401,8 +2245,7 @@ app.put("/api/user/ai-settings", requireApiAuth, (req, res) => {
}
// Логируем обновление AI настроек
const clientIP = getClientIP(req);
logAction(userId, "profile_update", "Обновлены AI настройки", clientIP);
logAction(userId, "profile_update", "Обновлены AI настройки");
res.json({ success: true, message: "AI настройки успешно сохранены" });
});
@ -2527,13 +2370,7 @@ app.post("/api/ai/improve", requireApiAuth, async (req, res) => {
});
// Логируем использование AI
const clientIP = getClientIP(req);
logAction(
req.session.userId,
"ai_improve",
"Улучшен текст через AI",
clientIP
);
logAction(req.session.userId, "ai_improve", "Улучшен текст через AI");
res.json({ success: true, improvedText });
} catch (error) {
@ -2552,11 +2389,10 @@ app.post("/api/ai/improve", requireApiAuth, async (req, res) => {
// Выход
app.post("/logout", (req, res) => {
const userId = req.session.userId;
const clientIP = getClientIP(req);
// Логируем выход
if (userId) {
logAction(userId, "logout", "Выход из системы", clientIP);
logAction(userId, "logout", "Выход из системы");
}
req.session.destroy((err) => {