update authentication

This commit is contained in:
dbdbd9 2025-07-28 15:32:23 +07:00
parent 063f96c19d
commit 2a6fcd6227
4 changed files with 96 additions and 126 deletions

View File

@ -123,23 +123,29 @@
async function getProfile() { async function getProfile() {
const token = localStorage.getItem("token"); const token = localStorage.getItem("token");
const user = JSON.parse(localStorage.getItem("user"));
await fetch("/api/profile", { await fetch("/api/confirm-count", {
method: "GET", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
}, },
body: JSON.stringify({
email: user.email,
}),
}) })
.then((res) => res.json()) .then((res) => res.json())
.then((data) => { .then((data) => {
document.getElementById( document.getElementById(
"welcome-user", "welcome-user",
).innerHTML = `Welcome, <strong>${data?.user?.name}</strong> ▼`; ).innerHTML = `Welcome, <strong>${
JSON.parse(localStorage.getItem("user")).name
}</strong> ▼`;
document.getElementById( document.getElementById(
"confirm-count-user", "confirm-count-user",
).innerHTML = `Confirmed: <strong>${data?.user?.confirm_count}</strong>`; ).innerHTML = `Confirmed: <strong>${data?.count}</strong>`;
}) })
.catch((err) => { .catch((err) => {
console.error(err); console.error(err);
@ -304,8 +310,7 @@
); );
if (currentVerUser) { if (currentVerUser) {
deviceConfirmBtn.style.display = "none"; deviceConfirmBtn.style.display = "none";
confirmedUserName.textContent = confirmedUserName.textContent = currentVerUser.user;
currentVerUser.user.name;
confirmUserText.style.display = "inline"; confirmUserText.style.display = "inline";
} else { } else {
deviceConfirmBtn.style.display = "inline-block"; deviceConfirmBtn.style.display = "inline-block";
@ -602,6 +607,7 @@ ${license}`.trim();
if (!pendingDevice) return; if (!pendingDevice) return;
const token = localStorage.getItem("token"); const token = localStorage.getItem("token");
const user = JSON.parse(localStorage.getItem("user"));
try { try {
const res = await fetch("/api/confirm-device", { const res = await fetch("/api/confirm-device", {
method: "POST", method: "POST",
@ -609,7 +615,11 @@ ${license}`.trim();
"Content-Type": "application/json", "Content-Type": "application/json",
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
}, },
body: JSON.stringify(pendingDevice), body: JSON.stringify({
...pendingDevice,
name: user.name,
email: user.email,
}),
}); });
const data = await res.json(); const data = await res.json();
if (data.success) { if (data.success) {

View File

@ -67,11 +67,17 @@
const errorMsg = document.querySelector(".error-msg"); const errorMsg = document.querySelector(".error-msg");
try { try {
const res = await fetch("/api/login", { const res = await fetch(
"https://stage.nswteam.net/api/login",
{
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }), body: JSON.stringify({
}); userEmail: email,
password,
}),
},
);
const data = await res.json(); const data = await res.json();
@ -83,7 +89,16 @@
} }
localStorage.setItem("token", data.token); localStorage.setItem("token", data.token);
localStorage.setItem("user", JSON.stringify(data.user)); localStorage.setItem(
"user",
JSON.stringify({
name:
data.data.firstName +
" " +
data.data.lastName,
email: data.data.userEmail,
}),
);
window.location.href = "/"; window.location.href = "/";
} catch (err) { } catch (err) {

View File

@ -1,8 +1,5 @@
const express = require("express"); const express = require("express");
const path = require("path"); const path = require("path");
const bcrypt = require("bcrypt");
const { createToken } = require("../utils/jwt");
const { authenticateToken } = require("../middleware/auth");
let router = express.Router(); let router = express.Router();
@ -15,60 +12,5 @@ module.exports = (app, db) => {
res.sendFile(path.join(__dirname, "../public/login.html")); res.sendFile(path.join(__dirname, "../public/login.html"));
}); });
router.post("/api/login", async (req, res) => {
const { email, password } = req.body;
try {
const [rows] = await db.query(
"SELECT * FROM users WHERE email = ?",
[email],
);
const user = rows[0];
const isMatch = await bcrypt.compare(
password,
user?.password || "!@#",
);
if (!user || !isMatch) {
return res
.status(401)
.json({ message: "Invalid email or password" });
}
const token = createToken({
id: user.id,
email: user.email,
name: user.name,
});
return res
.status(200)
.json({ token, user: { name: user.name, email: user.email } });
} catch (err) {
console.error("Login error:", err);
return res.status(500).json({ message: "Internal Server Error" });
}
});
router.get("/api/profile", authenticateToken, async (req, res) => {
const userId = req.user?.id;
try {
const [rows] = await db.query("SELECT * FROM users WHERE id = ?", [
userId,
]);
const user = rows[0];
return res.status(200).json({
user: {
name: user.name,
confirm_count: user.confirm_count,
},
});
} catch (err) {
console.error(err);
return res.status(500).json({ message: "Internal Server Error" });
}
});
app.use("/", router); app.use("/", router);
}; };

