diff --git a/bundled-addons/aegis/addon.json b/bundled-addons/aegis/addon.json index e4aa94a9..eab8c1a2 100644 --- a/bundled-addons/aegis/addon.json +++ b/bundled-addons/aegis/addon.json @@ -1,7 +1,7 @@ { "id": "aegis", "name": "Aegis Wallet", - "version": "0.32.0", + "version": "0.32.1", "category": "plugin", "description": "Multi-chain wallet (BCH, BTC, TRX, ETH, SOL, SC, DGB) derived from your Theseus vault. Dapps get window.bitcoincash and window.wizardconnect on any site; window.tronWeb / window.tronLink / window.ethereum / window.solana too. Every call needs your approval.", "author": "Silent Mode", diff --git a/bundled-addons/aegis/index.js b/bundled-addons/aegis/index.js index 135642b3..83d4a337 100644 --- a/bundled-addons/aegis/index.js +++ b/bundled-addons/aegis/index.js @@ -2856,6 +2856,11 @@ function registerPanelMessages(api) { await refreshHostPin(api); if (r && r.ok) return { ok: true, masterPassword: mintPinProof() }; if (r && r.code === "no-pin") throw new Error("no PIN is set"); + // Not a guess (Theseus spends no strike on it): the pad had the wrong + // number of digits for this PIN. + if (r && r.code === "wrong-length") { + return { ok: false, remaining: Number(r.remaining) || 0, lockedMs: 0, error: `Your PIN has ${Number(r.length) || hostPinCache.length || "a different number of"} digits. Reopen this prompt and try again.` }; + } return { ok: false, remaining: Number(r?.remaining) || 0, lockedMs: Number(r?.lockedMs) || 0, error: r?.error || undefined }; } const blob = openPinBlob(api); @@ -2981,6 +2986,7 @@ function registerPanelMessages(api) { pinHardware: blob ? (blob.hw ? "tpm" : "none") : host ? (host.pinSet ? host.hardware || "none" : null) : null, pinStorable: host ? host.storable !== false : osSealUsable(safeStorageOr(api)), pinUnified: !!hostPinApi(api), + pinLength: host && host.pinSet && Number(host.length) >= 6 && Number(host.length) <= 8 ? Number(host.length) : 6, pinLegacyExposure: exposed && !exposed.dismissed ? { at: exposed.at } : null, }; } diff --git a/bundled-addons/aegis/panel.js b/bundled-addons/aegis/panel.js index 3bd3f3cb..a1166e7b 100644 --- a/bundled-addons/aegis/panel.js +++ b/bundled-addons/aegis/panel.js @@ -330,6 +330,12 @@ const pinTry = async (pin) => { async function pinLockoutRemainingMs() { try { return Number((await S.invoke("pinStatus")).lockedMs) || 0; } catch { return 0; } } +// How many digits the PIN being entered has: the Theseus vault PIN can be +// 6-8 digits (pinLength from the host), Aegis's own PIN is always 6. +function pinEntryLength() { + const n = Number(securityState && securityState.pinLength); + return n >= 6 && n <= 8 ? n : 6; +} async function refreshSecurityState() { try { securityState = await S.invoke("securityGet"); @@ -3375,7 +3381,7 @@ function renderLockScreen(phase) { body.dataset.mode = "pin"; body.innerHTML = `
-
${"".repeat(6)}
+
${"".repeat(pinEntryLength())}
${[1,2,3,4,5,6,7,8,9].map((n) => ``).join("")} @@ -3469,7 +3475,10 @@ function renderLockScreen(phase) { // are duplicate ids — a global lookup then returns the FIRST one, and this // function binds a second click handler to the wrong pad's buttons. The // symptom is a pad that appends two digits per press and resets after three. +// The pad takes its length from the dots it was drawn with: 6 for Aegis's +// own PIN, 6-8 for the Theseus vault PIN (pinLength from the host). function setupPinPad({ dots, keys, err, onComplete }) { + const len = dots.querySelectorAll(".pindot").length || 6; let buf = ""; const paint = () => { const nodes = dots.querySelectorAll(".pindot"); @@ -3480,10 +3489,10 @@ function setupPinPad({ dots, keys, err, onComplete }) { if (err) err.textContent = ""; if (k === "clear") { buf = ""; paint(); return; } if (k === "back") { buf = buf.slice(0, -1); paint(); return; } - if (buf.length >= 6) return; + if (buf.length >= len) return; buf += k; paint(); - if (buf.length === 6) { + if (buf.length === len) { keys.querySelectorAll("button").forEach((x) => x.disabled = true); let res = "reset"; try { res = await onComplete(buf); } @@ -3512,9 +3521,9 @@ function setupPinPad({ dots, keys, err, onComplete }) { if (tgt && (tgt.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(tgt.tagName || ""))) return; if (err) err.textContent = ""; if (/^[0-9]$/.test(e.key)) { - if (buf.length >= 6) return; + if (buf.length >= len) return; buf += e.key; paint(); - if (buf.length === 6) { + if (buf.length === len) { keys.querySelectorAll("button").forEach((x) => x.disabled = true); let res = "reset"; try { res = await onComplete(buf); } @@ -5345,7 +5354,7 @@ function capturePinForSecret(subtitle) {

Confirm with PIN

${esc(subtitle || "")}
-
${"".repeat(6)}
+
${"".repeat(pinEntryLength())}
${[1,2,3,4,5,6,7,8,9].map((n) => ``).join("")} @@ -5410,7 +5419,7 @@ async function verifyPinInteractivelyOnce(subtitle) {

Confirm with PIN

${esc(subtitle || "")}
-
${"".repeat(6)}
+
${"".repeat(pinEntryLength())}
${[1,2,3,4,5,6,7,8,9].map((n) => ``).join("")}