188 lines
5.2 KiB
JavaScript
188 lines
5.2 KiB
JavaScript
import initSqlJs from 'sql.js';
|
|
import bcrypt from 'bcryptjs';
|
|
import path from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
import fs from 'fs';
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
|
// 数据库文件路径
|
|
const dbPath = process.env.DATABASE_PATH || path.join(__dirname, 'data', 'auth.db');
|
|
const dbDir = path.dirname(dbPath);
|
|
|
|
// 确保数据目录存在
|
|
if (!fs.existsSync(dbDir)) {
|
|
fs.mkdirSync(dbDir, { recursive: true });
|
|
}
|
|
|
|
let db = null;
|
|
|
|
// 初始化数据库
|
|
async function initDatabase() {
|
|
const SQL = await initSqlJs();
|
|
|
|
// 尝试加载现有数据库文件
|
|
if (fs.existsSync(dbPath)) {
|
|
const fileBuffer = fs.readFileSync(dbPath);
|
|
db = new SQL.Database(fileBuffer);
|
|
} else {
|
|
db = new SQL.Database();
|
|
}
|
|
|
|
// 创建表
|
|
db.run(`
|
|
CREATE TABLE IF NOT EXISTS access_passwords (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL UNIQUE,
|
|
password_hash TEXT NOT NULL,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
`);
|
|
|
|
db.run(`
|
|
CREATE TABLE IF NOT EXISTS admin_users (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
username TEXT NOT NULL UNIQUE,
|
|
password_hash TEXT NOT NULL,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
`);
|
|
|
|
// 初始化默认管理员账户
|
|
const adminUsername = process.env.ADMIN_USERNAME || 'admin';
|
|
const adminPassword = process.env.ADMIN_PASSWORD || 'admin123456';
|
|
|
|
const existingAdmin = db.exec('SELECT id FROM admin_users WHERE username = ?', [adminUsername]);
|
|
|
|
if (existingAdmin.length === 0 || existingAdmin[0].values.length === 0) {
|
|
const passwordHash = bcrypt.hashSync(adminPassword, 10);
|
|
db.run('INSERT INTO admin_users (username, password_hash) VALUES (?, ?)', [adminUsername, passwordHash]);
|
|
console.log(`[DB] 默认管理员账户已创建: ${adminUsername}`);
|
|
}
|
|
|
|
// 保存数据库
|
|
saveDatabase();
|
|
}
|
|
|
|
// 保存数据库到文件
|
|
function saveDatabase() {
|
|
if (db) {
|
|
const data = db.export();
|
|
const buffer = Buffer.from(data);
|
|
fs.writeFileSync(dbPath, buffer);
|
|
}
|
|
}
|
|
|
|
// ── 访问密码操作 ──
|
|
|
|
export function getAllPasswords() {
|
|
const result = db.exec('SELECT id, name, created_at FROM access_passwords ORDER BY created_at DESC');
|
|
if (result.length === 0) return [];
|
|
|
|
const columns = result[0].columns;
|
|
return result[0].values.map(row => {
|
|
const obj = {};
|
|
columns.forEach((col, i) => {
|
|
obj[col] = row[i];
|
|
});
|
|
return obj;
|
|
});
|
|
}
|
|
|
|
export function getPasswordByName(name) {
|
|
const result = db.exec('SELECT * FROM access_passwords WHERE name = ?', [name]);
|
|
if (result.length === 0 || result[0].values.length === 0) return null;
|
|
|
|
const columns = result[0].columns;
|
|
const row = result[0].values[0];
|
|
const obj = {};
|
|
columns.forEach((col, i) => {
|
|
obj[col] = row[i];
|
|
});
|
|
return obj;
|
|
}
|
|
|
|
export function addPassword(name, password) {
|
|
const passwordHash = bcrypt.hashSync(password, 10);
|
|
try {
|
|
db.run('INSERT INTO access_passwords (name, password_hash) VALUES (?, ?)', [name, passwordHash]);
|
|
saveDatabase();
|
|
|
|
// 获取最后插入的 ID
|
|
const idResult = db.exec('SELECT last_insert_rowid()');
|
|
const id = idResult[0].values[0][0];
|
|
|
|
return { success: true, id };
|
|
} catch (error) {
|
|
if (error.message && error.message.includes('UNIQUE constraint failed')) {
|
|
return { success: false, error: '密码名称已存在' };
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export function deletePassword(id) {
|
|
db.run('DELETE FROM access_passwords WHERE id = ?', [id]);
|
|
saveDatabase();
|
|
|
|
// 检查是否删除了记录
|
|
const result = db.exec('SELECT changes()');
|
|
return result[0].values[0][0] > 0;
|
|
}
|
|
|
|
export function verifyPassword(name, password) {
|
|
// 如果只提供密码,遍历所有密码记录进行匹配
|
|
if (!name && password) {
|
|
const allPasswords = getAllPasswords();
|
|
for (const record of allPasswords) {
|
|
const fullRecord = getPasswordByName(record.name);
|
|
if (fullRecord && bcrypt.compareSync(password, fullRecord.password_hash)) {
|
|
return { valid: true, name: record.name };
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// 如果提供了名称和密码,按名称验证
|
|
const record = getPasswordByName(name);
|
|
if (!record) {
|
|
return false;
|
|
}
|
|
return bcrypt.compareSync(password, record.password_hash) ? { valid: true, name } : false;
|
|
}
|
|
|
|
// ── 管理员操作 ──
|
|
|
|
export function getAdminByUsername(username) {
|
|
const result = db.exec('SELECT * FROM admin_users WHERE username = ?', [username]);
|
|
if (result.length === 0 || result[0].values.length === 0) return null;
|
|
|
|
const columns = result[0].columns;
|
|
const row = result[0].values[0];
|
|
const obj = {};
|
|
columns.forEach((col, i) => {
|
|
obj[col] = row[i];
|
|
});
|
|
return obj;
|
|
}
|
|
|
|
export function verifyAdminPassword(username, password) {
|
|
const admin = getAdminByUsername(username);
|
|
if (!admin) {
|
|
return false;
|
|
}
|
|
return bcrypt.compareSync(password, admin.password_hash);
|
|
}
|
|
|
|
export function updateAdminPassword(username, newPassword) {
|
|
const passwordHash = bcrypt.hashSync(newPassword, 10);
|
|
db.run('UPDATE admin_users SET password_hash = ? WHERE username = ?', [passwordHash, username]);
|
|
saveDatabase();
|
|
|
|
const result = db.exec('SELECT changes()');
|
|
return result[0].values[0][0] > 0;
|
|
}
|
|
|
|
// 导出初始化函数
|
|
export { initDatabase };
|