Compare commits

..

1 Commits

Author SHA1 Message Date
3350105a48 fix: correct verify-build diagnostics and close two robustness gaps (closes #180)
All checks were successful
check / check (push) Successful in 1m12s
The both-markers diagnostic claimed the debug branch was still live. It is
not: with the __BUILD_DEBUG__ define removed, the emitted bundle carries
`typeof __BUILD_DEBUG__<"u"?__BUILD_DEBUG__:!1`, and in extension context the
identifier is undeclared, so DEBUG evaluates to false at runtime. The message
now states what the check does prove -- DEBUG was not resolved at build time,
so the release/debug distinction is no longer enforced and which way the
unresolved fallback evaluates is an accident a refactor can flip -- and it
remains a hard failure. The other seven failure messages were reviewed and
none needed rewording.

has_marker no longer swallows grep's exit 2 with 2>/dev/null. Match and
no-match are answers about the emitted output; an unreadable file is not, and
is now reported as a permissions or I/O fault instead of as "the emitted
output changed shape". Both paths still fail hard.

The unlisted-bundle scan no longer filters by extension, so the endsWith(".js")
test in build.js is the only place that assumption lives. A bundle emitted
under another extension previously escaped the manifest and the cross-check at
once; it now fails as unlisted. Both sites carry a comment naming the other.

Also: the manifest must be readable and a listed bundle must be non-empty,
so a vacuous input fails loudly rather than reaching a marker check that
cannot prove anything.
2026-08-11 12:26:38 +00:00
4 changed files with 126 additions and 340 deletions

404
README.md
View File

@@ -271,10 +271,10 @@ on a different table knows exactly tf I am talking about.
Every interactive element must visually indicate that it is clickable. Buttons
use a visible border, padding, and a hover state (invert to white-on-black).
Text that triggers an action (e.g. "Add additional wallet...") uses an
underline. No invisible hit targets, no bare text that happens to have a click
handler. If it does something when you click it, it must look like it does
something when you click it.
Text that triggers an action (e.g. "Import private key") uses an underline. No
invisible hit targets, no bare text that happens to have a click handler. If it
does something when you click it, it must look like it does something when you
click it.
#### Display Consistency
@@ -334,18 +334,12 @@ attack.
The core hierarchy is **Wallets → Addresses**:
- A **wallet** is one of three types:
- An **HD wallet** (`type: "hd"`, recovery phrase): generates multiple
addresses from a single 12/24 word recovery phrase using BIP-39/BIP-44
derivation. The user can add more addresses with a "+" button.
- A **key wallet** (`type: "key"`, private key): a single address imported
directly from a private key. No "+" button since there is only one
address.
- An **xprv wallet** (`type: "xprv"`, extended private key): the same
multi-address behavior as an HD wallet, including the "+" button and the
address scan on import, but imported from an extended private key rather
than a recovery phrase. It therefore has no recovery phrase to display or
back up.
- A **wallet** is either:
- An **HD wallet** (recovery phrase): generates multiple addresses from a
single 12/24 word recovery phrase using BIP-39/BIP-44 derivation. The user
can add more addresses with a "+" button.
- A **key wallet** (private key): a single address imported directly from a
private key. No "+" button since there is only one address.
- An **address** holds ETH and any user-added ERC-20 tokens.
- The user can have multiple wallets, each with multiple addresses (HD) or a
single address (key).
@@ -360,140 +354,95 @@ menus.
### Screen Map
Navigation uses a stack model (like iOS): each forward action pushes the current
screen onto `state.viewStack`, and "Back" pops it (`pushCurrentView()` and
`goBack()` in `src/popup/views/helpers.js`). The root screen is either Welcome
(no wallets) or Home (has wallets). Each screen below gives its view id in
parentheses; the registry of view ids is the `VIEWS` array in
`src/popup/views/helpers.js`, and the markup for a screen is the element with id
`view-` plus that view id in `src/popup/index.html`.
Navigation uses a stack model (like iOS): each action pushes a screen onto the
stack, and "Back" pops it. The root screen is either Welcome (no wallets) or
Home (has wallets). Screens are listed below with their elements and
transitions.
Three elements sit outside the screens and are present on all of them: the title
bar ("AutistMask by @sneak" plus the Settings gear), the flash message line
under it, and the red banner at the very top that appears on a debug build, when
runtime debug mode is on, or when the active network is a testnet. They are not
repeated in the element lists below.
#### Welcome
Closing and reopening the popup returns to the screen the user was last on only
for the views listed in `RESTORABLE_VIEWS` (`src/popup/index.js`). Every other
screen, including ExportPrivKey, falls back to Home.
#### Welcome (`welcome`)
- **When**: No wallets exist yet (`state.hasWallet` is false). This is the root
screen in that case.
- **Elements**:
- "Welcome! To get started, add a wallet." text
- "Add wallet" button
- **When**: No wallets exist yet.
- **Elements**: "AutistMask" heading, brief intro text, "Add wallet" button.
- **Transitions**:
- "Add wallet" → **AddWallet**
#### Home (`main`)
#### Home
- **When**: At least one wallet exists. This is the root screen.
- **Elements**:
- Active address ETH balance (large) + USD value in parentheses
- "Total:" USD value across ETH and all tracked tokens of the active address
- Header: "AutistMask", Settings gear button
- Active address ETH balance (large) + USD value (inline parentheses)
- Total USD value across all tokens (small text)
- Active address (color dot, full address, etherscan link, tap to copy)
- Send / Receive quick-action buttons, both acting on the active address
- Send / Receive quick-action buttons
- ETH/USD price display
- Wallet list: each wallet shows its name (tap to rename inline) and a "+"
button for HD and xprv wallets, then one block per address with "Address
N" (bold when active), the ENS name if resolved, the full address, an
`[info]` button, the address USD total, and a balance line for ETH and for
each tracked token
- "Recent Transactions": up to 25 transactions merged across every address
of every wallet, deduplicated by hash and filtered
- Wallet list: each wallet shows name (tap to rename), "+" button (HD only),
and its addresses with color dots, balances, and `[info]` buttons
- Recent transactions across all addresses (merged, deduplicated, filtered)
- "Add additional wallet..." link at bottom
- **Transitions**:
- Tap address row → sets the active address and broadcasts
`AUTISTMASK_ACTIVE_CHANGED` (no screen change)
- Tap wallet name → inline rename field (no screen change)
- "+" on wallet → derives the next address inline (no screen change)
- Tap address row → sets active address (no screen change)
- `[info]` on address → **AddressDetail**
- "Send" → **Send** (refuses with a flash message on a zero balance)
- "Send" → **Send** (selects active address)
- "Receive" → **Receive** (shows active address QR)
- Tap home tx row → **TransactionDetail**
- "+" on wallet → derives next address inline
- "Add additional wallet..." → **AddWallet**
- Settings gear → **Settings** (toggles; tap again to return)
- Tap home tx row → **AddressDetail** (for the address involved)
#### AddWallet (`add-wallet`)
#### AddWallet
- **When**: User wants to add a new wallet (from Welcome, Home, or Settings).
This one screen covers all three import modes; there is no separate import
screen.
- **When**: User wants to add a new wallet (from Home, Welcome, or Settings).
- **Elements**:
- "Back" button, "Add Wallet" heading
- Three tabs — "From Phrase" (`tab-mnemonic`), "From Key" (`tab-privkey`),
"From xprv" (`tab-xprv`) — each showing its own form section:
- **From Phrase**: instruction text, a die button that generates a
random recovery phrase, a recovery phrase textarea, and a backup
warning box that becomes visible once the die button has been used
- **From Key**: instruction text and a masked private key input
- **From xprv**: instruction text and a masked extended private key
input
- Password + confirm password inputs, with a hint line whose wording depends
on the selected tab
- "Add Wallet" heading, "Back" button
- Instruction text
- Die button `[die]` (generates random recovery phrase)
- Recovery phrase textarea
- Backup warning box (shown after die is clicked)
- Password + confirm password inputs
- "Add" button
- "Have a private key instead?" link
- **Transitions**:
- "Add" (valid phrase + password) → **Home**
- "Back" → previous screen (Home or Welcome)
- "Have a private key instead?" → **ImportKey**
#### ImportKey
- **When**: User wants to import a single private key.
- **Elements**:
- "Import Private Key" heading, "Back" button
- Instruction text
- Private key input (password-masked)
- Password + confirm password inputs
- "Import" button
- **Transitions**:
- "Import" with a valid entry and a matching password of at least 12
characters → creates the wallet, clears the navigation stack, and →
**Home**. The phrase and xprv modes then scan for further used addresses
and report the count as a flash message.
- "Import" with an invalid entry, a duplicate wallet or address, or a short
or mismatched password → flash message, no screen change
- "Back" → previous screen (Welcome, Home, or Settings)
- "Import" (valid key + password) → **Home**
- "Back" → **AddWallet**
#### AddressDetail (`address`)
#### AddressDetail
- **When**: User tapped `[info]` on an address from Home.
- **Elements**:
- "Back" button
- Blockie identicon (48px, centered)
- Title: "Wallet Name — Address N"
- ENS name (if resolved, bold above the address)
- ENS name (if resolved, bold with color dot)
- Full address (color dot, etherscan link, tap to copy)
- USD total for address
- Balance list: ETH + tracked ERC-20 tokens (4 decimal places, USD inline).
Each balance row is clickable → **AddressToken**
- Send / Receive / + Token buttons and a "···" menu button
- "···" dropdown containing a single "Export Private Key" entry
- Send / Receive / + Token buttons
- Transaction list (with ENS resolution for counterparties)
- **Transitions**:
- Tap balance row → **AddressToken** (for that token)
- "Send" → **Send** (refuses with a flash message on a zero balance)
- "Send" → **Send**
- "Receive" → **Receive**
- "+ Token" → **AddToken**
- "···" → "Export Private Key" → **ExportPrivKey**
- Tap transaction row → **TransactionDetail**
- "Back" → previous screen (Home)
- "Back" → **Home**
#### ExportPrivKey (`export-privkey`)
- **When**: User chose "Export Private Key" from the "···" menu on
AddressDetail. This screen discloses secret material.
- **Elements**:
- "Back" button
- Blockie identicon (48px, centered)
- "Export Private Key" heading
- "Wallet Name — Address N" and the full address (etherscan link, tap to
copy)
- Warning that anyone holding the private key can transfer all funds from
the address
- Error line
- Password input and "Reveal" button, shown until the key is revealed
- The private key on a highlighted background, tap to copy, shown only after
the password has been accepted
- **Transitions**:
- "Reveal" (correct password) → decrypts the wallet secret, derives this
address's key, hides the password input and shows the key (no screen
change)
- "Reveal" (wrong password) → "Wrong password." on the error line, nothing
revealed
- "Back" → clears the key and password from the DOM, then → previous screen
(AddressDetail)
#### AddressToken (`address-token`)
#### AddressToken
- **When**: User clicked a specific token balance on AddressDetail.
- **Elements**:
@@ -504,64 +453,49 @@ screen, including ExportPrivKey, falls back to Home.
- USD total for this token
- Single token balance line (4 decimal places)
- Send / Receive buttons
- Token contract well (ERC-20 only): full contract address (tap to copy,
etherscan link) plus name, symbol, decimals, holder count and project
website where known
- Token-filtered transaction list (only this token's transfers)
- **Transitions**:
- "Send" → **Send** (token locked: the dropdown is replaced by a static
symbol and contract address)
- "Send" → **Send** (token pre-selected and locked in dropdown)
- "Receive" → **Receive** (ERC-20 warning shown for non-ETH tokens)
- Tap transaction row → **TransactionDetail**
- "Back" → previous screen (AddressDetail)
- "Back" → **AddressDetail**
#### Send (`send`)
#### Send
- **When**: User wants to send ETH or a token, from Home, AddressDetail, or
AddressToken.
- **When**: User wants to send ETH or a token from this address.
- **Elements**:
- "Back" button, "Send" heading
- "Send" heading, "Back" button
- From: address with color dot + etherscan link
- What to send: token dropdown (or static display with contract address when
locked from AddressToken)
- To: address or ENS name input, with an inline validation message
- To: address or ENS name input
- Amount input with current balance display
- "Review" button, disabled until the recipient validates
- "Review" button
- **Transitions**:
- "Review" (valid inputs, ENS resolved) → **ConfirmTx**
- "Review" with an unresolvable ENS name or an invalid amount → flash
message, no screen change
- "Back" → previous screen (Home, AddressDetail, or AddressToken)
- "Back" → **AddressToken** (if came from token view) or **AddressDetail**
#### ConfirmTx (`confirm-tx`)
#### ConfirmTx
- **When**: User reviewed send details and is ready to authorize.
- **Elements**:
- "Back" button, "Confirm Transaction" heading
- "Confirm Transaction" heading, "Back" button
- Type: "Native ETH transfer" or "ERC-20 token transfer (SYMBOL)"
- Token contract: full address + etherscan link (ERC-20 only)
- From: blockie + color dot + full address + etherscan link + wallet title
- To: blockie + color dot + full address + etherscan link + ENS name
- Amount: value + symbol (USD in parentheses)
- Your balance: value + symbol (USD in parentheses)
- Estimated network fee: "Estimating..." then the ETH amount (USD in
parentheses) or "Unable to estimate", fetched async
- Warnings: inline warnings from the local checks (scam address, self-send)
plus four reserved warning boxes made visible by the async checks —
recipient with no transaction history, recipient is a contract, burn
address, and an Etherscan phishing/scam label
- Estimated network fee: ETH amount (USD in parentheses), fetched async
- Warnings (scam address, self-send)
- Errors (insufficient balance)
- Password: an inline field on this screen, not a modal, with its own error
line
- "Sign & Send" button (disabled if errors)
- "Send" button (disabled if errors)
- **Transitions**:
- "Sign & Send" (correct password) → broadcast tx → **WaitTx**
- "Sign & Send" (correct password) → broadcast fails → **ErrorTx**
- "Sign & Send" (wrong password) → "Wrong password." on the password error
line, no screen change
- "Send" → password modal → broadcast tx → **WaitTx**
- "Send" → password modal → broadcast fails → **ErrorTx**
- "Back" → **Send**
#### WaitTx (`wait-tx`)
#### WaitTx
- **When**: Transaction has been broadcast, waiting for on-chain confirmation.
- **Elements**:
@@ -575,24 +509,20 @@ screen, including ExportPrivKey, falls back to Home.
- Receipt found → **SuccessTx**
- 60 seconds without confirmation → **ErrorTx** (timeout message)
#### SuccessTx (`success-tx`)
#### SuccessTx
- **When**: Transaction confirmed on-chain.
- **Elements**:
- "Transaction Confirmed" heading
- Decoded action well (shown when the transaction carried recognized
calldata; the top-level Amount and To are hidden in that case)
- Amount + symbol
- To: color dot + full address + etherscan link
- Block number
- Transaction hash: full hash (tap to copy) + etherscan link
- "Done" button
- **Transitions**:
- "Done" in the approval popup → closes the popup window
- "Done" otherwise → resets the navigation stack, then → **AddressToken**
(if `selectedToken` set) or **AddressDetail**
- "Done" **AddressToken** (if `selectedToken` set) or **AddressDetail**
#### ErrorTx (`error-tx`)
#### ErrorTx
- **When**: Transaction broadcast failed, or timed out waiting for confirmation.
- **Elements**:
@@ -604,28 +534,24 @@ screen, including ExportPrivKey, falls back to Home.
full hash (tap to copy) + etherscan link
- "Done" button
- **Transitions**:
- "Done" in the approval popup → closes the popup window
- "Done" otherwise → resets the navigation stack, then → **AddressToken**
(if `selectedToken` set) or **AddressDetail**
- "Done" **AddressToken** (if `selectedToken` set) or **AddressDetail**
#### Receive (`receive`)
#### Receive
- **When**: User wants to receive funds at this address, from Home,
AddressDetail, or AddressToken.
- **When**: User wants to receive funds at this address.
- **Elements**:
- "Back" button, "Receive" heading
- "Receive" heading, "Back" button
- Instruction text
- QR code encoding the address
- Full address (color dot, selectable, etherscan link)
- "Copy address" button
- ERC-20 warning (shown when navigating from AddressToken for non-ETH token)
- **Transitions**:
- "Back" → previous screen (Home, AddressDetail, or AddressToken)
- "Back" → **AddressToken** (if `selectedToken` set) or **AddressDetail**
#### TransactionDetail (`transaction`)
#### TransactionDetail
- **When**: User tapped a transaction row on Home, AddressDetail, or
AddressToken.
- **When**: User tapped a transaction row from AddressDetail or AddressToken.
- **Elements** (grouped into logical blocks using light well containers; field
labels are self-explanatory so groups have no headings):
- "Transaction" heading, "Back" button
@@ -650,182 +576,91 @@ screen, including ExportPrivKey, falls back to Home.
- Raw data (shown when calldata is present): full calldata in monospace
dashed border
- **Transitions**:
- "Back" → previous screen (Home, AddressDetail, or AddressToken)
- "Back" → **AddressToken** (if `selectedToken` set) or **AddressDetail**
#### AddToken (`add-token`)
#### AddToken
- **When**: User wants to track an ERC-20 token, reached from "+ Token" on
AddressDetail.
- **When**: User wants to track an ERC-20 token on this address.
- **Elements**:
- "Back" button, "Add Token" heading
- "Add Token" heading, "Back" button
- Instruction text (find contract address on Etherscan)
- Contract address input
- Status line ("Looking up token...", cleared or replaced on failure)
- Common token quick-pick buttons (top 25 by market cap), which fill the
contract address input
- Token info preview (name, symbol — fetched from contract)
- Common token quick-pick buttons
- "Add" button
- **Transitions**:
- "Add" (valid contract) → tracks the token, pops the stack, and re-renders
**AddressDetail**
- "Add" with a token already tracked, a scam-listed address, or a failed
contract lookup → flash message, no screen change
- "Back" → previous screen (AddressDetail)
- "Add" (valid contract) → **AddressDetail**
- "Back" → **AddressDetail**
#### Settings (`settings`)
#### Settings
- **When**: User tapped the Settings gear.
- **When**: User tapped Settings gear from Home.
- **Elements**:
- "Back" button, "Settings" heading
- Wallets: one row per wallet with its name (tap to rename inline) and an
`[x]` delete button, plus a "+ Add wallet" button
- Tracked Tokens: one row per tracked token with an `[x]` remove button,
plus a "+ Add token" button
- Display: "Show tracked tokens with zero balance" checkbox and a Theme
selector (System / Light / Dark)
- Network: network selector (Ethereum Mainnet / Sepolia Testnet); switching
resets the RPC and Blockscout endpoints to that network's defaults
- Ethereum RPC: endpoint URL input + "Save" button (validated against
`eth_chainId` before being saved)
- Blockscout API: endpoint URL input + "Save" button (validated against
`/stats` before being saved)
- "Settings" heading, "Back" button
- Wallets: "+ Add wallet" button
- Display: "Show tracked tokens with zero balance" checkbox
- Ethereum RPC: endpoint URL input + "Save" button
- Blockscout API: endpoint URL input + "Save" button
- Token Spam Protection:
- "Hide tokens with fewer than 1,000 holders" checkbox
- "Hide transactions from detected fraud contracts" checkbox
- "Hide dust transactions below N gwei" checkbox + threshold input
- "UTC Timestamps" checkbox
- Allowed Sites: list with remove buttons
- Denied Sites: list with remove buttons
- About: project link, license, author, version, release date, and the
commit, which links to the commit in the repository
- Debug: hidden until revealed, then an "Enable debug mode" checkbox that
turns on the red banner and verbose logging
- **Transitions**:
- "+ Add wallet" → **AddWallet**
- "+ Add token" → **SettingsAddToken**
- `[x]` on a wallet → **DeleteWallet**
- Tap wallet name → inline rename field (no screen change)
- `[x]` on a tracked token or a site → removes it in place (no screen
change)
- Ten clicks on the version → reveals the Debug well (no screen change)
- "Back" (or Settings gear again) → previous screen (Home)
- "Back" (or Settings gear again) → **Home**
#### DeleteWallet (`delete-wallet-confirm`)
#### SiteApproval
- **When**: User tapped the `[x]` next to a wallet in Settings.
- **Elements**:
- "Back" button, "Delete Wallet" heading
- Warning naming the wallet and stating that deletion is permanent and any
funds are unrecoverable without the recovery phrase
- Error line
- Password input
- "Confirm Delete" button
- **Transitions**:
- "Confirm Delete" (correct password, other wallets remain) → deletes the
wallet and its site permissions, then → **Settings** with a "Wallet
deleted." flash message
- "Confirm Delete" (correct password, last wallet) → deletes the wallet,
clears the selection and the navigation stack, then → **Welcome**
- Either way, the active address moves only if it belonged to the deleted
wallet, and `AUTISTMASK_ACTIVE_CHANGED` is broadcast when it does
(`src/shared/walletDelete.js`)
- "Confirm Delete" (wrong password) → "Wrong password." on the error line,
nothing deleted
- "Back" → previous screen (Settings)
#### SettingsAddToken (`settings-addtoken`)
- **When**: User tapped "+ Add token" in Settings. Tokens added here are tracked
across every address, unlike AddToken which is reached from one address.
- **Elements**:
- "Back" button, "Add Token" heading
- Instruction text
- "Top tokens:" quick-pick buttons (top 10 by market cap; already-tracked
tokens are disabled)
- "Or pick from top 100:" dropdown (already-tracked tokens are disabled) +
"Add selected" button
- "Or enter contract address:" input, a status line, and an "Add" button
- **Transitions**:
- Any of the three add paths, on success → adds the token and shows an
"Added SYMBOL" flash message (no screen change)
- A duplicate, a scam-listed address, or a failed contract lookup → flash
message, no screen change
- "Back" → previous screen (Settings)
#### SiteApproval (`approve-site`)
- **When**: A website requests wallet access via `eth_requestAccounts` or
`wallet_requestPermissions` and is on neither the allowed nor the denied list.
The background script prefers the toolbar popup (`action.openPopup()`) and
falls back to a separate popup window (`src/background/index.js`,
`requestApproval()`).
- **When**: A website requests wallet access via `eth_requestAccounts`. Opened
in a separate popup by the background script.
- **Elements**:
- "Connection Request" heading
- Phishing warning banner (shown when the hostname is on the phishing
blocklist)
- Site hostname (bold) + "wants to connect to your wallet"
- Site hostname (bold)
- Address that will be shared (color dot + full address + etherscan link)
- "Remember my choice for this site" checkbox
- "Allow" / "Deny" buttons
- **Transitions**:
- "Allow" / "Deny" → closes popup (returns result to background script; the
choice is persisted to the allowed or denied list when "Remember" is
checked)
- Popup closed without answering → treated as a denial
- "Allow" / "Deny" → closes popup (returns result to background script)
#### TxApproval (`approve-tx`)
#### TxApproval
- **When**: A connected website requests a transaction via
`eth_sendTransaction`. Always opened in a separate popup window by the
background script (`windows.create()`), because the request is triggered
programmatically rather than by a user gesture.
`eth_sendTransaction`. Opened via the toolbar popup by the background script.
- **Elements**:
- "Transaction Request" heading
- Phishing warning banner (shown when the hostname is on the phishing
blocklist)
- Site hostname (bold) + "wants to send a transaction"
- Decoded action (if calldata is recognized): action name, token details,
amounts, steps, deadline (see Transaction Decoding)
- From: color dot + full address + etherscan link
- Contract: color dot + full address + etherscan link (or "contract
- To/Contract: color dot + full address + etherscan link (or "contract
creation"), token symbol label if known
- Value: amount in ETH (4 decimal places, USD in parentheses)
- Value: amount in ETH (4 decimal places)
- Raw data: full calldata displayed inline (shown if present)
- Password input and an error line
- Password input
- "Confirm" / "Reject" buttons
- **Transitions**:
- "Confirm" (correct password) → decrypts and signs in the popup, hands the
signed transaction to the background to broadcast, then → **WaitTx** in
the same popup window
- "Confirm" (wrong password) → error line, no screen change
- "Confirm" (with password) → closes popup (returns result to background)
- "Reject" → closes popup (returns rejection to background)
- Popup window closed without answering → the request is rejected with
EIP-1193 code 4001
#### SignApproval (`approve-sign`)
#### SignApproval
- **When**: A connected website requests a message signature via
`personal_sign`, `eth_sign`, or `eth_signTypedData_v4`. Opened the same way as
TxApproval, in a separate popup window.
`personal_sign`, `eth_sign`, or `eth_signTypedData_v4`. Opened via the toolbar
popup by the background script.
- **Elements**:
- "Signature Request" heading
- Phishing warning banner (shown when the hostname is on the phishing
blocklist)
- Site hostname (bold) + "wants you to sign a message"
- Danger warning box (shown for `eth_sign`, which signs a raw hash)
- Type: "Personal message" or "Typed data (EIP-712)"
- From: color dot + full address + etherscan link
- Message: decoded UTF-8 text (personal_sign) or formatted domain/type/
message fields (EIP-712 typed data)
- Password input and an error line
- Password input
- "Sign" / "Reject" buttons
- **Transitions**:
- "Sign" (correct password) → signs locally → closes popup (returns
signature)
- "Sign" (wrong password, or a signing failure) → error line, no screen
change
- "Sign" (with password) → signs locally → closes popup (returns signature)
- "Reject" → closes popup (returns rejection to background)
- Popup window closed without answering → the request is rejected with
EIP-1193 code 4001
### External Services
@@ -980,7 +815,6 @@ hardcoded test phrase.
- Create new HD wallet (generates 12-word recovery phrase)
- Import HD wallet from existing 12 or 24 word recovery phrase
- Import single-address wallet from private key
- Import multi-address wallet from an extended private key (`xprv`)
- Add multiple addresses within an HD wallet
- Manage multiple wallets simultaneously
- View ETH balance per address
@@ -1152,7 +986,7 @@ Currently supported:
### Transactions
- [x] Gas estimation and fee display before confirming
- [ ] Gas estimation and fee display before confirming
### Testing

View File

@@ -46,13 +46,9 @@ undefined identifiers, which is how
- 2026-08-11: `script/verify-build` diagnostics corrected: the both-markers
message now states what is and is not proven, an unreadable bundle is
diagnosed as an I/O fault rather than as changed output, the `*.js` assumption
lives only in `build.js`, and the unlisted-bundle scan hard-fails when it
cannot enumerate `dist/`
diagnosed as an I/O fault rather than as changed output, and the `*.js`
assumption lives only in `build.js`
([#180](https://git.eeqj.de/sneak/AutistMask/issues/180)).
- 2026-08-11: README Screen Map rebuilt from the code — every screen, element
and transition re-verified against `src/popup/`
([#164](https://git.eeqj.de/sneak/AutistMask/issues/164)).
- 2026-08-11: `docs/README.md` rewritten against the code: no competitor names,
all five network destinations documented, password/Settings/Add Wallet
sections corrected ([#163](https://git.eeqj.de/sneak/AutistMask/issues/163)).

View File

@@ -31,10 +31,9 @@ function repoRelative(p) {
// searching the minified text, it does not depend on what survived minification.
//
// The ".js" filter below is the only place that assumption lives:
// script/verify-build searches every file and symlink under dist/ for a
// marker, without filtering by extension, and hard-fails if it cannot walk the
// whole tree, so a bundle emitted under some other extension fails there as
// unlisted rather than escaping both checks at once.
// script/verify-build searches every file under dist/ for a marker, without
// filtering by extension, so a bundle emitted under some other extension fails
// there as unlisted rather than escaping both checks at once.
function outputsContainingAuditedModule(metafile) {
return Object.entries(metafile.outputs)
.filter(([outFile, info]) => {

View File

@@ -53,26 +53,6 @@ has_marker() {
esac
}
# Does the manifest list the path $1, as a whole line? Same discipline as
# has_marker: exit 0 and 1 are answers about the manifest, exit 2 means the
# manifest could not be read and is not an answer at all. Without this, an
# unreadable manifest reads as "this file is not listed" and every emitted
# bundle gets reported as an unlisted one.
is_listed() {
_il_status=0
grep -q -x -F -e "$1" -- "$MANIFEST" || _il_status=$?
case "$_il_status" in
0) return 0 ;;
1) return 1 ;;
*)
fail "grep exited $_il_status reading $MANIFEST, so it could not be
searched and nothing was established about which bundles it lists. That is
a permissions or I/O fault on the manifest, not a stale manifest. Refusing
to report success."
;;
esac
}
# Read one bundle's DEBUG state into MARKER. Exactly one marker must be
# present. Both means the ternary in constants.js was never folded, which is
# what happens when the __BUILD_DEBUG__ define goes missing from build.js:
@@ -119,34 +99,11 @@ read_marker() {
# once, which is the correlated blind spot the two-source design exists to
# avoid. Every file under dist/ is searched, so build.js's filter is the only
# place the assumption lives and this check is what catches it being wrong.
#
# That claim only holds if the walk is exhaustive, so two things are enforced
# here rather than assumed:
#
# - find's exit status is checked. A subtree it cannot descend is reported on
# stderr and then simply missing from the listing, so an unchecked status
# turns "could not look" into "nothing was there" — the same conflation
# has_marker exists to prevent. The status cannot be read off a pipeline
# ending in sort, so the sort is a separate step.
# - symlinks are walked too (-type l), not skipped. A marker-carrying bundle
# reachable under an unlisted path in dist/ is a stale manifest whether the
# path is a link or a file, and grep reads through the link. A link that
# cannot be read through — dangling, or pointing at a directory — fails
# hard via has_marker's exit-2 path, which is the fail-closed answer: the
# build emits neither, so their DEBUG state is unproven, not fine.
check_unlisted_bundles() {
_find_status=0
_listing="$(find dist \( -type f -o -type l \) -print)" || _find_status=$?
[ "$_find_status" -eq 0 ] ||
fail "find exited $_find_status enumerating dist/, so part of the tree
was never walked and nothing was established about the files in it. Any
unlisted bundle there went unchecked. That is a permissions or I/O fault on
the artifact, not a stale manifest. Refusing to report success."
_listing="$(printf '%s\n' "$_listing" | sort)"
_listing="$(find dist -type f | sort)"
while read -r _file; do
[ -n "$_file" ] || continue
if is_listed "$_file"; then
if grep -q -x -F -e "$_file" -- "$MANIFEST"; then
continue
fi
if has_marker "$MARKER_ON" "$_file" ||