-
Notifications
You must be signed in to change notification settings - Fork 298
Expand file tree
/
Copy pathdbController.js
More file actions
117 lines (103 loc) · 3.22 KB
/
dbController.js
File metadata and controls
117 lines (103 loc) · 3.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/**
* 数据库查询控制器
* 提供安全的只读 SQL 查询功能
*/
import sqlite3pkg from 'node-sqlite3-wasm';
const { Database } = sqlite3pkg;
import path from 'path';
// 执行查询
export async function executeQuery(req, reply) {
try {
const { sql, params } = req.body;
if (!sql || !sql.trim()) {
return reply.code(400).send({
error: 'SQL 查询不能为空'
});
}
// 只允许 SELECT 查询
const trimmedSql = sql.trim().toLowerCase();
if (!trimmedSql.startsWith('select') && !trimmedSql.startsWith('pragma')) {
return reply.code(403).send({
error: '只允许 SELECT 查询'
});
}
// 额外安全检查
const dangerousKeywords = [
'drop', 'delete', 'insert', 'update', 'alter', 'create', 'truncate',
'replace', 'grant', 'revoke', 'lock', 'unlock', 'reindex', 'vacuum'
];
for (const keyword of dangerousKeywords) {
// Check for keyword surrounded by whitespace or non-word characters
// This prevents matching "update_time" but matches "update table" or "update\ntable"
const regex = new RegExp(`(^|[\\s\\W])${keyword}([\\s\\W]|$)`, 'i');
if (regex.test(trimmedSql)) {
return reply.code(403).send({
error: `不允许使用 ${keyword.toUpperCase()} 语句`
});
}
}
const dbPath = path.join(process.cwd(), 'database.db');
const db = new Database(dbPath);
try {
const rows = db.all(sql, params || []);
return reply.send({
success: true,
data: rows,
rows: rows.length
});
} finally {
db.close();
}
} catch (e) {
reply.code(500).send({
error: `SQL 错误: ${e.message}`
});
}
}
// 获取表结构
export async function getTables(req, reply) {
try {
const dbPath = path.join(process.cwd(), 'database.db');
const db = new Database(dbPath);
try {
const tables = db.all("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name");
return reply.send({
success: true,
tables: tables.map(t => t.name)
});
} finally {
db.close();
}
} catch (e) {
reply.code(500).send({
error: e.message
});
}
}
// 获取表结构
export async function getTableSchema(req, reply) {
try {
const { table } = req.params;
if (!table) {
return reply.code(400).send({
error: '表名不能为空'
});
}
const dbPath = path.join(process.cwd(), 'database.db');
const db = new Database(dbPath);
try {
const schema = db.all(`PRAGMA table_info(${table})`);
return reply.send({
success: true,
table,
columns: schema
});
} finally {
db.close();
}
} catch (e) {
reply.code(500).send({
error: e.message
});
}
}