feat: enroll panel proxyHeadersSeen chips on login/app
This commit is contained in:
parent
9ce87e8a20
commit
d026f7eeb4
2 changed files with 66 additions and 9 deletions
|
|
@ -249,10 +249,12 @@ function drawSecurity() {
|
|||
<div class="card sec-card" id="sec-device-cert">
|
||||
<h3>Device certificate (mTLS) <span class="pill off" id="sec-mtls-state">…</span></h3>
|
||||
<p class="muted" style="margin:0 0 0.5rem;font-size:13px" id="sec-mtls-note">Loading enroll status…</p>
|
||||
<p class="muted" style="margin:0 0 0.35rem;font-size:11px;font-family:ui-monospace,monospace" id="sec-mtls-updated" hidden></p>
|
||||
<div id="sec-mtls-proxy" style="display:none;flex-wrap:wrap;gap:0.3rem;margin:0 0 0.35rem"></div>
|
||||
<p class="muted" style="margin:0 0 0.35rem;font-size:12px" id="sec-mtls-mint" hidden></p>
|
||||
<p class="muted" style="margin:0;font-size:12px" id="sec-mtls-renew" hidden></p>
|
||||
<ol id="sec-mtls-next" class="muted" style="margin:0.55rem 0 0;padding-left:1.15rem;font-size:12px;line-height:1.45" hidden></ol>
|
||||
<p class="muted" style="margin:0.65rem 0 0;font-size:12px">Staff cookie only — never a customer xVerae- key. Cert mint/renew is reverse-proxy PKI (see ENROLL.md).</p>
|
||||
<p class="muted" style="margin:0.65rem 0 0;font-size:12px">Staff cookie only — never a customer xVerae- key. Cert mint/renew is reverse-proxy PKI (see ENROLL.md). Shows <span class="mono">updatedAt</span> + <span class="mono">proxyHeadersSeen</span> chips.</p>
|
||||
</div>`;
|
||||
const setupBtn = $('sec-totp-setup');
|
||||
if (setupBtn) setupBtn.onclick = () => runTotpSetup('sec-totp-setup-box');
|
||||
|
|
@ -277,12 +279,45 @@ function drawSecurity() {
|
|||
const mint = $('sec-mtls-mint');
|
||||
const renew = $('sec-mtls-renew');
|
||||
const next = $('sec-mtls-next');
|
||||
const updated = $('sec-mtls-updated');
|
||||
const proxyBox = $('sec-mtls-proxy');
|
||||
if (st) {
|
||||
st.textContent = s.stateLabel || s.state || 'Device cert';
|
||||
st.className = 'pill' + (s.state === 'enrolled' || s.state === 'enforce_on' ? '' : ' off');
|
||||
if (s.state === 'pending_proxy') st.className = 'pill warn';
|
||||
}
|
||||
if (note) note.textContent = s.note || '';
|
||||
if (updated) {
|
||||
if (typeof s.updatedAt === 'string' && s.updatedAt) {
|
||||
updated.hidden = false;
|
||||
updated.textContent = 'updatedAt ' + s.updatedAt;
|
||||
} else {
|
||||
updated.hidden = true;
|
||||
updated.textContent = '';
|
||||
}
|
||||
}
|
||||
if (proxyBox) {
|
||||
const seen = s.proxyHeadersSeen && typeof s.proxyHeadersSeen === 'object' ? s.proxyHeadersSeen : null;
|
||||
if (seen) {
|
||||
const keys = ['verify', 'verifyOk', 'dn', 'pem', 'any'];
|
||||
const chips = keys
|
||||
.filter((k) => Object.prototype.hasOwnProperty.call(seen, k))
|
||||
.map((k) => {
|
||||
const on = !!seen[k];
|
||||
return `<span class="pill ${on ? '' : 'off'}" style="font-size:11px">${k} ${on ? 'yes' : 'no'}</span>`;
|
||||
});
|
||||
if (chips.length) {
|
||||
proxyBox.style.display = 'flex';
|
||||
proxyBox.innerHTML = chips.join('');
|
||||
} else {
|
||||
proxyBox.style.display = 'none';
|
||||
proxyBox.innerHTML = '';
|
||||
}
|
||||
} else {
|
||||
proxyBox.style.display = 'none';
|
||||
proxyBox.innerHTML = '';
|
||||
}
|
||||
}
|
||||
if (mint && s.mint) {
|
||||
mint.hidden = false;
|
||||
mint.textContent = 'Mint: ' + s.mint;
|
||||
|
|
|
|||
|
|
@ -136,23 +136,45 @@
|
|||
if (!s || !s.note) return;
|
||||
const el = document.getElementById('enroll-status');
|
||||
el.hidden = false;
|
||||
const esc = (t) => String(t).replace(/&/g, '&').replace(/</g, '<');
|
||||
/* Prefer API state copy (not_enrolled|pending_proxy|enrolled|enforce_on) + nextSteps. */
|
||||
const label = s.stateLabel ? s.stateLabel + ' · ' : '';
|
||||
const steps = Array.isArray(s.nextSteps)
|
||||
? s.nextSteps.filter((x) => typeof x === 'string' && x.trim())
|
||||
: [];
|
||||
if (steps.length) {
|
||||
el.innerHTML =
|
||||
label +
|
||||
(s.note || '') +
|
||||
'<ol style="margin:0.45rem 0 0;padding-left:1.1rem">' +
|
||||
steps
|
||||
.map((t) => `<li>${String(t).replace(/&/g, '&').replace(/</g, '<')}</li>`)
|
||||
.join('') +
|
||||
'</ol>';
|
||||
} else {
|
||||
el.textContent = label + (s.note || '');
|
||||
let html = label + (s.note || '');
|
||||
if (typeof s.updatedAt === 'string' && s.updatedAt) {
|
||||
html +=
|
||||
'<div style="margin:0.35rem 0 0;font-family:ui-monospace,monospace;font-size:0.72rem">updatedAt ' +
|
||||
esc(s.updatedAt) +
|
||||
'</div>';
|
||||
}
|
||||
const seen = s.proxyHeadersSeen && typeof s.proxyHeadersSeen === 'object' ? s.proxyHeadersSeen : null;
|
||||
if (seen) {
|
||||
const keys = ['verify', 'verifyOk', 'dn', 'pem', 'any'];
|
||||
const chips = keys
|
||||
.filter((k) => Object.prototype.hasOwnProperty.call(seen, k))
|
||||
.map((k) => {
|
||||
const on = !!seen[k];
|
||||
return (
|
||||
'<span style="display:inline-block;margin:0.15rem 0.2rem 0 0;padding:0.05rem 0.4rem;border-radius:999px;font-size:0.68rem;font-weight:700;border:1px solid var(--line,#ddd);' +
|
||||
(on ? 'background:#ecfdf5;color:#047857' : 'background:#f4f1f8;color:#6b6478') +
|
||||
'">' +
|
||||
esc(k) +
|
||||
' ' +
|
||||
(on ? 'yes' : 'no') +
|
||||
'</span>'
|
||||
);
|
||||
});
|
||||
if (chips.length) html += '<div style="margin:0.35rem 0 0">' + chips.join('') + '</div>';
|
||||
}
|
||||
if (steps.length) {
|
||||
html +=
|
||||
'<ol style="margin:0.45rem 0 0;padding-left:1.1rem">' +
|
||||
steps.map((t) => '<li>' + esc(t) + '</li>').join('') +
|
||||
'</ol>';
|
||||
}
|
||||
el.innerHTML = html;
|
||||
if (s.state) el.dataset.state = s.state;
|
||||
})
|
||||
.catch(() => {});
|
||||
|
|
|
|||
Loading…
Reference in a new issue