Let the setup checklist create the SSH key it is asking for, instead of linking to a guide

This commit is contained in:
Gmer4Lfe
2026-08-16 13:24:26 -04:00
parent 19ba1e723c
commit 64de77c065
+49 -2
View File
@@ -322,13 +322,17 @@ function vvRunPopulate() {
// ── Checklist ───────────────────────────────────────────────────────────────── // ── Checklist ─────────────────────────────────────────────────────────────────
const vvActionLabels = { const vvActionLabels = {
create_key: 'Create API key', create_key: 'Create API key',
ssh_setup: 'SSH guide →', ssh_setup: 'Generate SSH key',
run_populate: 'Run now', run_populate: 'Run now',
pull_master: 'Pull from HOST1', pull_master: 'Pull from HOST1',
onboard: 'Partnership tab →', onboard: 'Partnership tab →',
}; };
// ssh_setup used to be a link to the Partnership tab — a guide, on the one row where the reader
// has no key and therefore cannot do the thing the guide describes. It generates the key here
// now, through api/setup.php?action=ssh_generate, which already existed and had never been
// called from anywhere. The partner path needs this: 'Pull from HOST1' authenticates with the
// key this row creates, so sending someone away to read about it left the next row unusable.
const vvActionHref = { const vvActionHref = {
ssh_setup: '?tab=partnership',
onboard: '?tab=partnership', onboard: '?tab=partnership',
}; };
@@ -352,6 +356,9 @@ function vvLoadChecklist() {
act = `<div class="vv-cl-act"><button onclick="vvRunPopulateBtn(this)">${lbl}</button></div>`; act = `<div class="vv-cl-act"><button onclick="vvRunPopulateBtn(this)">${lbl}</button></div>`;
} else if (item.action === 'pull_master') { } else if (item.action === 'pull_master') {
act = `<div class="vv-cl-act"><button onclick="vvPullMaster(this)">${lbl}</button><div id="vv-pull-err" class="vv-cl-err"></div></div>`; act = `<div class="vv-cl-act"><button onclick="vvPullMaster(this)">${lbl}</button><div id="vv-pull-err" class="vv-cl-err"></div></div>`;
} else if (item.action === 'ssh_setup') {
act = `<div class="vv-cl-act"><button onclick="vvSshGenerate(this)">${lbl}</button>`
+ `<div id="vv-ssh-out" class="vv-cl-err"></div></div>`;
} }
} }
return `<div class="vv-cl-item"> return `<div class="vv-cl-item">
@@ -366,6 +373,46 @@ function vvLoadChecklist() {
}).catch(() => {}); }).catch(() => {});
} }
// ── SSH key ───────────────────────────────────────────────────────────────────
// Generates this node's keypair and shows the public half. Generating it is the easy part; the
// key is useless until the other host trusts it, and that is a step no button here can take —
// so the public key is put on screen, in something selectable, rather than described.
//
// A readonly textarea rather than a copy button: the clipboard API needs a secure context and
// Unraid is routinely reached over plain http on the LAN, where it is simply undefined.
function vvSshGenerate(btn) {
btn.disabled = true; btn.textContent = '⟳ Generating…';
const out = document.getElementById('vv-ssh-out');
if (out) { out.textContent = ''; out.style.color = ''; }
fetch('/plugins/varaverk/api/setup.php', {
method: 'POST', headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({action: 'ssh_generate'})
}).then(r => r.json()).then(d => {
if (d.ok && d.pubkey) {
btn.textContent = '✓ Created';
if (out) {
out.style.color = '#8a8a8a';
// Built as nodes, not innerHTML — the key and its comment come off the filesystem and
// land in the page either way, so there is no reason to send them through a parser.
const p = document.createElement('div');
p.textContent = 'Key created. It is not trusted until this public key is on the other '
+ 'host — append it to /root/.ssh/authorized_keys there:';
p.style.cssText = 'margin-bottom:6px;line-height:1.5;';
const ta = document.createElement('textarea');
ta.readOnly = true; ta.value = d.pubkey; ta.rows = 3;
ta.style.cssText = 'width:100%;font-family:monospace;font-size:10px;background:#111;'
+ 'color:#8a8a8a;border:1px solid #2a2a2a;border-radius:3px;padding:6px;';
ta.onclick = () => ta.select();
out.appendChild(p); out.appendChild(ta);
}
setTimeout(vvLoadChecklist, 800);
} else {
if (out) { out.style.color = '#ef5350'; out.textContent = d.error || 'Key generation failed'; }
btn.disabled = false; btn.textContent = 'Retry';
}
}).catch(() => { btn.disabled = false; btn.textContent = 'Retry'; });
}
function vvRunPopulateBtn(btn) { function vvRunPopulateBtn(btn) {
btn.disabled = true; btn.textContent = '…'; btn.disabled = true; btn.textContent = '…';
fetch('/plugins/varaverk/api/setup.php', { fetch('/plugins/varaverk/api/setup.php', {