57 lines
2.6 KiB
TypeScript
57 lines
2.6 KiB
TypeScript
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 })
|
||
}
|
||
}
|