Diff -- /var/www/vhosts/3dshawn.com/site1/TEMPLATES/servers.html

O Operator
Diff

/var/www/vhosts/3dshawn.com/site1/TEMPLATES/servers.html

modified on local at 2026-07-12 00:35:29

Added
+8
lines
Removed
-0
lines
Context
278
unchanged
Blobs
from b85517f9ee2e
to 66b67331501d
Restore this content →
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.
11<div class="page-head">
22 <span class="page-eyebrow"><span class="dot"></span> Configure</span>
33 <h1 class="page-title">Servers &amp; agents</h1>
44 <p class="page-subtitle">The nodes DriftSense knows about &mdash; local (this box) and SSH agents (remote servers scanned over a restricted-key SSH connection). Add one at a time or bulk-import a list of hostnames sharing a single key.</p>
5</div>
6
7<div class="ds-guide">
8 <div class="dsg-icon">i</div>
9 <div>
10 <span class="dsg-title">Two flavors:</span>
11 <strong>Local</strong> = scanner runs on the same box as the file being watched (fast, zero-network). <strong>SSH agent</strong> = scanner SSHes into the target box using a restricted key; only footprint on that box is one <code>authorized_keys</code> entry. Great for <em>stealth deployment</em> where you don't want developers on the monitored box to see DriftSense installed. Paste a PEM key below to store it <span class="ds-help" data-help-title="Encrypted at rest" data-help-body="PEM keys pasted here are encrypted with an HMAC-SHA-256 CTR construction using a per-install master key at <code>/etc/drift_sense/master.key</code> (mode 0640, group psacln). Neither the DB nor a filesystem snapshot exposes plaintext keys."></span> in the DB (encrypted). Test any row with the "Test" button.
12 </div>
513</div>
614
715[if:$has_imported]
816<div class="banner banner-ok" style="margin:0 0 16px;padding:10px 14px;border-radius:10px;background:rgba(52,211,153,.10);border:1px solid rgba(52,211,153,.35);color:#a7f3d0;font-size:13px">
917 Bulk import created $imported server(s). They'll be scanned on the next agent tick (within 5 minutes).
1018</div>
1119[/if]
1220
1321[if:!$crypto_ready]
1422<div class="banner banner-warn" style="margin:0 0 16px;padding:10px 14px;border-radius:10px;background:rgba(245,158,11,.10);border:1px solid rgba(245,158,11,.35);color:#fcd34d;font-size:13px">
1523 <strong>Master encryption key missing.</strong> Encrypted key storage requires <code>/etc/drift_sense/master.key</code>. Run on the server: <code>sudo perl -e 'use lib "/var/www/vhosts/3dshawn.com/site1"; use MODS::Crypto; MODS::Crypto::ensure_master()'</code>. Until then, encrypted-blob storage is unavailable and only on-disk <code>ssh_key_path</code> works.
1624</div>
1725[/if]
1826
1927<!-- ============================ TOP TABS ============================ -->
2028<div style="display:flex;gap:8px;margin-bottom:16px">
2129 <a class="tr-chip[if:!$bulk_mode] is-active[/if]" href="/servers.cgi">Single-server form</a>
2230 <a class="tr-chip[if:$bulk_mode] is-active[/if]" href="/servers.cgi?bulk=1">Bulk import</a>
2331</div>
2432
2533<div class="dash-grid" style="grid-template-columns:1fr 1fr;margin-bottom:20px">
2634 <!-- ============================ SINGLE-SERVER FORM ============================ -->
2735 [if:!$bulk_mode]
2836 <div class="module glow-teal">
2937 <div class="module-head"><div class="left">
3038 <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="2" width="20" height="8" rx="2"/><rect x="2" y="14" width="20" height="8" rx="2"/></svg></div>
3139 <div class="module-title">[if:$is_edit]Edit server #$server_id[/if][if:!$is_edit]Add server[/if]</div>
3240 <span class="module-subtitle">Pick <code>local</code> for the DriftSense host itself, or <code>ssh_agent</code> for anything remote.</span>
3341 </div></div>
3442 <div class="module-body">
3543 <form method="post" action="/servers.cgi" style="display:flex;flex-direction:column;gap:12px">
3644 <input type="hidden" name="op" value="$form_op">
3745 [if:$is_edit]<input type="hidden" name="server_id" value="$server_id">[/if]
3846
3947 <div style="display:flex;gap:12px">
4048 <label style="flex:2;display:flex;flex-direction:column;gap:4px">
4149 <span class="rb-label">Server name</span>
4250 <input type="text" name="server_name" value="$server_name" required placeholder="e.g. prod-web-1"
4351 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-family:inherit">
4452 </label>
4553 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
4654 <span class="rb-label">Kind</span>
4755 <select name="kind" style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px">
4856 <option value="local" $k_local_sel>local</option>
4957 <option value="ssh_agent" $k_ssh_sel>ssh_agent</option>
5058 </select>
5159 </label>
5260 </div>
5361
5462 <div style="display:flex;gap:12px">
5563 <label style="flex:2;display:flex;flex-direction:column;gap:4px">
5664 <span class="rb-label">SSH host</span>
5765 <input type="text" name="ssh_host" value="$ssh_host" placeholder="e.g. prod-web-1.internal or 10.0.0.42"
5866 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-family:var(--mono);font-size:12px">
5967 </label>
6068 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
6169 <span class="rb-label">User</span>
6270 <input type="text" name="ssh_user" value="$ssh_user"
6371 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-family:var(--mono);font-size:12px">
6472 </label>
6573 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
6674 <span class="rb-label">Port</span>
6775 <input type="number" name="ssh_port" value="$ssh_port" min="1" max="65535"
6876 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px">
6977 </label>
7078 </div>
7179
7280 <label style="display:flex;flex-direction:column;gap:4px">
7381 <span class="rb-label">SSH key path <span class="dim" style="text-transform:none;letter-spacing:0;font-size:10.5px">(on-disk fallback if you don't paste a key below)</span></span>
7482 <input type="text" name="ssh_key_path" value="$ssh_key_path" placeholder="/etc/drift_sense/keys/agent_key"
7583 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-family:var(--mono);font-size:12px">
7684 </label>
7785
7886 <label style="display:flex;flex-direction:column;gap:4px">
7987 <span class="rb-label">
8088 Paste PEM key (encrypted at rest with master key)
8189 [if:$has_key_blob]<span class="pill" style="background:rgba(52,211,153,.14);color:#86efac;border-color:rgba(52,211,153,.35);margin-left:6px">key already stored</span>[/if]
8290 </span>
8391 <textarea name="ssh_key_blob_plain" rows="4" placeholder="-----BEGIN OPENSSH PRIVATE KEY-----&#10;...&#10;-----END OPENSSH PRIVATE KEY-----"
8492 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:10px 12px;font-family:var(--mono);font-size:11.5px;resize:vertical"></textarea>
8593 </label>
8694
8795 <label style="display:flex;flex-direction:column;gap:4px">
8896 <span class="rb-label">Extra SSH options <span class="dim" style="text-transform:none;letter-spacing:0;font-size:10.5px">(optional, space-separated <code>-o key=value</code> pairs)</span></span>
8997 <input type="text" name="ssh_options" value="$ssh_options" placeholder="e.g. IdentitiesOnly=yes ProxyJump=bastion.internal"
9098 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-family:var(--mono);font-size:11.5px">
9199 </label>
92100
93101 <div style="display:flex;gap:8px;justify-content:flex-end;margin-top:6px">
94102 [if:$is_edit]<a href="/servers.cgi" class="tr-chip">Cancel</a>[/if]
95103 <button type="submit" class="tr-chip is-active" style="border:none">[if:$is_edit]Save[/if][if:!$is_edit]Add server[/if]</button>
96104 </div>
97105 </form>
98106 </div>
99107 </div>
100108 [/if]
101109
102110 <!-- ============================ BULK IMPORT ============================ -->
103111 [if:$bulk_mode]
104112 <div class="module glow-emerald" style="grid-column:1 / span 2">
105113 <div class="module-head"><div class="left">
106114 <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg></div>
107115 <div class="module-title">Bulk import</div>
108116 <span class="module-subtitle">Paste one hostname per line + one shared SSH key + a base scan config. DriftSense fans out.</span>
109117 </div></div>
110118 <div class="module-body">
111119 <form method="post" action="/servers.cgi" style="display:flex;flex-direction:column;gap:14px">
112120 <input type="hidden" name="op" value="bulk_import">
113121
114122 <label style="display:flex;flex-direction:column;gap:4px">
115123 <span class="rb-label">Hostnames &mdash; one per line, optional <code>label|host</code> or <code>label=host</code> format</span>
116124 <textarea name="hosts" rows="7" placeholder="prod-web-1.internal&#10;prod-web-2 = 10.0.0.11&#10;webstls | webstls.com&#10;staging | staging.internal"
117125 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:10px 12px;font-family:var(--mono);font-size:12.5px;resize:vertical" required></textarea>
118126 </label>
119127
120128 <div style="display:flex;gap:12px">
121129 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
122130 <span class="rb-label">User</span>
123131 <input type="text" name="ssh_user" value="root"
124132 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-family:var(--mono);font-size:12px">
125133 </label>
126134 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
127135 <span class="rb-label">Port</span>
128136 <input type="number" name="ssh_port" value="22"
129137 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px">
130138 </label>
131139 </div>
132140
133141 <label style="display:flex;flex-direction:column;gap:4px">
134142 <span class="rb-label">Shared PEM key (encrypted at rest) &mdash; optional if all hosts use <code>ssh_key_path</code></span>
135143 <textarea name="ssh_key_blob_plain" rows="4" placeholder="-----BEGIN OPENSSH PRIVATE KEY-----&#10;...&#10;-----END OPENSSH PRIVATE KEY-----"
136144 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:10px 12px;font-family:var(--mono);font-size:11.5px;resize:vertical"></textarea>
137145 </label>
138146
139147 <hr style="border:none;border-top:1px solid var(--border);margin:4px 0">
140148
141149 <div class="rb-label" style="margin-bottom:-6px">Base scan config &mdash; applied to every host</div>
142150
143151 <label style="display:flex;flex-direction:column;gap:4px">
144152 <span class="rb-label">Scan path</span>
145153 <input type="text" name="scan_path" value="/etc" placeholder="/etc or /var/www"
146154 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-family:var(--mono);font-size:12px" required>
147155 </label>
148156
149157 <div style="display:flex;gap:12px">
150158 <label style="flex:2;display:flex;flex-direction:column;gap:4px">
151159 <span class="rb-label">Ignore globs (comma-separated)</span>
152160 <input type="text" name="ignore_list" value="*.log,*.pid,*.sock,*.tmp,tmp/*,cache/*,logs/*,.git/*,node_modules/*"
153161 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-family:var(--mono);font-size:11.5px">
154162 </label>
155163 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
156164 <span class="rb-label">File-type filter <span class="dim" style="text-transform:none;letter-spacing:0;font-size:10.5px">(blank = all)</span></span>
157165 <input type="text" name="file_type_filter" value="" placeholder="cgi,pl,pm,html,css,js,md,sql,conf"
158166 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-family:var(--mono);font-size:11.5px">
159167 </label>
160168 </div>
161169
162170 <div style="display:flex;gap:8px;justify-content:flex-end;margin-top:6px">
163171 <a href="/servers.cgi" class="tr-chip">Cancel</a>
164172 <button type="submit" class="tr-chip is-active" style="border:none">Import all</button>
165173 </div>
166174 </form>
167175 </div>
168176 </div>
169177 [/if]
170178
171179 <!-- ============================ QUICK HELP CARD ============================ -->
172180 [if:!$bulk_mode]
173181 <div class="module glow-sky">
174182 <div class="module-head"><div class="left">
175183 <div class="module-title">Quick help</div>
176184 <span class="module-subtitle">The three most common setup shapes.</span>
177185 </div></div>
178186 <div class="module-body" style="font-size:13.5px;color:var(--text-dim);line-height:1.75">
179187 <p style="margin-bottom:10px"><strong style="color:var(--text)">Same server</strong> &mdash; pick <code>local</code>, skip all the SSH fields. This is the default install monitoring itself.</p>
180188 <p style="margin-bottom:10px"><strong style="color:var(--text)">Remote via SSH</strong> &mdash; pick <code>ssh_agent</code>, fill <code>ssh_host</code> + <code>ssh_user</code>, and either paste the PEM key below (encrypted at rest with the master key) OR give a path to a keyfile on disk.</p>
181189 <p style="margin-bottom:10px"><strong style="color:var(--text)">Test the connection</strong> &mdash; after saving, hit the "Test" button on the server row. Runs an SSH probe and reports back inline.</p>
182190 <p><strong style="color:var(--text)">Bulk import 20 hosts at once</strong> &mdash; switch to the "Bulk import" tab. Paste hostnames, one shared key, one base scan config. DriftSense fans out and starts scanning within 5 minutes.</p>
183191 </div>
184192 </div>
185193 [/if]
186194</div>
187195
188196<!-- ============================ SERVER LIST ============================ -->
189197<div class="module glow-sky">
190198 <div class="module-head"><div class="left">
191199 <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="2" width="20" height="8" rx="2"/><rect x="2" y="14" width="20" height="8" rx="2"/></svg></div>
192200 <div class="module-title">Registered servers</div>
193201 <span class="module-subtitle">$total total.</span>
194202 </div></div>
195203 <div class="module-body tight">
196204 [if:$has_rows]
197205 <table class="tbl">
198206 <thead><tr>
199207 <th style="width:140px">Kind / status</th>
200208 <th>Name</th>
201209 <th style="width:180px">Reach</th>
202210 <th style="width:130px">Key</th>
203211 <th style="width:150px">Last scan</th>
204212 <th style="width:220px">Actions</th>
205213 </tr></thead>
206214 <tbody>
207215 [loop:@rows]
208216 <tr>
209217 <td>
210218 <span class="pill $kind_pill">$kind</span>
211219 <span class="pill $status_pill" style="margin-left:4px">$status</span>
212220 </td>
213221 <td>
214222 <a href="$edit_url" style="color:var(--accent-hi);text-decoration:none"><strong>$server_name</strong></a>
215223 [if:$err_short]<div class="dim" style="font-size:11px;color:var(--accent-danger)">$err_short</div>[/if]
216224 </td>
217225 <td class="mono dim" style="font-size:12px">$ssh_user@$host_display:$ssh_port</td>
218226 <td class="mono dim" style="font-size:11.5px">$key_display</td>
219227 <td class="mono dim"><span class="ts" data-ts="$last_scan_epoch" data-fmt="relative">$last_scan_h</span></td>
220228 <td>
221229 <button type="button" class="tr-chip" onclick="dsTestConn($server_id, this)">Test</button>
222230 <a href="$edit_url" class="tr-chip">Edit</a>
223231 <form method="post" action="/servers.cgi" style="display:inline" onsubmit="return confirm('Disable this server?')">
224232 <input type="hidden" name="op" value="delete">
225233 <input type="hidden" name="server_id" value="$server_id">
226234 <button type="submit" class="tr-chip" title="Disable">&times;</button>
227235 </form>
228236 </td>
229237 </tr>
230238 [/loop]
231239 </tbody>
232240 </table>
233241 [/if]
234242 [if:!$has_rows]
235243 <div style="padding:36px 14px;text-align:center;color:var(--text-dim);font-size:13.5px">
236244 No servers registered. Use the form above to add one, or switch to Bulk Import.
237245 </div>
238246 [/if]
239247 </div>
240248</div>
241249
242250<script>
243251(function () {
244252 window.dsTestConn = async function (id, btn) {
245253 var orig = btn.textContent;
246254 btn.textContent = 'Testing...';
247255 btn.disabled = true;
248256 try {
249257 var r = await fetch('/servers.cgi?op=test&id=' + id + '&nc=' + Date.now(), { cache: 'no-store' });
250258 var j = await r.json();
251259 if (j.ok) {
252260 btn.textContent = 'OK';
253261 btn.style.background = '#34d399';
254262 btn.style.color = '#0a1220';
255263 btn.style.borderColor = '#34d399';
256264 alert('SSH probe OK\n\n' + (j.message || ''));
257265 } else {
258266 btn.textContent = 'FAIL';
259267 btn.style.background = '#f43f5e';
260268 btn.style.color = '#fff';
261269 btn.style.borderColor = '#f43f5e';
262270 alert('SSH probe failed\n\n' + (j.message || 'unknown error'));
263271 }
264272 } catch (e) {
265273 alert('Probe error: ' + e.message);
266274 btn.textContent = orig;
267275 } finally {
268276 setTimeout(function () {
269277 btn.disabled = false;
270278 btn.textContent = orig;
271279 btn.style.background = '';
272280 btn.style.color = '';
273281 btn.style.borderColor = '';
274282 }, 3500);
275283 }
276284 };
277285})();
278286</script>