mirror of
https://github.com/UNITRONIX/BetterDesk.git
synced 2026-09-11 01:55:43 +00:00
43e0b6f40a
Expose global connection strategy in the web panel with systemd/Docker persistence, extend server health diagnostics, enforce org network policy in the signal handler, and document when relay fallback is expected vs misconfiguration.
216 lines
14 KiB
HTML
216 lines
14 KiB
HTML
<%- include('layouts/main', {
|
|
title: _('policies.title') || 'Organization Policies',
|
|
pageStyles: ['policies'],
|
|
pageScripts: ['policies'],
|
|
currentPage: 'policies',
|
|
breadcrumb: [{ label: _('policies.title') || 'Organization Policies' }],
|
|
body: `
|
|
<div class="policy-page">
|
|
<!-- Header -->
|
|
<div class="policy-header">
|
|
<div class="policy-title">
|
|
<h1>${_('policies.title') || 'Organization Policies'}</h1>
|
|
<p class="policy-subtitle">${_('policies.subtitle') || 'Manage security, connection, and feature policies for your organizations'}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Organization selector -->
|
|
<div class="policy-org-selector">
|
|
<label>${_('policies.select_org') || 'Organization'}</label>
|
|
<select id="policy-org-select" class="form-input">
|
|
<option value="">${_('policies.select_org_placeholder') || 'Select an organization...'}</option>
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Policy sections (hidden until org selected) -->
|
|
<div class="policy-sections" id="policy-sections" style="display:none;">
|
|
<!-- Connection Policy -->
|
|
<div class="policy-card" data-section="connection">
|
|
<div class="policy-card-header">
|
|
<div class="policy-card-icon"><span class="material-icons">settings_remote</span></div>
|
|
<div class="policy-card-info">
|
|
<h3>${_('policies.connection_title') || 'Connection Policy'}</h3>
|
|
<p>${_('policies.connection_desc') || 'Control how remote sessions are established'}</p>
|
|
</div>
|
|
<span class="policy-status-badge" id="conn-status">—</span>
|
|
</div>
|
|
<div class="policy-card-body">
|
|
<div class="policy-field">
|
|
<label>${_('policies.connection_mode') || 'Connection Mode'}</label>
|
|
<select id="pol-connection-mode" class="form-input">
|
|
<option value="attended">${_('policies.mode_attended') || 'Attended (requires user approval)'}</option>
|
|
<option value="unattended">${_('policies.mode_unattended') || 'Unattended (always allow)'}</option>
|
|
<option value="ask_always">${_('policies.mode_ask') || 'Always Ask'}</option>
|
|
</select>
|
|
</div>
|
|
<div class="policy-field">
|
|
<label>${_('policies.max_session') || 'Max Session Duration (minutes)'}</label>
|
|
<input type="number" id="pol-max-session" class="form-input" min="0" max="1440" value="480" />
|
|
</div>
|
|
<div class="policy-field">
|
|
<label>${_('policies.idle_lock') || 'Idle Lock Timeout (minutes)'}</label>
|
|
<input type="number" id="pol-idle-lock" class="form-input" min="0" max="120" value="15" />
|
|
</div>
|
|
<div class="policy-field">
|
|
<label>${_('policies.wallpaper_policy') || 'Wallpaper During Session'}</label>
|
|
<select id="pol-wallpaper" class="form-input">
|
|
<option value="show">${_('policies.wallpaper_show') || 'Show'}</option>
|
|
<option value="hide_during_session">${_('policies.wallpaper_hide_session') || 'Hide during session'}</option>
|
|
<option value="hide_always">${_('policies.wallpaper_hide_always') || 'Always hide'}</option>
|
|
</select>
|
|
</div>
|
|
<button class="btn btn-primary btn-sm" onclick="Policies.saveSection('connection')">${_('common.save') || 'Save'}</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Feature Policy -->
|
|
<div class="policy-card" data-section="features">
|
|
<div class="policy-card-header">
|
|
<div class="policy-card-icon"><span class="material-icons">extension</span></div>
|
|
<div class="policy-card-info">
|
|
<h3>${_('policies.features_title') || 'Feature Policy'}</h3>
|
|
<p>${_('policies.features_desc') || 'Enable or disable specific features for devices'}</p>
|
|
</div>
|
|
<span class="policy-status-badge" id="feat-status">—</span>
|
|
</div>
|
|
<div class="policy-card-body">
|
|
<div class="policy-toggle-group">
|
|
<div class="policy-toggle">
|
|
<label>${_('policies.allow_file_transfer') || 'Allow File Transfer'}</label>
|
|
<input type="checkbox" id="pol-file-transfer" class="toggle-switch" checked />
|
|
</div>
|
|
<div class="policy-toggle">
|
|
<label>${_('policies.allow_clipboard') || 'Allow Clipboard Sync'}</label>
|
|
<input type="checkbox" id="pol-clipboard" class="toggle-switch" checked />
|
|
</div>
|
|
<div class="policy-toggle">
|
|
<label>${_('policies.allow_audio') || 'Allow Audio Streaming'}</label>
|
|
<input type="checkbox" id="pol-audio" class="toggle-switch" />
|
|
</div>
|
|
<div class="policy-toggle">
|
|
<label>${_('policies.allow_recording') || 'Allow Session Recording'}</label>
|
|
<input type="checkbox" id="pol-recording" class="toggle-switch" checked />
|
|
</div>
|
|
</div>
|
|
<button class="btn btn-primary btn-sm" onclick="Policies.saveSection('features')">${_('common.save') || 'Save'}</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Security Policy -->
|
|
<div class="policy-card" data-section="security">
|
|
<div class="policy-card-header">
|
|
<div class="policy-card-icon"><span class="material-icons">shield</span></div>
|
|
<div class="policy-card-info">
|
|
<h3>${_('policies.security_title') || 'Security Policy'}</h3>
|
|
<p>${_('policies.security_desc') || 'Enforce security requirements for organization devices'}</p>
|
|
</div>
|
|
<span class="policy-status-badge" id="sec-status">—</span>
|
|
</div>
|
|
<div class="policy-card-body">
|
|
<div class="policy-toggle-group">
|
|
<div class="policy-toggle">
|
|
<label>${_('policies.require_2fa') || 'Require 2FA for Unattended Access'}</label>
|
|
<input type="checkbox" id="pol-require-2fa" class="toggle-switch" checked />
|
|
</div>
|
|
</div>
|
|
<div class="policy-field">
|
|
<label>${_('policies.password_min_length') || 'Minimum Password Length'}</label>
|
|
<input type="number" id="pol-pass-min" class="form-input" min="6" max="128" value="12" />
|
|
</div>
|
|
<div class="policy-toggle-group">
|
|
<div class="policy-toggle">
|
|
<label>${_('policies.password_require_special') || 'Require Special Characters'}</label>
|
|
<input type="checkbox" id="pol-pass-special" class="toggle-switch" checked />
|
|
</div>
|
|
</div>
|
|
<div class="policy-field">
|
|
<label>${_('policies.password_max_age') || 'Password Max Age (days, 0=never)'}</label>
|
|
<input type="number" id="pol-pass-age" class="form-input" min="0" max="365" value="90" />
|
|
</div>
|
|
<div class="policy-field">
|
|
<label>${_('policies.allowed_operators') || 'Allowed Operator Roles (comma-separated)'}</label>
|
|
<input type="text" id="pol-allowed-ops" class="form-input" placeholder="admin, helpdesk" />
|
|
</div>
|
|
<button class="btn btn-primary btn-sm" onclick="Policies.saveSection('security')">${_('common.save') || 'Save'}</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Network Policy -->
|
|
<div class="policy-card" data-section="network">
|
|
<div class="policy-card-header">
|
|
<div class="policy-card-icon"><span class="material-icons">lan</span></div>
|
|
<div class="policy-card-info">
|
|
<h3>${_('policies.network_title') || 'Network Policy'}</h3>
|
|
<p>${_('policies.network_desc') || 'Control relay servers and direct connections'}</p>
|
|
</div>
|
|
<span class="policy-status-badge" id="net-status">—</span>
|
|
</div>
|
|
<div class="policy-card-body">
|
|
<div class="policy-toggle-group">
|
|
<div class="policy-toggle">
|
|
<label>${_('policies.block_direct_p2p') || 'Block Direct P2P (force relay)'}</label>
|
|
<input type="checkbox" id="pol-block-p2p" class="toggle-switch" />
|
|
</div>
|
|
<p class="text-muted policy-hint">${_('policies.block_direct_p2p_hint') || 'Applies to devices in this organization. Global default is configured under Settings → Connection strategy.'}</p>
|
|
</div>
|
|
<div class="policy-field">
|
|
<label>${_('policies.allowed_relays') || 'Allowed Relay Servers (one per line)'}</label>
|
|
<textarea id="pol-relay-servers" class="form-input" rows="3" placeholder="relay1.example.com:21117"></textarea>
|
|
</div>
|
|
<div class="policy-field">
|
|
<label>${_('policies.ip_allowlist') || 'IP Allowlist (CIDR, one per line)'}</label>
|
|
<textarea id="pol-ip-allowlist" class="form-input" rows="3" placeholder="192.168.1.0/24\n10.0.0.0/8"></textarea>
|
|
</div>
|
|
<button class="btn btn-primary btn-sm" onclick="Policies.saveSection('network')">${_('common.save') || 'Save'}</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Update Policy -->
|
|
<div class="policy-card" data-section="update">
|
|
<div class="policy-card-header">
|
|
<div class="policy-card-icon"><span class="material-icons">system_update</span></div>
|
|
<div class="policy-card-info">
|
|
<h3>${_('policies.update_title') || 'Update Policy'}</h3>
|
|
<p>${_('policies.update_desc') || 'Control automatic updates and update channels'}</p>
|
|
</div>
|
|
<span class="policy-status-badge" id="upd-status">—</span>
|
|
</div>
|
|
<div class="policy-card-body">
|
|
<div class="policy-toggle-group">
|
|
<div class="policy-toggle">
|
|
<label>${_('policies.auto_update') || 'Enable Auto-Update'}</label>
|
|
<input type="checkbox" id="pol-auto-update" class="toggle-switch" checked />
|
|
</div>
|
|
</div>
|
|
<div class="policy-field">
|
|
<label>${_('policies.update_channel') || 'Update Channel'}</label>
|
|
<select id="pol-update-channel" class="form-input">
|
|
<option value="stable">Stable</option>
|
|
<option value="beta">Beta</option>
|
|
<option value="dev">Dev</option>
|
|
</select>
|
|
</div>
|
|
<button class="btn btn-primary btn-sm" onclick="Policies.saveSection('update')">${_('common.save') || 'Save'}</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Policy Audit Log -->
|
|
<div class="policy-card" data-section="audit">
|
|
<div class="policy-card-header">
|
|
<div class="policy-card-icon"><span class="material-icons">history</span></div>
|
|
<div class="policy-card-info">
|
|
<h3>${_('policies.audit_title') || 'Policy Changes'}</h3>
|
|
<p>${_('policies.audit_desc') || 'Recent policy change history'}</p>
|
|
</div>
|
|
</div>
|
|
<div class="policy-card-body">
|
|
<div id="policy-audit-list" class="policy-audit-list">
|
|
<p class="text-muted">${_('policies.select_org_first') || 'Select an organization to view policy audit log.'}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`
|
|
}) %>
|