Files
BetterDesk/web-nodejs/views/dataguard.ejs
T
UNITRONIX bbf839754e Harden bd-mgmt, API key, and WS security
Add multiple security hardenings across the server and web console: enforce proof-of-possession for /ws/bd-mgmt using Ed25519-signed headers with timestamp/nonce and replay protection (public key binding, canonicalization, storage, verification, and tests); remove legacy API key query param and config-table fallback in favor of scoped api_keys (migrate bootstrap key into api_keys); tighten WebSocket origin handling for relay and signal servers to allow only localhost origins by default unless an explicit allowlist is set; update auth middleware public paths and test helpers to use X-API-Key header; add ensureScopedAPIKey migration and related helpers; add a GitHub Secret Scan workflow and an audit report. Misc: propagate audit logging on bd-mgmt connect/disconnect and validate enrollment public keys during device register.
2026-03-29 01:48:14 +01:00

164 lines
7.5 KiB
HTML

<%- include('layouts/main', {
title: typeof title !== 'undefined' ? title : 'DataGuard',
pageStyles: ['dataguard'],
pageScripts: ['dataguard'],
currentPage: 'dataguard',
breadcrumb: [{ label: _('nav.system') }, { label: _('dataguard.title') }],
body: `
<div class="page-header">
<h1>${_('dataguard.title')}</h1>
</div>
<!-- Stats -->
<div class="stat-cards">
<div class="stat-card">
<div class="stat-icon"><span class="material-icons">policy</span></div>
<div class="stat-info">
<span class="stat-value" id="stat-policies">0</span>
<span class="stat-label">${_('dataguard.total_policies')}</span>
</div>
</div>
<div class="stat-card">
<div class="stat-icon online"><span class="material-icons">check_circle</span></div>
<div class="stat-info">
<span class="stat-value" id="stat-active">0</span>
<span class="stat-label">${_('dataguard.active_policies')}</span>
</div>
</div>
<div class="stat-card">
<div class="stat-icon offline"><span class="material-icons">warning</span></div>
<div class="stat-info">
<span class="stat-value" id="stat-violations">0</span>
<span class="stat-label">${_('dataguard.violations')}</span>
</div>
</div>
<div class="stat-card">
<div class="stat-icon"><span class="material-icons">block</span></div>
<div class="stat-info">
<span class="stat-value" id="stat-blocked">0</span>
<span class="stat-label">${_('dataguard.blocked')}</span>
</div>
</div>
</div>
<!-- Tab bar -->
<div class="tab-bar">
<button class="tab-btn active" data-tab="policies">${_('dataguard.tab_policies')}</button>
<button class="tab-btn" data-tab="events">${_('dataguard.tab_events')}</button>
</div>
<!-- Policies panel -->
<div class="tab-panel active" id="tab-policies">
<div class="panel-actions">
<div class="search-wrapper">
<span class="material-icons">search</span>
<input type="text" id="policy-search" placeholder="${_('dataguard.search_policies')}" />
</div>
<button class="btn btn-primary" id="create-policy-btn">
<span class="material-icons">add</span> ${_('dataguard.create_policy')}
</button>
</div>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>${_('dataguard.policy_name')}</th>
<th>${_('dataguard.policy_type')}</th>
<th>${_('dataguard.action')}</th>
<th>${_('dataguard.scope')}</th>
<th>${_('dataguard.status')}</th>
<th>${_('dataguard.events_count')}</th>
<th>${_('common.actions')}</th>
</tr>
</thead>
<tbody id="policies-body"></tbody>
</table>
</div>
</div>
<!-- Events panel -->
<div class="tab-panel" id="tab-events">
<div class="panel-actions">
<div class="search-wrapper">
<span class="material-icons">search</span>
<input type="text" id="event-search" placeholder="${_('dataguard.search_events')}" />
</div>
<div class="filter-buttons" id="event-action-filter">
<button class="filter-btn active" data-action="">${_('common.all')}</button>
<button class="filter-btn" data-action="block">${_('dataguard.action_block')}</button>
<button class="filter-btn" data-action="log">${_('dataguard.action_log')}</button>
<button class="filter-btn" data-action="allow">${_('dataguard.action_allow')}</button>
</div>
</div>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>${_('dataguard.event_time')}</th>
<th>${_('dataguard.device')}</th>
<th>${_('dataguard.policy')}</th>
<th>${_('dataguard.action')}</th>
<th>${_('dataguard.detail')}</th>
</tr>
</thead>
<tbody id="events-body"></tbody>
</table>
</div>
</div>
<!-- Policy modal -->
<div class="modal-overlay" id="policy-modal" style="display:none">
<div class="modal">
<div class="modal-header">
<h2 id="policy-modal-title">${_('dataguard.create_policy')}</h2>
<button class="modal-close" data-modal="policy-modal"><span class="material-icons">close</span></button>
</div>
<div class="modal-body">
<input type="hidden" id="policy-id" />
<div class="form-row">
<label for="policy-name">${_('dataguard.policy_name')}</label>
<input type="text" id="policy-name" />
</div>
<div class="form-row">
<label for="policy-desc">${_('dataguard.policy_desc')}</label>
<textarea id="policy-desc" rows="2"></textarea>
</div>
<div class="form-row">
<label for="policy-type">${_('dataguard.policy_type')}</label>
<select id="policy-type">
<option value="usb">${_('dataguard.type_usb')}</option>
<option value="file_type">${_('dataguard.type_file_type')}</option>
<option value="clipboard">${_('dataguard.type_clipboard')}</option>
<option value="screen_share">${_('dataguard.type_screen_share')}</option>
<option value="file_transfer">${_('dataguard.type_file_transfer')}</option>
</select>
</div>
<div class="form-row">
<label for="policy-action">${_('dataguard.action')}</label>
<select id="policy-action">
<option value="allow">${_('dataguard.action_allow')}</option>
<option value="log">${_('dataguard.action_log')}</option>
<option value="block">${_('dataguard.action_block')}</option>
</select>
</div>
<div class="form-row">
<label for="policy-scope">${_('dataguard.scope')}</label>
<input type="text" id="policy-scope" placeholder="${_('dataguard.scope_help')}" />
</div>
<div class="form-row">
<label for="policy-rules">${_('dataguard.rules')}</label>
<textarea id="policy-rules" rows="3" placeholder='[{"key":"file_ext","value":".exe,.bat"}]'></textarea>
</div>
<div class="form-row">
<label><input type="checkbox" id="policy-enabled" checked /> ${_('dataguard.enabled')}</label>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" id="policy-cancel-btn">${_('common.cancel')}</button>
<button class="btn btn-primary" id="policy-save-btn">${_('common.save')}</button>
</div>
</div>
</div>
`
}) %>