syco.me Homelab Dashboard
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
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
|
||||
Reference in New Issue
Block a user