oa-ai/src/app/api/auth/change-password/route.ts

57 lines
2.6 KiB
TypeScript
Raw 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.

import { NextResponse } from 'next/server'
import { cookies } from 'next/headers'
import { exec } from 'child_process'
import { promisify } from 'util'
import { verifySharedJwt } from '@/lib/jwt'
const execAsync = promisify(exec)
export async function POST(request: Request) {
try {
const cookieStore = await cookies()
const token = cookieStore.get('tlyq_session')?.value
if (!token) return NextResponse.json({ error: '未登录' }, { status: 401 })
const session = verifySharedJwt(token)
if (!session) return NextResponse.json({ error: '会话已过期' }, { status: 401 })
const { currentPassword, newPassword } = await request.json()
if (!currentPassword || !newPassword) {
return NextResponse.json({ error: '请输入当前密码和新密码' }, { status: 400 })
}
if (newPassword.length < 8) {
return NextResponse.json({ error: '新密码至少 8 位' }, { status: 400 })
}
// 密码复杂度:大写/小写/数字/特殊字符 4选3
const hasUpper = /[A-Z]/.test(newPassword)
const hasLower = /[a-z]/.test(newPassword)
const hasDigit = /[0-9]/.test(newPassword)
const hasSpecial = /[^A-Za-z0-9]/.test(newPassword)
const complexityScore = [hasUpper, hasLower, hasDigit, hasSpecial].filter(Boolean).length
if (complexityScore < 3) {
return NextResponse.json({ error: '密码需包含大写字母、小写字母、数字、特殊字符中至少 3 种' }, { status: 400 })
}
// 从 LLDAP 容器动态获取 admin 密码不硬编码admin 改密码后无需改 OA 配置)
const { stdout: adminPassOut } = await execAsync('docker exec lldap printenv LLDAP_ADMIN_PASSWORD', { timeout: 3000 })
const adminPass = (adminPassOut.trim() || 'admin123').replace(/'/g, "'\\''")
const safeUser = session.username.replace(/'/g, "'\\''")
const safePass = newPassword.replace(/'/g, "'\\''")
const cmd = `docker exec lldap ./lldap_set_password --base-url http://localhost:17170 --admin-username admin --admin-password '${adminPass}' --username '${safeUser}' --password '${safePass}'`
const { stdout, stderr } = await execAsync(cmd, { timeout: 10000 })
if (stderr && !stderr.includes('Successfully')) {
return NextResponse.json({ error: stderr.trim() || '修改失败' }, { status: 500 })
}
return NextResponse.json({ success: true })
} catch (err) {
const msg = err instanceof Error ? err.message : '修改失败'
if (msg.includes('command not found') || msg.includes('No such container')) {
return NextResponse.json({ error: '密码服务不可用' }, { status: 503 })
}
return NextResponse.json({ error: msg }, { status: 500 })
}
}