diff --git a/oidc-controller/api/authSessions/models.py b/oidc-controller/api/authSessions/models.py index 8e10ec6d..c8fdc257 100644 --- a/oidc-controller/api/authSessions/models.py +++ b/oidc-controller/api/authSessions/models.py @@ -15,6 +15,7 @@ class AuthSessionState(StrEnum): EXPIRED = auto() VERIFIED = auto() FAILED = auto() + ABANDONED = auto() class AuthSessionBase(BaseModel): pres_exch_id: str diff --git a/oidc-controller/api/routers/acapy_handler.py b/oidc-controller/api/routers/acapy_handler.py index b53ff642..53a06737 100644 --- a/oidc-controller/api/routers/acapy_handler.py +++ b/oidc-controller/api/routers/acapy_handler.py @@ -61,6 +61,16 @@ async def post_topic(request: Request, topic: str, db: Database = Depends(get_db await AuthSessionCRUD(db).patch( str(auth_session.id), AuthSessionPatch(**auth_session.dict()) ) + + # abandoned state + if webhook_body["state"] == "abandoned": + logger.info("ABANDONED") + logger.info(webhook_body["error_msg"]) + auth_session.proof_status = AuthSessionState.ABANDONED + await sio.emit("status", {"status": "abandoned"}, to=sid) + await AuthSessionCRUD(db).patch( + str(auth_session.id), AuthSessionPatch(**auth_session.dict()) + ) # Calcuate the expiration time of the proof now_time = datetime.now() diff --git a/oidc-controller/api/templates/verified_credentials.html b/oidc-controller/api/templates/verified_credentials.html index 38a667d8..c1075fbf 100644 --- a/oidc-controller/api/templates/verified_credentials.html +++ b/oidc-controller/api/templates/verified_credentials.html @@ -136,6 +136,7 @@ .header-desc.success, .header-desc.pending, .header-desc.expired, + .header-desc.abandoned, .header-desc.failed { display: none; border-radius: 0.5rem; @@ -166,6 +167,9 @@ .header-desc.success { background-color: #dff0d8; } + .header-desc.abandoned { + background-color: #f2dede; + } .header-desc a { line-height: 1rem; } @@ -216,6 +220,18 @@

Scan with a Digital Wallet

+
+
{{add_asset("circle-x.svg")}}
+
+ Proof declined +
+ Try again. +
+
+
{{add_asset("hourglass.svg")}}
@@ -273,93 +289,27 @@

Scan with a Digital Wallet

socket.connect(); const toggleState = (state) => { - const intro = document.querySelector(".intro"); - const success = document.querySelector(".success"); - const pending = document.querySelector(".pending"); - const failed = document.querySelector(".failed"); - const expired = document.querySelector(".expired"); - const qrcode = document.querySelector(".qr-code"); - const scannedMask = document.querySelector(".scanned-mask"); - const refreshButton = document.getElementById("refresh-button"); - switch (state) { case "intro": - // Header elements - intro.style.display = "grid"; - success.style.display = "none"; - pending.style.display = "none"; - failed.style.display = "none"; - expired.style.display = "none"; - - // Button elements - refreshButton.style.display = "none"; - - // Turn off the spinner - qrcode.classList.remove("pending"); + setUiElements(".intro", false, false, false); break; case "verified": - // Header elements - intro.style.display = "none"; - success.style.display = "grid"; - pending.style.display = "none"; - failed.style.display = "none"; - expired.style.display = "none"; - - // Button elements - refreshButton.style.display = "none"; - scannedMask.style.display = "flex"; - - // Turn off the spinner - qrcode.classList.remove("pending"); - + setUiElements(".success", false, true, false); setTimeout(() => { window.location.replace("{{callback_url}}", { method: "POST" }); }, 2000); break; case "failed": - // Header elements - intro.style.display = "none"; - success.style.display = "none"; - pending.style.display = "none"; - failed.style.display = "grid"; - expired.style.display = "none"; - - // Button elements - refreshButton.style.display = "flex"; - scannedMask.style.display = "none"; - - // Turn off the spinner - qrcode.classList.remove("pending"); + setUiElements(".failed", true, false, false); break; case "pending": - // Header elements - intro.style.display = "none"; - success.style.display = "none"; - pending.style.display = "grid"; - failed.style.display = "none"; - expired.style.display = "none"; - - // Button elements - refreshButton.style.display = "none"; - scannedMask.style.display = "flex"; - - // Turn on the spinner - qrcode.classList.add("pending"); + setUiElements(".pending", false, true, true); break; case "expired": - // Header elements - intro.style.display = "none"; - success.style.display = "none"; - pending.style.display = "none"; - failed.style.display = "none"; - expired.style.display = "grid"; - - // Button elements - refreshButton.style.display = "flex"; - scannedMask.style.display = "none"; - - // Turn off the spinner - qrcode.classList.remove("pending"); + setUiElements(".expired", true, false, false); + break; + case "abandoned": + setUiElements(".abandoned", true, false, false); break; } }; @@ -368,6 +318,29 @@

Scan with a Digital Wallet

location.reload(true); }); + /** + * Set the UI elements based on the current state + */ + const setUiElements = (state, showRefresh, showScanned, setSpinner) => { + const stateElement = document.querySelector(state); + const qrcode = document.querySelector(".qr-code"); + const scannedMask = document.querySelector(".scanned-mask"); + const refreshButton = document.getElementById("refresh-button"); + + // set all elements to display: none and display the current state + document.querySelectorAll(".header-desc").forEach((el) => { + el.style.display = "none"; + }); + stateElement.style.display = "grid"; + + // set the refresh and/or scanned overlays + refreshButton.style.display = showRefresh ? "flex" : "none"; + scannedMask.style.display = showScanned ? "flex" : "none"; + + // add or remove 'pending' class from qrcode based on setSpinner + qrcode.classList.toggle("pending", setSpinner); + } + let timer; /**