85 lines
2.7 KiB
TypeScript
85 lines
2.7 KiB
TypeScript
import { Router } from 'express'
|
|
import axios from 'axios'
|
|
|
|
const router = Router()
|
|
|
|
let vwCookie: string | null = null
|
|
let vwCookieExpiry = 0
|
|
|
|
async function getCookie(): Promise<string> {
|
|
if (vwCookie && Date.now() < vwCookieExpiry) return vwCookie
|
|
|
|
const host = process.env.VAULTWARDEN_HOST
|
|
const token = process.env.VAULTWARDEN_ADMIN_TOKEN
|
|
if (!host || !token) throw new Error('VAULTWARDEN_HOST / VAULTWARDEN_ADMIN_TOKEN not configured')
|
|
|
|
const res = await axios.post(
|
|
`${host}/admin`,
|
|
new URLSearchParams({ token: token.trim() }),
|
|
{
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
maxRedirects: 0,
|
|
validateStatus: s => s === 303 || s === 200,
|
|
}
|
|
)
|
|
|
|
const setCookieHeader = res.headers['set-cookie']
|
|
const match = (Array.isArray(setCookieHeader) ? setCookieHeader : [setCookieHeader ?? ''])
|
|
.find(c => c.startsWith('VW_ADMIN='))
|
|
if (!match) throw new Error('Admin login failed — check VAULTWARDEN_ADMIN_TOKEN')
|
|
|
|
vwCookie = match.split(';')[0]
|
|
vwCookieExpiry = Date.now() + 18 * 60 * 1000
|
|
return vwCookie
|
|
}
|
|
|
|
router.get('/stats', async (_req, res) => {
|
|
try {
|
|
const host = process.env.VAULTWARDEN_HOST
|
|
if (!host) { res.status(503).json({ error: 'VAULTWARDEN_HOST not configured' }); return }
|
|
|
|
const cookie = await getCookie()
|
|
|
|
const [usersRes, diagRes] = await Promise.all([
|
|
axios.get(`${host}/admin/users`, { headers: { Cookie: cookie, Accept: 'application/json' } }),
|
|
axios.get(`${host}/admin/diagnostics`, { headers: { Cookie: cookie, Accept: 'application/json' } }),
|
|
])
|
|
|
|
type VwUser = {
|
|
id: string
|
|
email: string
|
|
name?: string
|
|
lastActive?: string
|
|
creationDate?: string
|
|
userEnabled?: boolean
|
|
twoFactorEnabled?: boolean
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const users: any[] = usersRes.data ?? []
|
|
const diag = diagRes.data ?? {}
|
|
|
|
res.json({
|
|
version: diag.version ?? null,
|
|
signupsAllowed: diag.config?.signups_allowed ?? null,
|
|
userCount: users.length,
|
|
users: users.map(u => ({
|
|
email: u.email,
|
|
name: u.name || u.email,
|
|
enabled: u.userEnabled ?? true,
|
|
lastActive: u.lastActive ?? null,
|
|
created: u.creationDate ?? null,
|
|
twoFa: u.twoFactorEnabled ?? false,
|
|
cipherCount: u.cipherCount ?? u.cipher_count ?? null,
|
|
attachCount: u.attachmentCount ?? u.attachment_count ?? null,
|
|
})),
|
|
})
|
|
} catch (err: unknown) {
|
|
if (err instanceof Error && err.message.includes('login failed')) vwCookie = null
|
|
const msg = err instanceof Error ? err.message : 'Unknown error'
|
|
res.status(500).json({ error: msg })
|
|
}
|
|
})
|
|
|
|
export default router
|