test: update admin/share edge scripts for cookie+csrf auth

This commit is contained in:
2026-02-17 21:32:07 +08:00
parent aed5dfdcb2
commit d236a790a1
2 changed files with 609 additions and 509 deletions

View File

@@ -1,69 +1,163 @@
/**
* 管理员功能完整性测试脚本
* 测试范围:
* 1. 用户管理 - 用户列表、搜索、封禁/解封、删除、修改存储权限、查看用户文件
* 2. 系统设置 - SMTP邮件配置、存储配置、注册开关、主题设置
* 3. 分享管理 - 查看所有分享、删除分享
* 4. 系统监控 - 健康检查、存储统计、操作日志
* 5. 安全检查 - 管理员权限验证、敏感操作确认
* 管理员功能完整性测试脚本Cookie + CSRF 认证模型)
*
* 覆盖范围:
* 1. 鉴权与权限校验
* 2. 用户管理(列表、封禁/删除自保护、存储权限)
* 3. 系统设置(获取/更新/参数校验)
* 4. 分享管理
* 5. 系统监控(健康、存储、日志)
* 6. 上传工具接口
*/
const http = require('http');
const https = require('https');
const { UserDB } = require('./database');
const BASE_URL = 'http://localhost:40001';
let adminToken = '';
let testUserId = null;
let testShareId = null;
const BASE_URL = process.env.TEST_BASE_URL || 'http://127.0.0.1:40001';
const state = {
adminSession: {
cookies: {},
csrfToken: ''
},
adminUserId: null,
testUserId: null,
latestSettings: null
};
// 测试结果收集
const testResults = {
passed: [],
failed: [],
warnings: []
};
// 辅助函数发送HTTP请求
function request(method, path, data = null, token = null) {
function makeCookieHeader(cookies) {
return Object.entries(cookies || {})
.map(([k, v]) => `${k}=${v}`)
.join('; ');
}
function storeSetCookies(session, setCookieHeader) {
if (!session || !setCookieHeader) return;
const list = Array.isArray(setCookieHeader) ? setCookieHeader : [setCookieHeader];
for (const raw of list) {
const first = String(raw || '').split(';')[0];
const idx = first.indexOf('=');
if (idx <= 0) continue;
const key = first.slice(0, idx).trim();
const value = first.slice(idx + 1).trim();
session.cookies[key] = value;
if (key === 'csrf_token') {
session.csrfToken = value;
}
}
}
function isSafeMethod(method) {
const upper = String(method || '').toUpperCase();
return upper === 'GET' || upper === 'HEAD' || upper === 'OPTIONS';
}
function request(method, path, options = {}) {
const {
data = null,
session = null,
headers = {},
requireCsrf = true
} = options;
return new Promise((resolve, reject) => {
const url = new URL(path, BASE_URL);
const options = {
hostname: url.hostname,
port: url.port,
path: url.pathname + url.search,
method: method,
headers: {
'Content-Type': 'application/json'
}
};
const transport = url.protocol === 'https:' ? https : http;
if (token) {
options.headers['Authorization'] = `Bearer ${token}`;
const requestHeaders = { ...headers };
if (session) {
const cookieHeader = makeCookieHeader(session.cookies);
if (cookieHeader) {
requestHeaders.Cookie = cookieHeader;
}
if (requireCsrf && !isSafeMethod(method)) {
const csrfToken = session.csrfToken || session.cookies.csrf_token;
if (csrfToken) {
requestHeaders['X-CSRF-Token'] = csrfToken;
}
}
}
const req = http.request(options, (res) => {
let payload = null;
if (data !== null && data !== undefined) {
payload = JSON.stringify(data);
requestHeaders['Content-Type'] = 'application/json';
requestHeaders['Content-Length'] = Buffer.byteLength(payload);
}
const req = transport.request({
protocol: url.protocol,
hostname: url.hostname,
port: url.port || (url.protocol === 'https:' ? 443 : 80),
path: url.pathname + url.search,
method,
headers: requestHeaders
}, (res) => {
let body = '';
res.on('data', chunk => body += chunk);
res.on('data', chunk => {
body += chunk;
});
res.on('end', () => {
try {
const json = JSON.parse(body);
resolve({ status: res.statusCode, data: json });
} catch (e) {
resolve({ status: res.statusCode, data: body });
if (session) {
storeSetCookies(session, res.headers['set-cookie']);
}
let parsed = body;
try {
parsed = body ? JSON.parse(body) : {};
} catch (e) {
// keep raw text
}
resolve({
status: res.statusCode,
data: parsed,
headers: res.headers
});
});
});
req.on('error', reject);
if (data) {
req.write(JSON.stringify(data));
if (payload) {
req.write(payload);
}
req.end();
});
}
// 测试函数包装器
async function initCsrf(session) {
const res = await request('GET', '/api/csrf-token', {
session,
requireCsrf: false
});
if (res.status === 200 && res.data && res.data.csrfToken) {
session.csrfToken = res.data.csrfToken;
}
return res;
}
function assert(condition, message) {
if (!condition) {
throw new Error(message);
}
}
function warn(message) {
testResults.warnings.push(message);
console.log(`[WARN] ${message}`);
}
async function test(name, fn) {
try {
await fn();
@@ -75,432 +169,355 @@ async function test(name, fn) {
}
}
// 警告记录
function warn(message) {
testResults.warnings.push(message);
console.log(`[WARN] ${message}`);
function ensureTestUser() {
if (state.testUserId) {
return;
}
const suffix = Date.now();
const username = `admin_test_user_${suffix}`;
const email = `${username}@test.local`;
const password = `AdminTest#${suffix}`;
const id = UserDB.create({
username,
email,
password,
is_verified: 1
});
UserDB.update(id, {
is_active: 1,
is_banned: 0,
storage_permission: 'user_choice',
current_storage_type: 'oss'
});
state.testUserId = id;
}
// 断言函数
function assert(condition, message) {
if (!condition) {
throw new Error(message);
function cleanupTestUser() {
if (!state.testUserId) return;
try {
UserDB.delete(state.testUserId);
} catch (error) {
warn(`清理测试用户失败: ${error.message}`);
} finally {
state.testUserId = null;
}
}
// ============ 测试用例 ============
// 1. 安全检查:未认证访问应被拒绝
async function testUnauthorizedAccess() {
const res = await request('GET', '/api/admin/users');
assert(res.status === 401, `未认证访问应返回401实际返回: ${res.status}`);
}
// 2. 管理员登录
async function testAdminLogin() {
const res = await request('POST', '/api/login', {
username: 'admin',
password: 'admin123',
captcha: '' // 开发环境可能不需要验证码
});
// 登录可能因为验证码失败,这是预期的
if (res.status === 400 && res.data.message && res.data.message.includes('验证码')) {
warn('登录需要验证码跳过登录测试使用模拟token');
// 使用JWT库生成一个测试token需要知道JWT_SECRET
// 或者直接查询数据库
return;
}
if (res.data.success) {
adminToken = res.data.token;
console.log(' - 获取到管理员token');
} else {
throw new Error(`登录失败: ${res.data.message}`);
}
}
// 3. 用户列表获取
async function testGetUsers() {
if (!adminToken) {
warn('无admin token跳过用户列表测试');
return;
}
const res = await request('GET', '/api/admin/users', null, adminToken);
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data.success === true, '应返回success: true');
assert(Array.isArray(res.data.users), 'users应为数组');
// 记录测试用户ID
if (res.data.users.length > 1) {
const nonAdminUser = res.data.users.find(u => !u.is_admin);
if (nonAdminUser) {
testUserId = nonAdminUser.id;
// 2. 安全检查:无效 Token 应被拒绝
async function testInvalidTokenAccess() {
const res = await request('GET', '/api/admin/users', {
headers: {
Authorization: 'Bearer invalid-token'
}
}
}
// 4. 系统设置获取
async function testGetSettings() {
if (!adminToken) {
warn('无admin token跳过系统设置测试');
return;
}
const res = await request('GET', '/api/admin/settings', null, adminToken);
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data.success === true, '应返回success: true');
assert(res.data.settings !== undefined, '应包含settings对象');
assert(res.data.settings.smtp !== undefined, '应包含smtp配置');
assert(res.data.settings.global_theme !== undefined, '应包含全局主题设置');
}
// 5. 更新系统设置
async function testUpdateSettings() {
if (!adminToken) {
warn('无admin token跳过更新系统设置测试');
return;
}
const res = await request('POST', '/api/admin/settings', {
global_theme: 'dark',
max_upload_size: 10737418240
}, adminToken);
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data.success === true, '应返回success: true');
}
// 6. 健康检查
async function testHealthCheck() {
if (!adminToken) {
warn('无admin token跳过健康检查测试');
return;
}
const res = await request('GET', '/api/admin/health-check', null, adminToken);
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data.success === true, '应返回success: true');
assert(res.data.checks !== undefined, '应包含checks数组');
assert(res.data.overallStatus !== undefined, '应包含overallStatus');
assert(res.data.summary !== undefined, '应包含summary');
// 检查各项检测项目
const checkNames = res.data.checks.map(c => c.name);
assert(checkNames.includes('JWT密钥'), '应包含JWT密钥检查');
assert(checkNames.includes('数据库连接'), '应包含数据库连接检查');
assert(checkNames.includes('存储目录'), '应包含存储目录检查');
}
// 7. 存储统计
async function testStorageStats() {
if (!adminToken) {
warn('无admin token跳过存储统计测试');
return;
}
const res = await request('GET', '/api/admin/storage-stats', null, adminToken);
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data.success === true, '应返回success: true');
assert(res.data.stats !== undefined, '应包含stats对象');
assert(typeof res.data.stats.totalDisk === 'number', 'totalDisk应为数字');
}
// 8. 系统日志获取
async function testGetLogs() {
if (!adminToken) {
warn('无admin token跳过系统日志测试');
return;
}
const res = await request('GET', '/api/admin/logs?page=1&pageSize=10', null, adminToken);
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data.success === true, '应返回success: true');
assert(Array.isArray(res.data.logs), 'logs应为数组');
assert(typeof res.data.total === 'number', 'total应为数字');
}
// 9. 日志统计
async function testLogStats() {
if (!adminToken) {
warn('无admin token跳过日志统计测试');
return;
}
const res = await request('GET', '/api/admin/logs/stats', null, adminToken);
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data.success === true, '应返回success: true');
assert(res.data.stats !== undefined, '应包含stats对象');
}
// 10. 分享列表获取
async function testGetShares() {
if (!adminToken) {
warn('无admin token跳过分享列表测试');
return;
}
const res = await request('GET', '/api/admin/shares', null, adminToken);
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data.success === true, '应返回success: true');
assert(Array.isArray(res.data.shares), 'shares应为数组');
// 记录测试分享ID
if (res.data.shares.length > 0) {
testShareId = res.data.shares[0].id;
}
}
// 11. 安全检查普通用户不能访问管理员API
async function testNonAdminAccess() {
// 使用一个无效的token模拟普通用户
const fakeToken = 'invalid-token';
const res = await request('GET', '/api/admin/users', null, fakeToken);
});
assert(res.status === 401, `无效token应返回401实际: ${res.status}`);
}
// 12. 安全检查:不能封禁自己
async function testCannotBanSelf() {
if (!adminToken) {
warn('无admin token跳过封禁自己测试');
return;
}
// 3. 管理员登录(基于 Cookie
async function testAdminLogin() {
await initCsrf(state.adminSession);
// 获取当前管理员ID
const usersRes = await request('GET', '/api/admin/users', null, adminToken);
const adminUser = usersRes.data.users.find(u => u.is_admin);
const res = await request('POST', '/api/login', {
data: {
username: 'admin',
password: 'admin123'
},
session: state.adminSession,
requireCsrf: false
});
if (!adminUser) {
warn('未找到管理员用户');
return;
}
assert(res.status === 200, `登录应返回200实际: ${res.status}`);
assert(res.data && res.data.success === true, `登录失败: ${res.data?.message || 'unknown'}`);
assert(!!state.adminSession.cookies.token, '登录后应写入 token Cookie');
const res = await request('POST', `/api/admin/users/${adminUser.id}/ban`, {
banned: true
}, adminToken);
await initCsrf(state.adminSession);
assert(res.status === 400, `封禁自己应返回400实际: ${res.status}`);
assert(res.data.message.includes('不能封禁自己'), '应提示不能封禁自己');
const profileRes = await request('GET', '/api/user/profile', {
session: state.adminSession
});
assert(profileRes.status === 200, `读取profile应返回200实际: ${profileRes.status}`);
assert(profileRes.data?.success === true, '读取profile应成功');
assert(profileRes.data?.user?.is_admin === 1, '登录账号应为管理员');
state.adminUserId = profileRes.data.user.id;
assert(Number.isInteger(state.adminUserId) && state.adminUserId > 0, '应获取管理员ID');
}
// 13. 安全检查:不能删除自己
// 4. 用户列表获取(分页)
async function testGetUsers() {
const res = await request('GET', '/api/admin/users?paged=1&page=1&pageSize=20&sort=created_desc', {
session: state.adminSession
});
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data?.success === true, '应返回success: true');
assert(Array.isArray(res.data?.users), 'users应为数组');
assert(!!res.data?.pagination, '分页模式应返回pagination');
}
// 5. 系统设置获取
async function testGetSettings() {
const res = await request('GET', '/api/admin/settings', {
session: state.adminSession
});
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data?.success === true, '应返回success: true');
assert(res.data?.settings && typeof res.data.settings === 'object', '应包含settings对象');
assert(res.data?.settings?.smtp && typeof res.data.settings.smtp === 'object', '应包含smtp配置');
assert(res.data?.settings?.global_theme !== undefined, '应包含全局主题设置');
state.latestSettings = res.data.settings;
}
// 6. 更新系统设置(写回当前值,避免影响测试环境)
async function testUpdateSettings() {
const current = state.latestSettings || {};
const payload = {
global_theme: current.global_theme || 'dark',
max_upload_size: Number(current.max_upload_size || 10737418240)
};
const res = await request('POST', '/api/admin/settings', {
data: payload,
session: state.adminSession
});
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data?.success === true, '应返回success: true');
}
// 7. 健康检查
async function testHealthCheck() {
const res = await request('GET', '/api/admin/health-check', {
session: state.adminSession
});
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data?.success === true, '应返回success: true');
assert(Array.isArray(res.data?.checks), '应包含checks数组');
assert(res.data?.summary && typeof res.data.summary === 'object', '应包含summary');
}
// 8. 存储统计
async function testStorageStats() {
const res = await request('GET', '/api/admin/storage-stats', {
session: state.adminSession
});
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data?.success === true, '应返回success: true');
assert(res.data?.stats && typeof res.data.stats === 'object', '应包含stats对象');
}
// 9. 系统日志获取
async function testGetLogs() {
const res = await request('GET', '/api/admin/logs?page=1&pageSize=10', {
session: state.adminSession
});
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data?.success === true, '应返回success: true');
assert(Array.isArray(res.data?.logs), 'logs应为数组');
}
// 10. 日志统计
async function testLogStats() {
const res = await request('GET', '/api/admin/logs/stats', {
session: state.adminSession
});
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data?.success === true, '应返回success: true');
assert(res.data?.stats && typeof res.data.stats === 'object', '应包含stats对象');
}
// 11. 分享列表获取
async function testGetShares() {
const res = await request('GET', '/api/admin/shares', {
session: state.adminSession
});
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data?.success === true, '应返回success: true');
assert(Array.isArray(res.data?.shares), 'shares应为数组');
}
// 12. 不能封禁自己
async function testCannotBanSelf() {
assert(state.adminUserId, '管理员ID未初始化');
const res = await request('POST', `/api/admin/users/${state.adminUserId}/ban`, {
data: { banned: true },
session: state.adminSession
});
assert(res.status === 400, `封禁自己应返回400实际: ${res.status}`);
assert(String(res.data?.message || '').includes('不能封禁自己'), '应提示不能封禁自己');
}
// 13. 不能删除自己
async function testCannotDeleteSelf() {
if (!adminToken) {
warn('无admin token跳过删除自己测试');
return;
}
assert(state.adminUserId, '管理员ID未初始化');
const usersRes = await request('GET', '/api/admin/users', null, adminToken);
const adminUser = usersRes.data.users.find(u => u.is_admin);
const res = await request('DELETE', `/api/admin/users/${state.adminUserId}`, {
session: state.adminSession
});
if (!adminUser) {
warn('未找到管理员用户');
return;
}
const res = await request('DELETE', `/api/admin/users/${adminUser.id}`, null, adminToken);
assert(res.status === 400, `删除自己应返回400实际: ${res.status}`);
assert(res.data.message.includes('不能删除自己'), '应提示不能删除自己');
assert(String(res.data?.message || '').includes('不能删除自己'), '应提示不能删除自己');
}
// 14. 参数验证无效用户ID
async function testInvalidUserId() {
if (!adminToken) {
warn('无admin token跳过无效用户ID测试');
return;
}
const res = await request('POST', '/api/admin/users/invalid/ban', {
banned: true
}, adminToken);
data: { banned: true },
session: state.adminSession
});
assert(res.status === 400, `无效用户ID应返回400实际: ${res.status}`);
}
// 15. 参数验证无效分享ID
async function testInvalidShareId() {
if (!adminToken) {
warn('无admin token跳过无效分享ID测试');
return;
}
const res = await request('DELETE', '/api/admin/shares/invalid', {
session: state.adminSession
});
const res = await request('DELETE', '/api/admin/shares/invalid', null, adminToken);
assert(res.status === 400, `无效分享ID应返回400实际: ${res.status}`);
}
// 16. 存储权限设置
async function testSetStoragePermission() {
if (!adminToken || !testUserId) {
warn('无admin token或测试用户跳过存储权限测试');
return;
}
ensureTestUser();
const res = await request('POST', `/api/admin/users/${testUserId}/storage-permission`, {
storage_permission: 'local_only',
local_storage_quota: 2147483648 // 2GB
}, adminToken);
const res = await request('POST', `/api/admin/users/${state.testUserId}/storage-permission`, {
data: {
storage_permission: 'local_only',
local_storage_quota: 2147483648,
download_traffic_quota: 3221225472
},
session: state.adminSession
});
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data.success === true, '应返回success: true');
assert(res.data?.success === true, '应返回success: true');
}
// 17. 参数验证:无效的存储权限值
async function testInvalidStoragePermission() {
if (!adminToken || !testUserId) {
warn('无admin token或测试用户跳过无效存储权限测试');
return;
}
ensureTestUser();
const res = await request('POST', `/api/admin/users/${testUserId}/storage-permission`, {
storage_permission: 'invalid_permission'
}, adminToken);
const res = await request('POST', `/api/admin/users/${state.testUserId}/storage-permission`, {
data: { storage_permission: 'invalid_permission' },
session: state.adminSession
});
assert(res.status === 400, `无效存储权限应返回400实际: ${res.status}`);
}
// 18. 主题设置验证
async function testInvalidTheme() {
if (!adminToken) {
warn('无admin token跳过无效主题测试');
return;
}
const res = await request('POST', '/api/admin/settings', {
global_theme: 'invalid_theme'
}, adminToken);
data: { global_theme: 'invalid_theme' },
session: state.adminSession
});
assert(res.status === 400, `无效主题应返回400实际: ${res.status}`);
}
// 19. 日志清理测试
async function testLogCleanup() {
if (!adminToken) {
warn('无admin token跳过日志清理测试');
return;
}
const res = await request('POST', '/api/admin/logs/cleanup', {
keepDays: 90
}, adminToken);
data: { keepDays: 90 },
session: state.adminSession
});
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data.success === true, '应返回success: true');
assert(typeof res.data.deletedCount === 'number', 'deletedCount应为数字');
assert(res.data?.success === true, '应返回success: true');
assert(typeof res.data?.deletedCount === 'number', 'deletedCount应为数字');
}
// 20. SMTP测试预期失败因为未配置)
// 20. SMTP测试未配置时返回400配置后可能200/500
async function testSmtpTest() {
if (!adminToken) {
warn('无admin token跳过SMTP测试');
return;
}
const res = await request('POST', '/api/admin/settings/test-smtp', {
to: 'test@example.com'
}, adminToken);
data: { to: 'test@example.com' },
session: state.adminSession
});
// SMTP未配置时应返回400
if (res.status === 400 && res.data.message && res.data.message.includes('SMTP未配置')) {
if (res.status === 400 && String(res.data?.message || '').includes('SMTP未配置')) {
console.log(' - SMTP未配置这是预期的');
return;
}
// 如果SMTP已配置可能成功或失败
assert(res.status === 200 || res.status === 500, `应返回200或500实际: ${res.status}`);
}
// 21. 上传工具检查
async function testCheckUploadTool() {
if (!adminToken) {
warn('无admin token跳过上传工具检查测试');
return;
}
// 21. 上传工具配置生成(替代已移除的 /api/admin/check-upload-tool
async function testGenerateUploadToolConfig() {
const res = await request('POST', '/api/upload/generate-tool', {
data: {},
session: state.adminSession
});
const res = await request('GET', '/api/admin/check-upload-tool', null, adminToken);
assert(res.status === 200, `应返回200实际: ${res.status}`);
assert(res.data.success === true, '应返回success: true');
assert(typeof res.data.exists === 'boolean', 'exists应为布尔值');
assert(res.data?.success === true, '应返回success: true');
assert(res.data?.config && typeof res.data.config === 'object', '应包含config对象');
assert(typeof res.data?.config?.api_key === 'string' && res.data.config.api_key.length > 0, '应返回有效api_key');
}
// 22. 用户文件查看 - 无效用户ID验证
async function testInvalidUserIdForFiles() {
if (!adminToken) {
warn('无admin token跳过用户文件查看无效ID测试');
return;
}
const res = await request('GET', '/api/admin/users/invalid/files', {
session: state.adminSession
});
const res = await request('GET', '/api/admin/users/invalid/files', null, adminToken);
assert(res.status === 400, `无效用户ID应返回400实际: ${res.status}`);
}
// 23. 删除用户 - 无效用户ID验证
async function testInvalidUserIdForDelete() {
if (!adminToken) {
warn('无admin token跳过删除用户无效ID测试');
return;
}
const res = await request('DELETE', '/api/admin/users/invalid', {
session: state.adminSession
});
const res = await request('DELETE', '/api/admin/users/invalid', null, adminToken);
assert(res.status === 400, `无效用户ID应返回400实际: ${res.status}`);
}
// 24. 存储权限设置 - 无效用户ID验证
async function testInvalidUserIdForPermission() {
if (!adminToken) {
warn('无admin token跳过存储权限无效ID测试');
return;
}
const res = await request('POST', '/api/admin/users/invalid/storage-permission', {
storage_permission: 'local_only'
}, adminToken);
data: {
storage_permission: 'local_only'
},
session: state.adminSession
});
assert(res.status === 400, `无效用户ID应返回400实际: ${res.status}`);
}
// 主测试函数
async function runTests() {
console.log('========================================');
console.log('管理员功能完整性测试');
console.log('管理员功能完整性测试Cookie + CSRF');
console.log('========================================\n');
// 先尝试直接使用数据库获取token
try {
const jwt = require('jsonwebtoken');
const { UserDB } = require('./database');
require('dotenv').config();
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key-change-in-production';
const adminUser = UserDB.findByUsername('admin');
if (adminUser) {
adminToken = jwt.sign(
{
id: adminUser.id,
username: adminUser.username,
is_admin: adminUser.is_admin,
type: 'access'
},
JWT_SECRET,
{ expiresIn: '2h' }
);
console.log('[INFO] 已通过数据库直接生成管理员token\n');
}
} catch (e) {
console.log('[INFO] 无法直接生成token将尝试登录: ' + e.message + '\n');
}
// 安全检查测试
console.log('\n--- 安全检查 ---');
await test('未认证访问应被拒绝', testUnauthorizedAccess);
await test('无效token应被拒绝', testNonAdminAccess);
await test('无效token应被拒绝', testInvalidTokenAccess);
// 如果还没有token尝试登录
if (!adminToken) {
await test('管理员登录', testAdminLogin);
}
await test('管理员登录', testAdminLogin);
// 用户管理测试
console.log('\n--- 用户管理 ---');
await test('获取用户列表', testGetUsers);
await test('不能封禁自己', testCannotBanSelf);
@@ -509,19 +526,16 @@ async function runTests() {
await test('设置存储权限', testSetStoragePermission);
await test('无效存储权限验证', testInvalidStoragePermission);
// 系统设置测试
console.log('\n--- 系统设置 ---');
await test('获取系统设置', testGetSettings);
await test('更新系统设置', testUpdateSettings);
await test('无效主题验证', testInvalidTheme);
await test('SMTP测试', testSmtpTest);
// 分享管理测试
console.log('\n--- 分享管理 ---');
await test('获取分享列表', testGetShares);
await test('无效分享ID验证', testInvalidShareId);
// 系统监控测试
console.log('\n--- 系统监控 ---');
await test('健康检查', testHealthCheck);
await test('存储统计', testStorageStats);
@@ -529,17 +543,16 @@ async function runTests() {
await test('日志统计', testLogStats);
await test('日志清理', testLogCleanup);
// 其他功能测试
console.log('\n--- 其他功能 ---');
await test('上传工具检查', testCheckUploadTool);
await test('上传工具配置生成', testGenerateUploadToolConfig);
// 参数验证增强测试
console.log('\n--- 参数验证增强 ---');
await test('用户文件查看无效ID验证', testInvalidUserIdForFiles);
await test('删除用户无效ID验证', testInvalidUserIdForDelete);
await test('存储权限设置无效ID验证', testInvalidUserIdForPermission);
// 输出测试结果
cleanupTestUser();
console.log('\n========================================');
console.log('测试结果汇总');
console.log('========================================');
@@ -549,26 +562,25 @@ async function runTests() {
if (testResults.failed.length > 0) {
console.log('\n失败的测试:');
testResults.failed.forEach(f => {
for (const f of testResults.failed) {
console.log(` - ${f.name}: ${f.error}`);
});
}
}
if (testResults.warnings.length > 0) {
console.log('\n警告:');
testResults.warnings.forEach(w => {
for (const w of testResults.warnings) {
console.log(` - ${w}`);
});
}
}
console.log('\n========================================');
// 返回退出码
process.exit(testResults.failed.length > 0 ? 1 : 0);
}
// 运行测试
runTests().catch(err => {
console.error('测试执行错误:', err);
runTests().catch((error) => {
cleanupTestUser();
console.error('测试执行异常:', error);
process.exit(1);
});