// 用户管理审计:角色 / 列表 / 新建 / 重置密码 / 删除 / 越权防护 const BASE = process.env.SYNC_BASE || 'http://127.0.0.1:3780' let pass = 0, fail = 0 function check(name, ok, detail) { if (ok) { pass++; console.log(' PASS ' + name) } else { fail++; console.log(' FAIL ' + name + (detail ? ' -> ' + String(JSON.stringify(detail)).slice(0, 160) : '')) } } async function req(path, method, body, token) { const r = await fetch(BASE + path, { method, headers: { 'Content-Type': 'application/json', ...(token ? { Authorization: 'Bearer ' + token } : {}) }, body: body ? JSON.stringify(body) : undefined }) return { status: r.status, data: await r.json().catch(() => ({})) } } async function main() { const ax = await req('/api/auth/register', 'POST', { username: 'xionglin', password: 'admin123' }) check('xionglin 注册成功', ax.status === 200, ax.data) const nu = await req('/api/auth/register', 'POST', { username: 'normal_u', password: 'normal123' }) check('普通用户注册成功', nu.status === 200, nu.data) const listNoAuth = await req('/api/admin/users', 'GET', null, nu.data.token) check('非管理员访问用户列表 403', listNoAuth.status === 403, listNoAuth.status) const badList = await req('/api/admin/users', 'GET', null) check('无 token 访问用户列表 403', badList.status === 403, badList.status) const list = await req('/api/admin/users', 'GET', null, ax.data.token) check('管理员可见用户列表', list.status === 200 && ((list.data.users || []).some(u => u.username === 'normal_u') && (list.data.users.some(u => u.username === 'xionglin' && u.role === 'admin'))), list.data) check('列表返回 me 字段', !!list.data.me) const create = await req('/api/admin/users/create', 'POST', { username: 'target_u', password: 'pass111' }, ax.data.token) check('管理员新建用户', create.status === 200 && !!create.data.userId, create.data) const dupCreate = await req('/api/admin/users/create', 'POST', { username: 'target_u', password: 'pass222' }, ax.data.token) check('重复用户名 409', dupCreate.status === 409, dupCreate.status) const loginTarget = await req('/api/auth/login', 'POST', { username: 'target_u', password: 'pass111' }) check('新用户可用初始密码登录', loginTarget.status === 200, loginTarget.status) const reset = await req('/api/admin/users/password', 'POST', { userId: create.data.userId, newPassword: 'pass999' }, ax.data.token) check('管理员重置密码 200', reset.status === 200, reset.data) const oldLogin = await req('/api/auth/login', 'POST', { username: 'target_u', password: 'pass111' }) check('旧密码失效 401', oldLogin.status === 401, oldLogin.status) const newLogin = await req('/api/auth/login', 'POST', { username: 'target_u', password: 'pass999' }) check('重置后新密码可登录', newLogin.status === 200, newLogin.status) const selfDel = await req('/api/admin/users/delete', 'POST', { userId: ax.data.userId }, ax.data.token) check('不能删除自己 400', selfDel.status === 400, selfDel.status) const del = await req('/api/admin/users/delete', 'POST', { userId: create.data.userId }, ax.data.token) check('删除用户 200', del.status === 200, del.data) const goneLogin = await req('/api/auth/login', 'POST', { username: 'target_u', password: 'pass999' }) check('删除后登录被拒 401', goneLogin.status === 401, goneLogin.status) const list2 = await req('/api/admin/users', 'GET', null, ax.data.token) check('列表不再含已删用户', !((list2.data.users || []).some(u => u.username === 'target_u'))) console.log('==== 用户管理审计: PASS ' + pass + ' / FAIL ' + fail + ' ====') process.exit(fail > 0 ? 1 : 0) } main().catch(e => { console.error('FAILED:', e && (e.stack || e.message)); process.exit(1) })