feat: implement user authentication and license management system
- Added schema for users, licenses, and license hostnames in the database. - Created storage utility for reading and writing JSON files. - Developed user service for user registration, authentication, and retrieval. - Implemented authentication middleware to protect routes. - Built LicenseCard component to display license details. - Created SiteNav component for navigation with user authentication status. - Established AuthContext for managing authentication state and actions. - Developed Home page to display available plugins. - Created LicenseManager page for managing licenses with forms for creation and verification. - Implemented PluginDetail page to show detailed information about a specific plugin. - Added utility functions for date formatting.
This commit is contained in:
69
server/lib/userService.js
Normal file
69
server/lib/userService.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import bcrypt from "bcryptjs";
|
||||
import jwt from "jsonwebtoken";
|
||||
import db from "./db.js";
|
||||
import { JWT_SECRET, JWT_EXPIRES_IN } from "./config.js";
|
||||
|
||||
function serializeUser(row) {
|
||||
if (!row) return null;
|
||||
return {
|
||||
id: row.id,
|
||||
username: row.username,
|
||||
name: row.name,
|
||||
email: row.email,
|
||||
createdAt: row.created_at ? new Date(row.created_at).toISOString() : null
|
||||
};
|
||||
}
|
||||
|
||||
function signToken(userId) {
|
||||
return jwt.sign({ sub: userId }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
|
||||
}
|
||||
|
||||
export async function registerUser({ username, name, email, password }) {
|
||||
const passwordHash = await bcrypt.hash(password, 10);
|
||||
try {
|
||||
const [result] = await db.query(
|
||||
`INSERT INTO users (username, name, email, password_hash) VALUES (?, ?, ?, ?)`,
|
||||
[username, name, email, passwordHash]
|
||||
);
|
||||
const user = await getUserById(result.insertId);
|
||||
const token = signToken(user.id);
|
||||
return { user, token };
|
||||
} catch (error) {
|
||||
if (error?.code === "ER_DUP_ENTRY") {
|
||||
const message = error.sqlMessage || "Duplicate";
|
||||
if (message.includes("username")) {
|
||||
error.meta = "USERNAME";
|
||||
} else if (message.includes("email")) {
|
||||
error.meta = "EMAIL";
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function authenticateUser(identifier, password) {
|
||||
const [rows] = await db.query(
|
||||
`SELECT * FROM users WHERE username = ? OR email = ? LIMIT 1`,
|
||||
[identifier, identifier]
|
||||
);
|
||||
if (rows.length === 0) {
|
||||
const err = new Error("Onjuiste inloggegevens.");
|
||||
err.meta = "INVALID_CREDENTIALS";
|
||||
throw err;
|
||||
}
|
||||
const row = rows[0];
|
||||
const ok = await bcrypt.compare(password, row.password_hash);
|
||||
if (!ok) {
|
||||
const err = new Error("Onjuiste inloggegevens.");
|
||||
err.meta = "INVALID_CREDENTIALS";
|
||||
throw err;
|
||||
}
|
||||
const user = serializeUser(row);
|
||||
const token = signToken(user.id);
|
||||
return { user, token };
|
||||
}
|
||||
|
||||
export async function getUserById(id) {
|
||||
const [rows] = await db.query(`SELECT id, username, name, email, created_at FROM users WHERE id = ? LIMIT 1`, [id]);
|
||||
return serializeUser(rows[0]);
|
||||
}
|
||||
Reference in New Issue
Block a user