Compare commits

..

No commits in common. "ada95e4e7fe37459344a921422ee1fa376810d70" and "629924c342315d294faf133baecb28e9233a5bc3" have entirely different histories.

5 changed files with 4 additions and 70 deletions

View File

@ -3,7 +3,7 @@ import { cookies } from 'next/headers'
import { getDb } from '@/lib/db' import { getDb } from '@/lib/db'
import { verifyToken } from '@/lib/auth' import { verifyToken } from '@/lib/auth'
import { checkPermission } from '@/lib/permissions' import { checkPermission } from '@/lib/permissions'
import { writeAuditLog, getClientIP, diffObjects } from '@/lib/audit' import { writeAuditLog, getClientIP } from '@/lib/audit'
async function getSession() { async function getSession() {
const cookieStore = await cookies() const cookieStore = await cookies()
@ -20,8 +20,7 @@ export async function PUT(request: Request, { params }: { params: Promise<{ id:
} }
const { id } = await params const { id } = await params
type ApiKeyRow = { id: number; name: string; permissions: string; expires_at: string | null; is_active: number } const existing = getDb().prepare('SELECT id FROM api_keys WHERE id = ?').get(id)
const existing = getDb().prepare<[string | number], ApiKeyRow>('SELECT id, name, permissions, expires_at, is_active FROM api_keys WHERE id = ?').get(id)
if (!existing) return NextResponse.json({ error: 'API Key 不存在' }, { status: 404 }) if (!existing) return NextResponse.json({ error: 'API Key 不存在' }, { status: 404 })
try { try {
@ -36,20 +35,6 @@ export async function PUT(request: Request, { params }: { params: Promise<{ id:
is_active !== undefined ? (is_active ? 1 : 0) : 1, is_active !== undefined ? (is_active ? 1 : 0) : 1,
id id
) )
// 审计日志
const changes = diffObjects(existing as unknown as Record<string, unknown>, body)
if (Object.keys(changes).length > 0) {
writeAuditLog({
userId: session.id,
action: 'update',
entityType: 'api_key',
entityId: Number(id),
details: { changes },
ipAddress: getClientIP(request),
})
}
return NextResponse.json({ success: true }) return NextResponse.json({ success: true })
} catch (e) { } catch (e) {
const msg = e instanceof Error ? e.message : '更新失败' const msg = e instanceof Error ? e.message : '更新失败'

View File

@ -1,6 +1,5 @@
// GET + POST /api/auth/logout — 退出登录(清除 cookie + 302 跳转 /login // GET + POST /api/auth/logout — 退出登录(清除 cookie + 302 跳转 /login
import { NextRequest, NextResponse } from 'next/server' import { NextResponse } from 'next/server'
import { writeAuditLog, getClientIP } from '@/lib/audit'
const cookieDomain = process.env.COOKIE_DOMAIN || '.tlyq.ai' const cookieDomain = process.env.COOKIE_DOMAIN || '.tlyq.ai'
@ -23,28 +22,4 @@ function logoutResponse(): NextResponse {
} }
export async function GET() { return logoutResponse() } export async function GET() { return logoutResponse() }
export async function POST() { return logoutResponse() }
export async function POST(request: NextRequest) {
// 从 session cookie 提取用户名用于审计
let username = 'anonymous'
try {
const token =
request.cookies.get('tlyq_session')?.value ||
request.cookies.get('session_issue')?.value
if (token) {
const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString())
username = payload.username || 'unknown'
}
} catch { /* 解析失败,使用默认值 */ }
writeAuditLog({
userId: null,
username,
action: 'logout',
entityType: 'auth',
details: { message: '用户登出' },
ipAddress: getClientIP(request),
})
return logoutResponse()
}

View File

@ -3,7 +3,6 @@ import { getDb } from '@/lib/db'
import { initDatabase } from '@/lib/db-schema' import { initDatabase } from '@/lib/db-schema'
import { getCurrentUser } from '@/lib/auth' import { getCurrentUser } from '@/lib/auth'
import { hasPermission } from '@/lib/permissions' import { hasPermission } from '@/lib/permissions'
import { writeAuditLog, getClientIP } from '@/lib/audit'
import fs from 'fs' import fs from 'fs'
export async function GET(_request: Request, { params }: { params: Promise<{ id: string }> }) { export async function GET(_request: Request, { params }: { params: Promise<{ id: string }> }) {
@ -90,16 +89,6 @@ export async function DELETE(_request: NextRequest, { params }: { params: Promis
// 删除数据库记录 // 删除数据库记录
db.prepare('DELETE FROM reports WHERE id = ?').run(id) db.prepare('DELETE FROM reports WHERE id = ?').run(id)
writeAuditLog({
userId: user.id,
apiKeyId: null,
action: 'delete',
entityType: 'report',
entityId: Number(id),
details: { deleted: { id: Number(id), title: report.title, type: report.type, period_start: report.period_start, period_end: report.period_end, file_path: report.file_path } },
ipAddress: getClientIP(_request),
})
return NextResponse.json({ success: true }) return NextResponse.json({ success: true })
} catch (e) { } catch (e) {
const msg = e instanceof Error ? e.message : '删除失败' const msg = e instanceof Error ? e.message : '删除失败'

View File

@ -3,7 +3,6 @@ import { getDb } from '@/lib/db'
import { initDatabase } from '@/lib/db-schema' import { initDatabase } from '@/lib/db-schema'
import { getCurrentUser } from '@/lib/auth' import { getCurrentUser } from '@/lib/auth'
import { hasPermission } from '@/lib/permissions' import { hasPermission } from '@/lib/permissions'
import { writeAuditLog, getClientIP } from '@/lib/audit'
import JSZip from 'jszip' import JSZip from 'jszip'
import fs from 'fs' import fs from 'fs'
@ -44,16 +43,6 @@ export async function POST(request: NextRequest) {
const zipBuffer = await zip.generateAsync({ type: 'nodebuffer' }) const zipBuffer = await zip.generateAsync({ type: 'nodebuffer' })
writeAuditLog({
userId: user.id,
apiKeyId: null,
action: 'export',
entityType: 'report',
entityId: null,
details: { exported_count: ids.length, ids },
ipAddress: getClientIP(request),
})
const d = new Date() const d = new Date()
const today = `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}` const today = `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`
const downloadName = `reports_${today}.zip` const downloadName = `reports_${today}.zip`

View File

@ -17,10 +17,6 @@ export function initDatabase(): void {
// 迁移:添加 parts_name 列 // 迁移:添加 parts_name 列
try { db.exec('ALTER TABLE tickets ADD COLUMN parts_name TEXT') } catch { /* 列已存在 */ } try { db.exec('ALTER TABLE tickets ADD COLUMN parts_name TEXT') } catch { /* 列已存在 */ }
// 迁移:添加 audit_logs.username 列(共享库 write-audit-log.ts 写入此列)
try { db.exec('ALTER TABLE audit_logs ADD COLUMN username TEXT') } catch { /* 列已存在 */ }
// 迁移:添加 audit_logs.api_key_id 列(共享库 audit-schema.ts 已定义)
try { db.exec('ALTER TABLE audit_logs ADD COLUMN api_key_id INTEGER REFERENCES api_keys(id)') } catch { /* 列已存在 */ }
// 迁移:添加 ticket_type 列 // 迁移:添加 ticket_type 列
try { db.exec('ALTER TABLE tickets ADD COLUMN ticket_type TEXT') } catch { /* 列已存在 */ } try { db.exec('ALTER TABLE tickets ADD COLUMN ticket_type TEXT') } catch { /* 列已存在 */ }