109
server.js
View File

@ -5,9 +5,7 @@ const dotenv = require("dotenv");
dotenv.config(); dotenv.config();
const stringSimilarity = require("string-similarity"); const stringSimilarity = require("string-similarity");
const bcrypt = require("bcrypt");
const inititalWebRoute = require("./route/web"); const inititalWebRoute = require("./route/web");
const { authenticateToken } = require("./middleware/auth");
// Nhận mảng message đầu vào, trả về mảng message đã loại bỏ trùng lặp // Nhận mảng message đầu vào, trả về mảng message đã loại bỏ trùng lặp
function deduplicateErrors(errors, threshold = 0.3) { function deduplicateErrors(errors, threshold = 0.3) {
@ -37,10 +35,17 @@ app.use(bodyParser.json());
app.use(express.static("public")); app.use(express.static("public"));
app.use(express.urlencoded({ extended: true })); app.use(express.urlencoded({ extended: true }));
// const db = mysql.createPool({
// host: "localhost",
// user: "admin",
// password: "Work1234",
// database: "log_analysis",
// });
const db = mysql.createPool({ const db = mysql.createPool({
host: "localhost", host: "localhost",
user: "admin", user: "root",
password: "Work1234", password: "",
database: "log_analysis", database: "log_analysis",
}); });
@ -54,21 +59,6 @@ async function columnExists(table, column) {
return rows[0].count > 0; return rows[0].count > 0;
} }
const checkAndInsertAdminUser = async () => {
const [rows] = await db.query(`SELECT id FROM users WHERE email = ?`, [
"admin@apactech.io",
]);
if (rows.length === 0) {
const hashedPassword = await bcrypt.hash("admin0312", 10);
await db.query(
`INSERT INTO users (name, email, password) VALUES (?, ?, ?)`,
["Admin", "admin@apactech.io", hashedPassword],
);
}
};
// === Tạo bảng // === Tạo bảng
(async () => { (async () => {
await db.query(` await db.query(`
@ -94,11 +84,24 @@ const checkAndInsertAdminUser = async () => {
await db.query(`ALTER TABLE devices DROP COLUMN updated_by`); await db.query(`ALTER TABLE devices DROP COLUMN updated_by`);
} }
if (!(await columnExists("devices", "updated_user"))) { if (await columnExists("devices", "updated_user")) {
await db.query(
`ALTER TABLE devices DROP FOREIGN KEY fk_updated_by_user`,
);
await db.query(`ALTER TABLE devices DROP COLUMN updated_user`);
}
if (!(await columnExists("devices", "update_name"))) {
await db.query(` await db.query(`
ALTER TABLE devices ALTER TABLE devices
ADD COLUMN updated_user INT DEFAULT NULL, ADD COLUMN update_name VARCHAR(255)
ADD CONSTRAINT fk_updated_by_user FOREIGN KEY (updated_user) REFERENCES users(id) ON DELETE SET NULL ON UPDATE CASCADE `);
}
if (!(await columnExists("devices", "update_email"))) {
await db.query(`
ALTER TABLE devices
ADD COLUMN update_email VARCHAR(255)
`); `);
} }
@ -121,9 +124,9 @@ const checkAndInsertAdminUser = async () => {
) )
`); `);
if (!(await columnExists(`${command}_outputs`, "is_deleted"))) { if (await columnExists(`${command}_outputs`, "is_deleted")) {
await db.query( await db.query(
`ALTER TABLE ${command}_outputs ADD COLUMN is_deleted BOOLEAN DEFAULT FALSE`, `ALTER TABLE ${command}_outputs DROP COLUMN is_deleted`,
); );
} }
}; };
@ -134,18 +137,8 @@ const checkAndInsertAdminUser = async () => {
await createOutputTable("logging"); await createOutputTable("logging");
await db.query(` await db.query(`
CREATE TABLE IF NOT EXISTS users ( DROP TABLE IF EXISTS users
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
confirm_count INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
`); `);
await checkAndInsertAdminUser();
})(); })();
// === APIs === // === APIs ===
@ -162,7 +155,7 @@ app.get("/api/pid/:pid/versions", async (req, res) => {
// Lấy danh sách các version tương ứng với PID // Lấy danh sách các version tương ứng với PID
const [devices] = await db.query( const [devices] = await db.query(
"SELECT id, version, updated_user FROM devices WHERE pid = ?", "SELECT id, version, update_name FROM devices WHERE pid = ?",
[pid], [pid],
); );
@ -171,12 +164,7 @@ app.get("/api/pid/:pid/versions", async (req, res) => {
for (const device of devices) { for (const device of devices) {
const deviceId = device.id; const deviceId = device.id;
const version = device.version; const version = device.version;
const userId = device.updated_user;
const [user] = await db.query(
"SELECT id, name FROM users WHERE id = ?",
[userId],
);
const [[inv]] = await db.query( const [[inv]] = await db.query(
"SELECT COUNT(*) AS c FROM inventory_outputs WHERE device_id = ?", "SELECT COUNT(*) AS c FROM inventory_outputs WHERE device_id = ?",
[deviceId], [deviceId],
@ -195,7 +183,7 @@ app.get("/api/pid/:pid/versions", async (req, res) => {
); );
results.push({ results.push({
user: user[0], user: device.update_name,
version, version,
commands: { commands: {
inventory: inv.c, inventory: inv.c,
@ -219,16 +207,15 @@ app.get("/api/device/:pid/:version/:command", async (req, res) => {
if (!device) return res.status(404).json({ message: "Not found" }); if (!device) return res.status(404).json({ message: "Not found" });
const [logs] = await db.query( const [logs] = await db.query(
`SELECT id, filename, output, created_at, is_deleted FROM ${command}_outputs WHERE device_id = ? ORDER BY created_at DESC`, `SELECT id, filename, output, created_at FROM ${command}_outputs WHERE device_id = ? ORDER BY created_at DESC`,
[device.id], [device.id],
); );
res.json(logs); res.json(logs);
}); });
app.post("/api/confirm-device", authenticateToken, async (req, res) => { app.post("/api/confirm-device", async (req, res) => {
const { pid, version, deletedLogs } = req.body; const { pid, version, deletedLogs, name, email } = req.body;
const updatedBy = req.user?.id;
if (!pid || !version) { if (!pid || !version) {
return res.status(400).json({ return res.status(400).json({
@ -263,9 +250,10 @@ app.post("/api/confirm-device", authenticateToken, async (req, res) => {
`UPDATE devices `UPDATE devices
SET is_confirmed = true, SET is_confirmed = true,
updated_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP,
updated_user = ? update_name = ?,
update_email = ?
WHERE pid = ? AND version = ?`, WHERE pid = ? AND version = ?`,
[updatedBy, pid, version], [name, email, pid, version],
); );
// Delete Log // Delete Log
@ -297,11 +285,6 @@ app.post("/api/confirm-device", authenticateToken, async (req, res) => {
]); ]);
} }
await db.query(
"UPDATE users SET confirm_count = confirm_count + 1 WHERE id = ?",
[updatedBy],
);
res.json({ res.json({
success: true, success: true,
message: "Device confirmed successfully!", message: "Device confirmed successfully!",
@ -315,6 +298,26 @@ app.post("/api/confirm-device", authenticateToken, async (req, res) => {
} }
}); });
app.post("/api/confirm-count", async (req, res) => {
try {
const { email } = req.body;
if (!email) {
return res.status(400).json({ error: "Email is required" });
}
const [[result]] = await db.query(
"SELECT COUNT(*) AS c FROM devices WHERE update_email = ?",
[email],
);
res.json({ count: result.c });
} catch (err) {
console.error("Error fetching confirm count:", err);
res.status(500).json({ error: "Internal server error" });
}
});
// Danh sách regex lọc lỗi // Danh sách regex lọc lỗi
const errorPatterns = [ const errorPatterns = [
{ {