feat: implement Remote WinBox worker, API, frontend integration, OpenBao persistence, and supporting docs

This commit is contained in:
Jason Staack
2026-03-14 09:05:14 -05:00
parent 7af08276ea
commit 970501e453
86 changed files with 3440 additions and 3764 deletions

View File

@@ -968,6 +968,59 @@ export const remoteAccessApi = {
.then((r) => r.data),
}
// ─── Remote WinBox (Browser) ─────────────────────────────────────────────────
export interface RemoteWinBoxSession {
session_id: string
status: 'creating' | 'active' | 'grace' | 'terminating' | 'terminated' | 'failed'
websocket_path?: string
xpra_ws_port?: number
idle_timeout_seconds: number
max_lifetime_seconds: number
expires_at: string
max_expires_at: string
created_at?: string
}
export const remoteWinboxApi = {
create: (tenantId: string, deviceId: string, opts?: {
idle_timeout_seconds?: number
max_lifetime_seconds?: number
}) =>
api
.post<RemoteWinBoxSession>(
`/api/tenants/${tenantId}/devices/${deviceId}/winbox-remote-sessions`,
opts || {},
)
.then((r) => r.data),
get: (tenantId: string, deviceId: string, sessionId: string) =>
api
.get<RemoteWinBoxSession>(
`/api/tenants/${tenantId}/devices/${deviceId}/winbox-remote-sessions/${sessionId}`,
)
.then((r) => r.data),
list: (tenantId: string, deviceId: string) =>
api
.get<RemoteWinBoxSession[]>(
`/api/tenants/${tenantId}/devices/${deviceId}/winbox-remote-sessions`,
)
.then((r) => r.data),
delete: (tenantId: string, deviceId: string, sessionId: string) =>
api
.delete(
`/api/tenants/${tenantId}/devices/${deviceId}/winbox-remote-sessions/${sessionId}`,
)
.then((r) => r.data),
getWebSocketUrl: (sessionPath: string) => {
const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
return `${proto}//${window.location.host}${sessionPath}`
},
}
// ─── Config History ─────────────────────────────────────────────────────────
export interface ConfigChangeEntry {

View File

@@ -10,7 +10,7 @@
* - localStorage and sessionStorage are NEVER used for any key material.
*/
const DB_NAME = 'mikrotik-portal-keys';
const DB_NAME = 'the-other-dude-keys';
const DB_VERSION = 1;
const STORE_NAME = 'secret-keys';

View File

@@ -28,6 +28,11 @@ export async function updateSMTPSettings(data: {
await api.put('/api/settings/smtp', data)
}
export async function clearWinboxSessions(): Promise<{ status: string; deleted: number }> {
const res = await api.delete('/api/settings/winbox-sessions')
return res.data
}
export async function testSMTPSettings(data: {
to: string
smtp_host?: string