mirror of
https://github.com/UNITRONIX/BetterDesk.git
synced 2026-09-10 17:45:42 +00:00
bbf839754e
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.
164 lines
7.5 KiB
HTML
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>
|
|
`
|
|
}) %>
|