Aug 26 - Enhance security 4
CI / Python lint (flake8) (push) Has been cancelled
CI / Python syntax check (push) Has been cancelled
CI / Alembic migration chain (push) Has been cancelled
CI / JavaScript syntax check (push) Has been cancelled
CI / Pytest (push) Has been cancelled
CI / Build extension zip (push) Has been cancelled
CI / Python lint (flake8) (push) Has been cancelled
CI / Python syntax check (push) Has been cancelled
CI / Alembic migration chain (push) Has been cancelled
CI / JavaScript syntax check (push) Has been cancelled
CI / Pytest (push) Has been cancelled
CI / Build extension zip (push) Has been cancelled
This commit is contained in:
@@ -953,6 +953,25 @@ ul {
|
||||
border: 1px solid #ffb74d;
|
||||
}
|
||||
|
||||
/* Emergency access: a pending request or a retrieved snapshot is the one thing
|
||||
in this list the grantor must not scroll past, so it gets the strongest
|
||||
treatment available rather than the amber used for ordinary warnings. */
|
||||
.badge-danger {
|
||||
background: #ffebee;
|
||||
color: #b71c1c;
|
||||
border: 1px solid #ef9a9a;
|
||||
}
|
||||
|
||||
.share-item.em-alert {
|
||||
border-left: 3px solid #c62828;
|
||||
background: #fff5f5;
|
||||
}
|
||||
|
||||
.share-meta.em-retrieved {
|
||||
color: #b71c1c;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.badge-info {
|
||||
background: #e3f2fd;
|
||||
color: #1565c0;
|
||||
|
||||
+30
-5
@@ -2445,6 +2445,16 @@ const Vault = (() => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whole days left before a pending emergency request unlocks. Mirrors the
|
||||
* server's wait_elapsed calculation in EmergencyAccess.wait_elapsed.
|
||||
*/
|
||||
function _emDaysRemaining(g) {
|
||||
if (!g.request_initiated_at) return g.wait_days;
|
||||
const elapsedMs = Date.now() - new Date(g.request_initiated_at).getTime();
|
||||
return Math.max(0, Math.ceil(g.wait_days - elapsedMs / 86400000));
|
||||
}
|
||||
|
||||
function renderEmergencyGrants(grants) {
|
||||
const ul = document.getElementById("em-grants-list");
|
||||
if (!ul) return;
|
||||
@@ -2471,17 +2481,32 @@ const Vault = (() => {
|
||||
}
|
||||
}
|
||||
if (g.status === "pending") {
|
||||
// The wait period is the only thing standing between a request and
|
||||
// the grantee reading the vault, so make the countdown explicit
|
||||
// rather than showing a bare status word.
|
||||
const waitInfo = g.wait_elapsed
|
||||
? "Wait period elapsed"
|
||||
: "Access requested";
|
||||
actions = `<span class="badge badge-warn">${waitInfo}</span>
|
||||
<button class="btn-secondary btn-sm" data-deny="${g.id}">Deny</button>`;
|
||||
? "⚠ Wait elapsed — access is available now"
|
||||
: `⏳ Unlocks in ${_emDaysRemaining(g)} day(s)`;
|
||||
actions = `<span class="badge badge-danger">${waitInfo}</span>
|
||||
<button class="btn-primary btn-sm" data-deny="${g.id}">Deny</button>`;
|
||||
}
|
||||
return `<li class="share-item">
|
||||
|
||||
// Retrieval is not blocked after the wait elapses, so the grantor's
|
||||
// signal that it happened is this badge plus their audit log.
|
||||
const retrieved = g.vault_retrieval_count
|
||||
? `<span class="share-meta em-retrieved">⚠ Vault retrieved ${
|
||||
g.vault_retrieval_count
|
||||
}× · first on ${new Date(
|
||||
g.vault_retrieved_at,
|
||||
).toLocaleDateString()} — remove this grant if unexpected</span>`
|
||||
: "";
|
||||
|
||||
return `<li class="share-item${g.status === "pending" || g.vault_retrieval_count ? " em-alert" : ""}">
|
||||
<div class="share-icon">🚨</div>
|
||||
<div class="share-info">
|
||||
<span class="share-name">${escHtml(g.grantee_email)}</span>
|
||||
<span class="share-meta">Status: ${escHtml(g.status)} · Wait: ${g.wait_days} day(s)</span>
|
||||
${retrieved}
|
||||
</div>
|
||||
<div class="share-actions">
|
||||
${actions}
|
||||
|
||||
Reference in New Issue
Block a user