portal: enforce onboarding step prerequisites
This commit is contained in:
parent
5f8ef42d79
commit
a63bb3b048
@ -65,6 +65,16 @@ ONBOARDING_STEPS: tuple[str, ...] = (
|
||||
|
||||
KEYCLOAK_MANAGED_STEPS: set[str] = {"keycloak_password_changed"}
|
||||
|
||||
ONBOARDING_STEP_PREREQUISITES: dict[str, set[str]] = {
|
||||
"vaultwarden_master_password": {"keycloak_password_changed"},
|
||||
"element_recovery_key": {"keycloak_password_changed", "vaultwarden_master_password"},
|
||||
"element_recovery_key_stored": {
|
||||
"keycloak_password_changed",
|
||||
"vaultwarden_master_password",
|
||||
"element_recovery_key",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _normalize_status(status: str) -> str:
|
||||
cleaned = (status or "").strip().lower()
|
||||
@ -562,6 +572,12 @@ def register(app) -> None:
|
||||
mark_done = completed
|
||||
|
||||
if mark_done:
|
||||
prerequisites = ONBOARDING_STEP_PREREQUISITES.get(step, set())
|
||||
if prerequisites:
|
||||
current_completed = _completed_onboarding_steps(conn, code, username)
|
||||
missing = sorted(prerequisites - current_completed)
|
||||
if missing:
|
||||
return jsonify({"error": "step is blocked", "blocked_by": missing}), 409
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO access_request_onboarding_steps (request_code, step)
|
||||
|
||||
@ -140,10 +140,13 @@
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="isStepDone('vaultwarden_master_password')"
|
||||
:disabled="!auth.authenticated || loading"
|
||||
:disabled="!auth.authenticated || loading || isStepBlocked('vaultwarden_master_password')"
|
||||
@change="toggleStep('vaultwarden_master_password', $event)"
|
||||
/>
|
||||
<span>Set a Vaultwarden master password</span>
|
||||
<span class="pill mono auto-pill" :class="stepPillClass('vaultwarden_master_password')">
|
||||
{{ stepPillLabel("vaultwarden_master_password") }}
|
||||
</span>
|
||||
</label>
|
||||
<p class="muted">
|
||||
Open <a href="https://vault.bstein.dev" target="_blank" rel="noreferrer">Passwords</a> and set a strong master
|
||||
@ -156,10 +159,13 @@
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="isStepDone('element_recovery_key')"
|
||||
:disabled="!auth.authenticated || loading"
|
||||
:disabled="!auth.authenticated || loading || isStepBlocked('element_recovery_key')"
|
||||
@change="toggleStep('element_recovery_key', $event)"
|
||||
/>
|
||||
<span>Create an Element recovery key</span>
|
||||
<span class="pill mono auto-pill" :class="stepPillClass('element_recovery_key')">
|
||||
{{ stepPillLabel("element_recovery_key") }}
|
||||
</span>
|
||||
</label>
|
||||
<p class="muted">
|
||||
In Element, create a recovery key so you can restore encrypted history if you lose a device.
|
||||
@ -171,10 +177,13 @@
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="isStepDone('element_recovery_key_stored')"
|
||||
:disabled="!auth.authenticated || loading"
|
||||
:disabled="!auth.authenticated || loading || isStepBlocked('element_recovery_key_stored')"
|
||||
@change="toggleStep('element_recovery_key_stored', $event)"
|
||||
/>
|
||||
<span>Store the recovery key in Vaultwarden</span>
|
||||
<span class="pill mono auto-pill" :class="stepPillClass('element_recovery_key_stored')">
|
||||
{{ stepPillLabel("element_recovery_key_stored") }}
|
||||
</span>
|
||||
</label>
|
||||
<p class="muted">Save the recovery key in Vaultwarden so it doesn't get lost.</p>
|
||||
</li>
|
||||
@ -247,6 +256,33 @@ function isStepDone(step) {
|
||||
return Array.isArray(steps) ? steps.includes(step) : false;
|
||||
}
|
||||
|
||||
function isStepBlocked(step) {
|
||||
const order = [
|
||||
"keycloak_password_changed",
|
||||
"vaultwarden_master_password",
|
||||
"element_recovery_key",
|
||||
"element_recovery_key_stored",
|
||||
];
|
||||
const idx = order.indexOf(step);
|
||||
if (idx <= 0) return false;
|
||||
for (let i = 0; i < idx; i += 1) {
|
||||
if (!isStepDone(order[i])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function stepPillLabel(step) {
|
||||
if (isStepDone(step)) return "done";
|
||||
if (isStepBlocked(step)) return "blocked";
|
||||
return "pending";
|
||||
}
|
||||
|
||||
function stepPillClass(step) {
|
||||
if (isStepDone(step)) return "pill-ok";
|
||||
if (isStepBlocked(step)) return "pill-wait";
|
||||
return "pill-warn";
|
||||
}
|
||||
|
||||
function taskPillClass(status) {
|
||||
const key = (status || "").trim();
|
||||
if (key === "ok") return "pill-ok";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user