Files
reflector-dashboard/auth/admin_nodeauth.php
T
bjorneandClaude Fable 5.1 25b481e2ae Public web-only release: SvxPortal front-end + auth backend, install templates and INSTALL.md
Stripped from the internal repo: per-box deploy trees, Go services (nodelist/astmeta/proxy/svxdr),
deploy/sync scripts and all secrets. Config templates for nginx, PHP-FPM, Redis and tmpfiles
live in install/ with CHANGEME placeholders.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-26 23:07:05 +02:00

119 lines
6.3 KiB
PHP

<?php
declare(strict_types=1);
require __DIR__ . '/lib.php';
start_session();
$uuid = $_SESSION['uid'] ?? null;
if (!is_string($uuid) || $uuid === '') { header('Location: /'); exit; }
$me = acct_get($uuid);
$lvl = acct_admin_level($uuid);
if ($lvl < 2) { header('Location: /'); exit; }
$page_title = 'Admin · Node Auth — SvxPortal';
require __DIR__ . '/header.php';
?>
<div class="container py-4" style="max-width:900px;">
<!-- Node list -->
<div id="naListPanel">
<div class="panel">
<div class="d-flex justify-content-between align-items-center mb-3 gap-2 flex-wrap">
<h5 class="mb-0">Node Authentication</h5>
<button type="button" class="btn btn-primary btn-sm" id="naBtnShowAdd">+ Add node</button>
</div>
<div id="naMsg" class="small mb-2" style="display:none;"></div>
<div style="overflow-x:auto; -webkit-overflow-scrolling:touch;">
<table class="data-table" id="naTable" style="min-width:640px;">
<thead><tr><th>Callsign</th><th>Auth</th><th>Admins</th><th>Cert email</th><th>Valid to</th><th>Actions</th></tr></thead>
<tbody><tr><td colspan="6" class="text-secondary">Loading…</td></tr></tbody>
</table>
</div>
<div id="naStatus" class="text-secondary small mt-2"></div>
</div>
</div>
<!-- Add node -->
<div id="naAddPanel" style="display:none;">
<div class="d-flex justify-content-between align-items-center mb-3">
<h5 class="mb-0">Add node</h5>
<button type="button" class="btn btn-outline-secondary btn-sm" id="naBtnAddBack">Back to list</button>
</div>
<div class="panel">
<div class="small text-secondary mb-3">Login/password node. Cert nodes are added under <a href="/auth/admin_certs.php">Certificates</a> (linked by the certificate's email); their admins are managed from the node list.</div>
<label class="form-label small text-secondary mb-1" for="naNewNode">Login (node callsign, with -SSID)</label>
<input type="text" class="form-control form-control-sm mono mb-3" id="naNewNode" placeholder="SA7ABC-1" style="width:180px; text-transform:uppercase;">
<label class="form-label small text-secondary mb-1" for="naNewPw">Password</label>
<div class="d-flex gap-2 align-items-center flex-wrap mb-1">
<input type="text" class="form-control form-control-sm mono" id="naNewPw" style="width:240px;">
<button type="button" class="btn btn-outline-secondary btn-sm" id="naNewPwGen">Generate</button>
<button type="button" class="btn btn-outline-secondary btn-sm" id="naNewPwCopy">Copy</button>
</div>
<div class="small text-secondary mb-3">Auto-generated. Goes in the node's <span class="mono">AUTH_KEY</span>; the node's admins see it in clear text under their profile → Nodes.</div>
<label class="form-label small text-secondary">Node admins</label>
<div class="small text-secondary mb-2">Callsigns that may administer this node and see its password. The node's own callsign always counts; add others here.</div>
<div class="d-flex gap-2 mb-2"><button type="button" class="btn btn-sm btn-outline-success" id="naAddAdmBtn">Add admin</button></div>
<div id="naAddAdmWrap" class="mb-3"></div>
<button type="button" class="btn btn-primary btn-sm" id="naBtnAdd">Create node</button>
<div id="naAddMsg" class="small mt-2" style="display:none;"></div>
</div>
</div>
<!-- Edit node -->
<div id="naEditPanel" style="display:none;">
<div class="d-flex justify-content-between align-items-center mb-3">
<h5 class="mb-0">Edit: <span id="naEditCs" class="mono"></span></h5>
<button type="button" class="btn btn-outline-secondary btn-sm" id="naBtnBack">Back to list</button>
</div>
<div class="panel">
<div class="small mb-3"><span class="text-secondary">Auth:</span> <span id="naEditType"></span></div>
<label class="form-label small text-secondary">Linked account</label>
<div id="naEditAcct" class="small mb-3">Loading…</div>
<div id="naEditPwWrap" style="display:none;">
<label class="form-label small text-secondary">Password (goes in the node's <span class="mono">AUTH_KEY</span>)</label>
<div class="d-flex gap-2 align-items-center flex-wrap mb-1">
<input type="text" class="form-control form-control-sm mono" id="naEditPw" style="width:240px;">
<button type="button" class="btn btn-primary btn-sm" id="naBtnPwSave">Save</button>
<button type="button" class="btn btn-outline-secondary btn-sm" id="naBtnPwGen">Generate new</button>
<button type="button" class="btn btn-outline-secondary btn-sm" id="naBtnPwCopy">Copy</button>
</div>
<div id="naPwMsg" class="small mb-3" style="display:none;"></div>
</div>
<div id="naEditCertWrap" style="display:none;">
<label class="form-label small text-secondary">Certificate</label>
<div id="naEditCert" class="small mb-3"></div>
</div>
<label class="form-label small text-secondary">Node admins</label>
<div class="small text-secondary mb-2">Add a callsign to give them admin rights on this node. Each node has its own admins.</div>
<div id="naEditAdmins"></div>
</div>
</div>
</div>
<!-- One-time password modal (after Add) -->
<div class="modal fade" id="naPwModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content" style="background:#111; border:1px solid var(--line);">
<div class="modal-header" style="border-color:var(--line);">
<h5 class="modal-title" id="naPwTitle">Node password</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="small text-secondary mb-2">Copy this password into the node's <span class="mono">svxlink.conf</span> (<span class="mono">AUTH_KEY</span>). The node's owner and admins can also view it under profile → My Nodes.</div>
<div class="mono" id="naPwValue" style="font-size:1.1rem; word-break:break-all;"></div>
<button type="button" class="btn btn-sm btn-outline-secondary mt-2" id="naPwCopy">Copy</button>
</div>
</div>
</div>
</div>
<?php
$extra_scripts = '<script>var ADMIN_LEVEL = ' . $lvl . ';</script><script src="/auth/admin_nodeauth.js?v=' . @filemtime(__DIR__ . '/admin_nodeauth.js') . '"></script>';
require __DIR__ . '/footer.php';
?>