Добавлена новая middleware для аутентификации API

- Реализована функция `requireApiAuth`, которая проверяет аутентификацию пользователя и возвращает JSON-ответ в случае неаутентифицированного доступа.
- Обновлены маршруты API для использования новой middleware вместо старой `requireAuth`, улучшая обработку аутентификации для всех API-запросов.
This commit is contained in:
Fovway 2025-10-26 15:01:50 +07:00
parent ce803b4c20
commit 88d4a5f5d5

157
server.js
View File

@ -530,6 +530,15 @@ function requireAuth(req, res, next) {
}
}
// Middleware для аутентификации API (возвращает JSON вместо редиректа)
function requireApiAuth(req, res, next) {
if (req.session.authenticated) {
return next();
} else {
return res.status(401).json({ error: "Не аутентифицирован" });
}
}
// Маршруты
// Главная страница с формой входа
@ -680,7 +689,7 @@ app.get("/api/auth/status", (req, res) => {
});
// API для получения информации о пользователе
app.get("/api/user", requireAuth, (req, res) => {
app.get("/api/user", requireApiAuth, (req, res) => {
if (!req.session.userId) {
return res.status(401).json({ error: "Не аутентифицирован" });
}
@ -740,7 +749,7 @@ app.get("/notes", requireAuth, (req, res) => {
});
// API для поиска заметок с изображениями (должен быть ПЕРЕД /api/notes/:id)
app.get("/api/notes/search", requireAuth, (req, res) => {
app.get("/api/notes/search", requireApiAuth, (req, res) => {
const { q, tag, date } = req.query;
let whereClause = "WHERE n.user_id = ?";
@ -805,7 +814,7 @@ app.get("/api/notes/search", requireAuth, (req, res) => {
});
// API для получения всех заметок с изображениями (исключая архивные)
app.get("/api/notes", requireAuth, (req, res) => {
app.get("/api/notes", requireApiAuth, (req, res) => {
const sql = `
SELECT
n.*,
@ -847,7 +856,7 @@ app.get("/api/notes", requireAuth, (req, res) => {
});
// API для создания новой заметки
app.post("/api/notes", requireAuth, (req, res) => {
app.post("/api/notes", requireApiAuth, (req, res) => {
const { content, date, time } = req.body;
if (!content || !date || !time) {
@ -879,7 +888,7 @@ app.post("/api/notes", requireAuth, (req, res) => {
});
// API для обновления заметки
app.put("/api/notes/:id", requireAuth, (req, res) => {
app.put("/api/notes/:id", requireApiAuth, (req, res) => {
const { content } = req.body;
const { id } = req.params;
@ -931,7 +940,7 @@ app.put("/api/notes/:id", requireAuth, (req, res) => {
});
// API для удаления заметки
app.delete("/api/notes/:id", requireAuth, (req, res) => {
app.delete("/api/notes/:id", requireApiAuth, (req, res) => {
const { id } = req.params;
// Проверяем, что заметка принадлежит текущему пользователю
@ -1087,7 +1096,7 @@ app.post(
);
// API для получения изображений заметки
app.get("/api/notes/:id/images", requireAuth, (req, res) => {
app.get("/api/notes/:id/images", requireApiAuth, (req, res) => {
const { id } = req.params;
// Проверяем, что заметка принадлежит текущему пользователю
@ -1126,7 +1135,7 @@ app.get("/api/notes/:id/images", requireAuth, (req, res) => {
});
// API для удаления изображения заметки
app.delete("/api/notes/:noteId/images/:imageId", requireAuth, (req, res) => {
app.delete("/api/notes/:noteId/images/:imageId", requireApiAuth, (req, res) => {
const { noteId, imageId } = req.params;
// Проверяем, что заметка принадлежит текущему пользователю
@ -1221,7 +1230,7 @@ app.get("/profile", requireAuth, (req, res) => {
});
// API для обновления профиля
app.put("/api/user/profile", requireAuth, async (req, res) => {
app.put("/api/user/profile", requireApiAuth, async (req, res) => {
const { username, email, currentPassword, newPassword, accent_color } =
req.body;
const userId = req.session.userId;
@ -1379,7 +1388,7 @@ app.post(
);
// API для удаления аватарки
app.delete("/api/user/avatar", requireAuth, (req, res) => {
app.delete("/api/user/avatar", requireApiAuth, (req, res) => {
const userId = req.session.userId;
// Получаем текущую аватарку
@ -1414,7 +1423,7 @@ app.delete("/api/user/avatar", requireAuth, (req, res) => {
});
// API для закрепления заметки
app.put("/api/notes/:id/pin", requireAuth, (req, res) => {
app.put("/api/notes/:id/pin", requireApiAuth, (req, res) => {
const { id } = req.params;
// Проверяем, что заметка принадлежит текущему пользователю
@ -1458,7 +1467,7 @@ app.put("/api/notes/:id/pin", requireAuth, (req, res) => {
});
// API для архивирования заметки
app.put("/api/notes/:id/archive", requireAuth, (req, res) => {
app.put("/api/notes/:id/archive", requireApiAuth, (req, res) => {
const { id } = req.params;
// Проверяем, что заметка принадлежит текущему пользователю
@ -1501,7 +1510,7 @@ app.put("/api/notes/:id/archive", requireAuth, (req, res) => {
});
// API для восстановления заметки из архива
app.put("/api/notes/:id/unarchive", requireAuth, (req, res) => {
app.put("/api/notes/:id/unarchive", requireApiAuth, (req, res) => {
const { id } = req.params;
// Проверяем, что заметка принадлежит текущему пользователю
@ -1543,7 +1552,7 @@ app.put("/api/notes/:id/unarchive", requireAuth, (req, res) => {
});
// API для получения архивных заметок
app.get("/api/notes/archived", requireAuth, (req, res) => {
app.get("/api/notes/archived", requireApiAuth, (req, res) => {
const sql = `
SELECT
n.*,
@ -1585,7 +1594,7 @@ app.get("/api/notes/archived", requireAuth, (req, res) => {
});
// API для окончательного удаления всех архивных заметок пользователя
app.delete("/api/notes/archived/all", requireAuth, async (req, res) => {
app.delete("/api/notes/archived/all", requireApiAuth, async (req, res) => {
const { password } = req.body;
if (!password) {
@ -1694,7 +1703,7 @@ app.delete("/api/notes/archived/all", requireAuth, async (req, res) => {
});
// API для окончательного удаления архивной заметки
app.delete("/api/notes/archived/:id", requireAuth, (req, res) => {
app.delete("/api/notes/archived/:id", requireApiAuth, (req, res) => {
const { id } = req.params;
// Проверяем, что заметка принадлежит текущему пользователю и архивирована
@ -1762,116 +1771,8 @@ app.delete("/api/notes/archived/:id", requireAuth, (req, res) => {
});
});
// API для окончательного удаления всех архивных заметок пользователя
app.delete("/api/notes/archived/all", requireAuth, async (req, res) => {
const { password } = req.body;
if (!password) {
return res.status(400).json({ error: "Пароль обязателен" });
}
try {
// Получаем хеш пароля пользователя
const userSql = "SELECT password FROM users WHERE id = ?";
db.get(userSql, [req.session.userId], async (err, user) => {
if (err) {
console.error("Ошибка получения пользователя:", err.message);
return res.status(500).json({ error: "Ошибка сервера" });
}
if (!user) {
return res.status(404).json({ error: "Пользователь не найден" });
}
// Проверяем пароль
const validPassword = await bcrypt.compare(password, user.password);
if (!validPassword) {
return res.status(401).json({ error: "Неверный пароль" });
}
// Получаем все архивные заметки пользователя
const getNotesSql =
"SELECT id FROM notes WHERE user_id = ? AND is_archived = 1";
db.all(getNotesSql, [req.session.userId], (err, notes) => {
if (err) {
console.error("Ошибка получения архивных заметок:", err.message);
return res.status(500).json({ error: "Ошибка сервера" });
}
if (notes.length === 0) {
return res.json({
success: true,
message: "Архив уже пуст",
deletedCount: 0,
});
}
// Удаляем изображения для всех заметок
const noteIds = notes.map((note) => note.id);
const placeholders = noteIds.map(() => "?").join(",");
const getImagesSql = `SELECT file_path FROM note_images WHERE note_id IN (${placeholders})`;
db.all(getImagesSql, noteIds, (err, images) => {
if (err) {
console.error("Ошибка получения изображений:", err.message);
} else {
// Удаляем файлы изображений
images.forEach((image) => {
const imagePath = path.join(__dirname, "public", image.file_path);
if (fs.existsSync(imagePath)) {
try {
fs.unlinkSync(imagePath);
} catch (err) {
console.error("Ошибка удаления файла изображения:", err);
}
}
});
}
// Удаляем записи об изображениях
const deleteImagesSql = `DELETE FROM note_images WHERE note_id IN (${placeholders})`;
db.run(deleteImagesSql, noteIds, (err) => {
if (err) {
console.error("Ошибка удаления изображений:", err.message);
}
// Удаляем сами заметки
const deleteNotesSql = `DELETE FROM notes WHERE user_id = ? AND is_archived = 1`;
db.run(deleteNotesSql, [req.session.userId], function (err) {
if (err) {
console.error("Ошибка удаления заметок:", err.message);
return res.status(500).json({ error: "Ошибка сервера" });
}
const deletedCount = this.changes;
// Логируем действие
const clientIP = getClientIP(req);
logAction(
req.session.userId,
"note_delete_permanent",
`Удалены все архивные заметки (${deletedCount} шт.)`,
clientIP
);
res.json({
success: true,
message: `Удалено ${deletedCount} архивных заметок`,
deletedCount,
});
});
});
});
});
});
} catch (error) {
console.error("Ошибка при проверке пароля:", error);
res.status(500).json({ error: "Ошибка сервера" });
}
});
// API для получения логов пользователя
app.get("/api/logs", requireAuth, (req, res) => {
app.get("/api/logs", requireApiAuth, (req, res) => {
const { action_type, limit = 100, offset = 0 } = req.query;
let sql = `
@ -1939,7 +1840,7 @@ app.get("/settings", requireAuth, (req, res) => {
});
// API для получения AI настроек
app.get("/api/user/ai-settings", requireAuth, (req, res) => {
app.get("/api/user/ai-settings", requireApiAuth, (req, res) => {
if (!req.session.userId) {
return res.status(401).json({ error: "Не аутентифицирован" });
}
@ -1961,7 +1862,7 @@ app.get("/api/user/ai-settings", requireAuth, (req, res) => {
});
// API для сохранения AI настроек
app.put("/api/user/ai-settings", requireAuth, (req, res) => {
app.put("/api/user/ai-settings", requireApiAuth, (req, res) => {
const { openai_api_key, openai_base_url, openai_model } = req.body;
const userId = req.session.userId;
@ -1990,7 +1891,7 @@ app.put("/api/user/ai-settings", requireAuth, (req, res) => {
});
// API для улучшения текста через AI
app.post("/api/ai/improve", requireAuth, async (req, res) => {
app.post("/api/ai/improve", requireApiAuth, async (req, res) => {
const { text } = req.body;
if (!text) {