Show every answer the portal remembers, and give SSH keys their missing half
Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
@@ -69,7 +69,7 @@ grep -qiE 'property (string|var) (secret|password|value)\b' "$service" \
|
||||
&& fail 'the Keyring service declares a property that would hold a secret value'
|
||||
|
||||
# ── 4. Forgetting is confirmed ───────────────────────────────────────────────
|
||||
grep -q 'confirmingPath' "$page" \
|
||||
grep -q 'confirmingItem' "$page" \
|
||||
|| fail 'the page deletes a stored secret without a confirmation step'
|
||||
grep -q 'Keyring.forget(' "$page" \
|
||||
|| fail 'the page cannot forget a secret at all'
|
||||
@@ -79,9 +79,78 @@ grep -q 'Keyring.forget(' "$page" \
|
||||
# for confirmation rather than a deletion.
|
||||
grep -q 'if (!secretRow.confirming)' "$page" \
|
||||
|| fail 'the first press on Forget is not turned into a confirmation step'
|
||||
grep -q 'root.confirmingPath = secretRow.itemPath;' "$page" \
|
||||
grep -q 'root.confirmingItem = secretRow.itemPath;' "$page" \
|
||||
|| fail 'nothing records which item is awaiting confirmation'
|
||||
|
||||
# ── 5. Confirming a Forget does not move the Copy button ─────────────────────
|
||||
#
|
||||
# The page used to run one confirmation state for the whole card, and the row's
|
||||
# other button read `confirming ? "Cancel" : "Copy"`. So arming Forget on a row
|
||||
# replaced the word "Copy" -- in the exact place the user had just learnt to
|
||||
# find it -- with "Cancel", and the way out of a confirmation was to press the
|
||||
# button that copies. Two states that happen to be about the same row are still
|
||||
# two states.
|
||||
python3 - "$page" <<'PY' || fail 'the copy button doubles as something else'
|
||||
import re
|
||||
import sys
|
||||
|
||||
text = "\n".join(line for line in open(sys.argv[1], encoding="utf-8").read().splitlines()
|
||||
if not line.strip().startswith("//"))
|
||||
|
||||
|
||||
def block_at(start: int) -> str:
|
||||
depth = 0
|
||||
for index in range(text.find("{", start), len(text)):
|
||||
if text[index] == "{":
|
||||
depth += 1
|
||||
elif text[index] == "}":
|
||||
depth -= 1
|
||||
if depth == 0:
|
||||
return text[start:index + 1]
|
||||
return ""
|
||||
|
||||
|
||||
buttons = [block_at(match.start()) for match in re.finditer(r"SettingsButton \{", text)]
|
||||
copiers = [block for block in buttons if "Keyring.copy(" in block]
|
||||
if not copiers:
|
||||
raise SystemExit("nothing on the page copies a stored secret")
|
||||
for block in copiers:
|
||||
label = re.search(r'text:\s*(.+)', block)
|
||||
if label is None:
|
||||
raise SystemExit("the copy button has no label")
|
||||
if label.group(1).strip().rstrip(";") != '"Copy"':
|
||||
raise SystemExit(f"the copy button's label is conditional: {label.group(1).strip()}")
|
||||
|
||||
# ...and its press does one thing. The old Cancel behaviour lived in the
|
||||
# handler as well as the label: pressing Copy while a Forget was armed
|
||||
# cleared the confirmation instead of copying.
|
||||
handler = re.search(r'onClicked:\s*(\{.*?\n\s*\}|[^\n]+)', block, re.S)
|
||||
if handler is None:
|
||||
raise SystemExit("the copy button does nothing when pressed")
|
||||
if re.search(r'confirming', handler.group(1)):
|
||||
raise SystemExit(f"pressing Copy reads the confirmation state: {handler.group(1).strip()}")
|
||||
|
||||
forgetters = [block for block in buttons if "Keyring.forget(" in block]
|
||||
if not forgetters:
|
||||
raise SystemExit("nothing on the page forgets a stored secret")
|
||||
for block in forgetters:
|
||||
if "Keyring.copy(" in block:
|
||||
raise SystemExit("one button both copies and forgets")
|
||||
PY
|
||||
|
||||
# ── 6. A copy says it happened, on its own row ───────────────────────────────
|
||||
#
|
||||
# Putting something on the clipboard is invisible. The confirmation has to be
|
||||
# tied to the row it happened on, or a card of six identical Copy buttons says
|
||||
# only that A copy happened.
|
||||
grep -qE 'Keyring\.copiedPath === [A-Za-z_][A-Za-z0-9_]*\.itemPath' "$page" \
|
||||
|| fail 'the copy confirmation is not tied to the row that was copied'
|
||||
grep -q 'copiedPath' "$service" \
|
||||
|| fail 'the service records nothing about a copy, so no row can confirm one'
|
||||
# ...and the confirmation is not the same state as the Forget confirmation.
|
||||
grep -qE 'confirmingItem[^=]*=[^=].*copiedPath|copiedPath.*=.*confirmingItem' "$page" \
|
||||
&& fail 'the confirm state and the copy state are the same value'
|
||||
|
||||
# Opening the page must not enumerate anyone's passwords as a side effect.
|
||||
grep -qE 'Component.onCompleted:.*Keyring.list\(\)' "$page" \
|
||||
&& fail 'the page lists stored secrets when it opens rather than when asked'
|
||||
|
||||
Reference in New Issue
Block a user