Files
clean-chrome/server/server.js

130 lines
4.3 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const express = require('express');
const cors = require('cors');
const sqlite3 = require('sqlite3').verbose();
const path = require('path');
const app = express();
const PORT = process.env.PORT || 3001;
const INVITE_CODE = 'Moka'; // 注册需校验此邀请码
// 启用中间件
app.use(cors()); // 允许 Chrome 扩展跨域请求
app.use(express.json()); // 解析 application/json
// 初始化 SQLite 数据库 (建议使用绝对路径并指向挂载的目录)
const dbPath = process.env.DB_PATH || path.join(__dirname, 'data', 'data.db');
const dbDir = path.dirname(dbPath);
// 确保目录存在
const fs = require('fs');
if (!fs.existsSync(dbDir)) {
fs.mkdirSync(dbDir, { recursive: true });
}
const db = new sqlite3.Database(dbPath, (err) => {
if (err) {
console.error('Could not connect to database', err);
} else {
console.log('Connected to sqlite3 database at:', dbPath);
// 初始化用户表
db.run(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password TEXT NOT NULL,
rules TEXT DEFAULT '[]',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
}
});
// === 接口 1: 注册 ===
app.post('/api/register', (req, res) => {
const { username, password, inviteCode } = req.body;
if (inviteCode !== INVITE_CODE) {
return res.json({ code: 1, msg: '注册码错误' });
}
if (!username || !password) {
return res.json({ code: 1, msg: '用户名和密码不能为空' });
}
// 写入数据库 (直接使用 db.run 更简洁)
db.run('INSERT INTO users (username, password) VALUES (?, ?)', [username, password], function (err) {
if (err) {
if (err.message.includes('UNIQUE constraint failed')) {
return res.json({ code: 1, msg: '用户名太火爆,已被注册' });
}
console.error('Register error:', err);
return res.json({ code: 1, msg: '服务器内部错误' });
}
res.json({ code: 0, msg: '注册成功' });
});
});
// === 接口 2: 登录 ===
app.post('/api/login', (req, res) => {
const { username, password } = req.body;
if (!username || !password) {
return res.json({ code: 1, msg: '请输入用户名和密码' });
}
db.get('SELECT * FROM users WHERE username = ? AND password = ?', [username, password], (err, row) => {
if (err) {
console.error('Login error:', err);
return res.json({ code: 1, msg: '服务器内部错误' });
}
if (!row) {
return res.json({ code: 1, msg: '账号或密码错误' });
}
let parsedRules = [];
try {
parsedRules = row.rules ? JSON.parse(row.rules) : [];
} catch (e) {
console.error('Failed to parse rules JSON', e);
}
res.json({
code: 0,
msg: '登录成功',
data: { rules: parsedRules }
});
});
});
// === 接口 3: 同步配置数据 (保存更新) ===
app.post('/api/sync', (req, res) => {
const { username, rules } = req.body;
if (!username || !Array.isArray(rules)) {
return res.json({ code: 1, msg: '参数不合法' });
}
const rulesJsonStr = JSON.stringify(rules);
// 覆盖更新该用户的 rules 列
// (简化起见,此处信任前端传来的 username。真实生产在这一步应当检验 token/session不过做个人小工具够用即可防君子
db.run('UPDATE users SET rules = ? WHERE username = ?', [rulesJsonStr, username], function (err) {
if (err) {
console.error('Sync error:', err);
return res.json({ code: 1, msg: '同步失败:服务器内部错误' });
}
if (this.changes === 0) {
return res.json({ code: 1, msg: '同步失败:未找到该用户' });
}
res.json({ code: 0, msg: '同步成功' });
});
});
// 启动服务器
app.listen(PORT, '0.0.0.0', () => {
console.log(`Server is running on http://0.0.0.0:${PORT}`);
console.log(`API endpoints available:`);
console.log(`- POST /api/register`);
console.log(`- POST /api/login`);
console.log(`- POST /api/sync`);
});