Compare commits
2 Commits
3350105a48
...
0e3dd14001
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e3dd14001 | ||
| b9bc226ae1 |
404
README.md
404
README.md
@@ -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
|
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).
|
use a visible border, padding, and a hover state (invert to white-on-black).
|
||||||
Text that triggers an action (e.g. "Import private key") uses an underline. No
|
Text that triggers an action (e.g. "Add additional wallet...") uses an
|
||||||
invisible hit targets, no bare text that happens to have a click handler. If it
|
underline. No invisible hit targets, no bare text that happens to have a click
|
||||||
does something when you click it, it must look like it does something when you
|
handler. If it does something when you click it, it must look like it does
|
||||||
click it.
|
something when you click it.
|
||||||
|
|
||||||
#### Display Consistency
|
#### Display Consistency
|
||||||
|
|
||||||
@@ -334,12 +334,18 @@ attack.
|
|||||||
|
|
||||||
The core hierarchy is **Wallets → Addresses**:
|
The core hierarchy is **Wallets → Addresses**:
|
||||||
|
|
||||||
- A **wallet** is either:
|
- A **wallet** is one of three types:
|
||||||
- An **HD wallet** (recovery phrase): generates multiple addresses from a
|
- An **HD wallet** (`type: "hd"`, recovery phrase): generates multiple
|
||||||
single 12/24 word recovery phrase using BIP-39/BIP-44 derivation. The user
|
addresses from a single 12/24 word recovery phrase using BIP-39/BIP-44
|
||||||
can add more addresses with a "+" button.
|
derivation. The user can add more addresses with a "+" button.
|
||||||
- A **key wallet** (private key): a single address imported directly from a
|
- A **key wallet** (`type: "key"`, private key): a single address imported
|
||||||
private key. No "+" button since there is only one address.
|
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.
|
||||||
- An **address** holds ETH and any user-added ERC-20 tokens.
|
- An **address** holds ETH and any user-added ERC-20 tokens.
|
||||||
- The user can have multiple wallets, each with multiple addresses (HD) or a
|
- The user can have multiple wallets, each with multiple addresses (HD) or a
|
||||||
single address (key).
|
single address (key).
|
||||||
@@ -354,95 +360,140 @@ menus.
|
|||||||
|
|
||||||
### Screen Map
|
### Screen Map
|
||||||
|
|
||||||
Navigation uses a stack model (like iOS): each action pushes a screen onto the
|
Navigation uses a stack model (like iOS): each forward action pushes the current
|
||||||
stack, and "Back" pops it. The root screen is either Welcome (no wallets) or
|
screen onto `state.viewStack`, and "Back" pops it (`pushCurrentView()` and
|
||||||
Home (has wallets). Screens are listed below with their elements and
|
`goBack()` in `src/popup/views/helpers.js`). The root screen is either Welcome
|
||||||
transitions.
|
(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`.
|
||||||
|
|
||||||
#### Welcome
|
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.
|
||||||
|
|
||||||
- **When**: No wallets exist yet.
|
Closing and reopening the popup returns to the screen the user was last on only
|
||||||
- **Elements**: "AutistMask" heading, brief intro text, "Add wallet" button.
|
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
|
||||||
- **Transitions**:
|
- **Transitions**:
|
||||||
- "Add wallet" → **AddWallet**
|
- "Add wallet" → **AddWallet**
|
||||||
|
|
||||||
#### Home
|
#### Home (`main`)
|
||||||
|
|
||||||
- **When**: At least one wallet exists. This is the root screen.
|
- **When**: At least one wallet exists. This is the root screen.
|
||||||
- **Elements**:
|
- **Elements**:
|
||||||
- Header: "AutistMask", Settings gear button
|
- Active address ETH balance (large) + USD value in parentheses
|
||||||
- Active address ETH balance (large) + USD value (inline parentheses)
|
- "Total:" USD value across ETH and all tracked tokens of the active address
|
||||||
- Total USD value across all tokens (small text)
|
|
||||||
- Active address (color dot, full address, etherscan link, tap to copy)
|
- Active address (color dot, full address, etherscan link, tap to copy)
|
||||||
- Send / Receive quick-action buttons
|
- Send / Receive quick-action buttons, both acting on the active address
|
||||||
- ETH/USD price display
|
- ETH/USD price display
|
||||||
- Wallet list: each wallet shows name (tap to rename), "+" button (HD only),
|
- Wallet list: each wallet shows its name (tap to rename inline) and a "+"
|
||||||
and its addresses with color dots, balances, and `[info]` buttons
|
button for HD and xprv wallets, then one block per address with "Address
|
||||||
- Recent transactions across all addresses (merged, deduplicated, filtered)
|
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
|
||||||
- "Add additional wallet..." link at bottom
|
- "Add additional wallet..." link at bottom
|
||||||
- **Transitions**:
|
- **Transitions**:
|
||||||
- Tap address row → sets active address (no screen change)
|
- 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)
|
||||||
- `[info]` on address → **AddressDetail**
|
- `[info]` on address → **AddressDetail**
|
||||||
- "Send" → **Send** (selects active address)
|
- "Send" → **Send** (refuses with a flash message on a zero balance)
|
||||||
- "Receive" → **Receive** (shows active address QR)
|
- "Receive" → **Receive** (shows active address QR)
|
||||||
- "+" on wallet → derives next address inline
|
- Tap home tx row → **TransactionDetail**
|
||||||
- "Add additional wallet..." → **AddWallet**
|
- "Add additional wallet..." → **AddWallet**
|
||||||
- Settings gear → **Settings** (toggles; tap again to return)
|
- Settings gear → **Settings** (toggles; tap again to return)
|
||||||
- Tap home tx row → **AddressDetail** (for the address involved)
|
|
||||||
|
|
||||||
#### AddWallet
|
#### AddWallet (`add-wallet`)
|
||||||
|
|
||||||
- **When**: User wants to add a new wallet (from Home, Welcome, or Settings).
|
- **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.
|
||||||
- **Elements**:
|
- **Elements**:
|
||||||
- "Add Wallet" heading, "Back" button
|
- "Back" button, "Add Wallet" heading
|
||||||
- Instruction text
|
- Three tabs — "From Phrase" (`tab-mnemonic`), "From Key" (`tab-privkey`),
|
||||||
- Die button `[die]` (generates random recovery phrase)
|
"From xprv" (`tab-xprv`) — each showing its own form section:
|
||||||
- Recovery phrase textarea
|
- **From Phrase**: instruction text, a die button that generates a
|
||||||
- Backup warning box (shown after die is clicked)
|
random recovery phrase, a recovery phrase textarea, and a backup
|
||||||
- Password + confirm password inputs
|
warning box that becomes visible once the die button has been used
|
||||||
- "Add" button
|
- **From Key**: instruction text and a masked private key input
|
||||||
- "Have a private key instead?" link
|
- **From xprv**: instruction text and a masked extended private key
|
||||||
- **Transitions**:
|
input
|
||||||
- "Add" (valid phrase + password) → **Home**
|
- Password + confirm password inputs, with a hint line whose wording depends
|
||||||
- "Back" → previous screen (Home or Welcome)
|
on the selected tab
|
||||||
- "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
|
- "Import" button
|
||||||
- **Transitions**:
|
- **Transitions**:
|
||||||
- "Import" (valid key + password) → **Home**
|
- "Import" with a valid entry and a matching password of at least 12
|
||||||
- "Back" → **AddWallet**
|
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)
|
||||||
|
|
||||||
#### AddressDetail
|
#### AddressDetail (`address`)
|
||||||
|
|
||||||
- **When**: User tapped `[info]` on an address from Home.
|
- **When**: User tapped `[info]` on an address from Home.
|
||||||
- **Elements**:
|
- **Elements**:
|
||||||
- "Back" button
|
- "Back" button
|
||||||
- Blockie identicon (48px, centered)
|
- Blockie identicon (48px, centered)
|
||||||
- Title: "Wallet Name — Address N"
|
- Title: "Wallet Name — Address N"
|
||||||
- ENS name (if resolved, bold with color dot)
|
- ENS name (if resolved, bold above the address)
|
||||||
- Full address (color dot, etherscan link, tap to copy)
|
- Full address (color dot, etherscan link, tap to copy)
|
||||||
- USD total for address
|
- USD total for address
|
||||||
- Balance list: ETH + tracked ERC-20 tokens (4 decimal places, USD inline).
|
- Balance list: ETH + tracked ERC-20 tokens (4 decimal places, USD inline).
|
||||||
Each balance row is clickable → **AddressToken**
|
Each balance row is clickable → **AddressToken**
|
||||||
- Send / Receive / + Token buttons
|
- Send / Receive / + Token buttons and a "···" menu button
|
||||||
|
- "···" dropdown containing a single "Export Private Key" entry
|
||||||
- Transaction list (with ENS resolution for counterparties)
|
- Transaction list (with ENS resolution for counterparties)
|
||||||
- **Transitions**:
|
- **Transitions**:
|
||||||
- Tap balance row → **AddressToken** (for that token)
|
- Tap balance row → **AddressToken** (for that token)
|
||||||
- "Send" → **Send**
|
- "Send" → **Send** (refuses with a flash message on a zero balance)
|
||||||
- "Receive" → **Receive**
|
- "Receive" → **Receive**
|
||||||
- "+ Token" → **AddToken**
|
- "+ Token" → **AddToken**
|
||||||
|
- "···" → "Export Private Key" → **ExportPrivKey**
|
||||||
- Tap transaction row → **TransactionDetail**
|
- Tap transaction row → **TransactionDetail**
|
||||||
- "Back" → **Home**
|
- "Back" → previous screen (Home)
|
||||||
|
|
||||||
#### AddressToken
|
#### 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`)
|
||||||
|
|
||||||
- **When**: User clicked a specific token balance on AddressDetail.
|
- **When**: User clicked a specific token balance on AddressDetail.
|
||||||
- **Elements**:
|
- **Elements**:
|
||||||
@@ -453,49 +504,64 @@ transitions.
|
|||||||
- USD total for this token
|
- USD total for this token
|
||||||
- Single token balance line (4 decimal places)
|
- Single token balance line (4 decimal places)
|
||||||
- Send / Receive buttons
|
- 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)
|
- Token-filtered transaction list (only this token's transfers)
|
||||||
- **Transitions**:
|
- **Transitions**:
|
||||||
- "Send" → **Send** (token pre-selected and locked in dropdown)
|
- "Send" → **Send** (token locked: the dropdown is replaced by a static
|
||||||
|
symbol and contract address)
|
||||||
- "Receive" → **Receive** (ERC-20 warning shown for non-ETH tokens)
|
- "Receive" → **Receive** (ERC-20 warning shown for non-ETH tokens)
|
||||||
- Tap transaction row → **TransactionDetail**
|
- Tap transaction row → **TransactionDetail**
|
||||||
- "Back" → **AddressDetail**
|
- "Back" → previous screen (AddressDetail)
|
||||||
|
|
||||||
#### Send
|
#### Send (`send`)
|
||||||
|
|
||||||
- **When**: User wants to send ETH or a token from this address.
|
- **When**: User wants to send ETH or a token, from Home, AddressDetail, or
|
||||||
|
AddressToken.
|
||||||
- **Elements**:
|
- **Elements**:
|
||||||
- "Send" heading, "Back" button
|
- "Back" button, "Send" heading
|
||||||
- From: address with color dot + etherscan link
|
- From: address with color dot + etherscan link
|
||||||
- What to send: token dropdown (or static display with contract address when
|
- What to send: token dropdown (or static display with contract address when
|
||||||
locked from AddressToken)
|
locked from AddressToken)
|
||||||
- To: address or ENS name input
|
- To: address or ENS name input, with an inline validation message
|
||||||
- Amount input with current balance display
|
- Amount input with current balance display
|
||||||
- "Review" button
|
- "Review" button, disabled until the recipient validates
|
||||||
- **Transitions**:
|
- **Transitions**:
|
||||||
- "Review" (valid inputs, ENS resolved) → **ConfirmTx**
|
- "Review" (valid inputs, ENS resolved) → **ConfirmTx**
|
||||||
- "Back" → **AddressToken** (if came from token view) or **AddressDetail**
|
- "Review" with an unresolvable ENS name or an invalid amount → flash
|
||||||
|
message, no screen change
|
||||||
|
- "Back" → previous screen (Home, AddressDetail, or AddressToken)
|
||||||
|
|
||||||
#### ConfirmTx
|
#### ConfirmTx (`confirm-tx`)
|
||||||
|
|
||||||
- **When**: User reviewed send details and is ready to authorize.
|
- **When**: User reviewed send details and is ready to authorize.
|
||||||
- **Elements**:
|
- **Elements**:
|
||||||
- "Confirm Transaction" heading, "Back" button
|
- "Back" button, "Confirm Transaction" heading
|
||||||
- Type: "Native ETH transfer" or "ERC-20 token transfer (SYMBOL)"
|
- Type: "Native ETH transfer" or "ERC-20 token transfer (SYMBOL)"
|
||||||
- Token contract: full address + etherscan link (ERC-20 only)
|
- Token contract: full address + etherscan link (ERC-20 only)
|
||||||
- From: blockie + color dot + full address + etherscan link + wallet title
|
- From: blockie + color dot + full address + etherscan link + wallet title
|
||||||
- To: blockie + color dot + full address + etherscan link + ENS name
|
- To: blockie + color dot + full address + etherscan link + ENS name
|
||||||
- Amount: value + symbol (USD in parentheses)
|
- Amount: value + symbol (USD in parentheses)
|
||||||
- Your balance: value + symbol (USD in parentheses)
|
- Your balance: value + symbol (USD in parentheses)
|
||||||
- Estimated network fee: ETH amount (USD in parentheses), fetched async
|
- Estimated network fee: "Estimating..." then the ETH amount (USD in
|
||||||
- Warnings (scam address, self-send)
|
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
|
||||||
- Errors (insufficient balance)
|
- Errors (insufficient balance)
|
||||||
- "Send" button (disabled if errors)
|
- Password: an inline field on this screen, not a modal, with its own error
|
||||||
|
line
|
||||||
|
- "Sign & Send" button (disabled if errors)
|
||||||
- **Transitions**:
|
- **Transitions**:
|
||||||
- "Send" → password modal → broadcast tx → **WaitTx**
|
- "Sign & Send" (correct password) → broadcast tx → **WaitTx**
|
||||||
- "Send" → password modal → broadcast fails → **ErrorTx**
|
- "Sign & Send" (correct password) → broadcast fails → **ErrorTx**
|
||||||
|
- "Sign & Send" (wrong password) → "Wrong password." on the password error
|
||||||
|
line, no screen change
|
||||||
- "Back" → **Send**
|
- "Back" → **Send**
|
||||||
|
|
||||||
#### WaitTx
|
#### WaitTx (`wait-tx`)
|
||||||
|
|
||||||
- **When**: Transaction has been broadcast, waiting for on-chain confirmation.
|
- **When**: Transaction has been broadcast, waiting for on-chain confirmation.
|
||||||
- **Elements**:
|
- **Elements**:
|
||||||
@@ -509,20 +575,24 @@ transitions.
|
|||||||
- Receipt found → **SuccessTx**
|
- Receipt found → **SuccessTx**
|
||||||
- 60 seconds without confirmation → **ErrorTx** (timeout message)
|
- 60 seconds without confirmation → **ErrorTx** (timeout message)
|
||||||
|
|
||||||
#### SuccessTx
|
#### SuccessTx (`success-tx`)
|
||||||
|
|
||||||
- **When**: Transaction confirmed on-chain.
|
- **When**: Transaction confirmed on-chain.
|
||||||
- **Elements**:
|
- **Elements**:
|
||||||
- "Transaction Confirmed" heading
|
- "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
|
- Amount + symbol
|
||||||
- To: color dot + full address + etherscan link
|
- To: color dot + full address + etherscan link
|
||||||
- Block number
|
- Block number
|
||||||
- Transaction hash: full hash (tap to copy) + etherscan link
|
- Transaction hash: full hash (tap to copy) + etherscan link
|
||||||
- "Done" button
|
- "Done" button
|
||||||
- **Transitions**:
|
- **Transitions**:
|
||||||
- "Done" → **AddressToken** (if `selectedToken` set) or **AddressDetail**
|
- "Done" in the approval popup → closes the popup window
|
||||||
|
- "Done" otherwise → resets the navigation stack, then → **AddressToken**
|
||||||
|
(if `selectedToken` set) or **AddressDetail**
|
||||||
|
|
||||||
#### ErrorTx
|
#### ErrorTx (`error-tx`)
|
||||||
|
|
||||||
- **When**: Transaction broadcast failed, or timed out waiting for confirmation.
|
- **When**: Transaction broadcast failed, or timed out waiting for confirmation.
|
||||||
- **Elements**:
|
- **Elements**:
|
||||||
@@ -534,24 +604,28 @@ transitions.
|
|||||||
full hash (tap to copy) + etherscan link
|
full hash (tap to copy) + etherscan link
|
||||||
- "Done" button
|
- "Done" button
|
||||||
- **Transitions**:
|
- **Transitions**:
|
||||||
- "Done" → **AddressToken** (if `selectedToken` set) or **AddressDetail**
|
- "Done" in the approval popup → closes the popup window
|
||||||
|
- "Done" otherwise → resets the navigation stack, then → **AddressToken**
|
||||||
|
(if `selectedToken` set) or **AddressDetail**
|
||||||
|
|
||||||
#### Receive
|
#### Receive (`receive`)
|
||||||
|
|
||||||
- **When**: User wants to receive funds at this address.
|
- **When**: User wants to receive funds at this address, from Home,
|
||||||
|
AddressDetail, or AddressToken.
|
||||||
- **Elements**:
|
- **Elements**:
|
||||||
- "Receive" heading, "Back" button
|
- "Back" button, "Receive" heading
|
||||||
- Instruction text
|
- Instruction text
|
||||||
- QR code encoding the address
|
- QR code encoding the address
|
||||||
- Full address (color dot, selectable, etherscan link)
|
- Full address (color dot, selectable, etherscan link)
|
||||||
- "Copy address" button
|
- "Copy address" button
|
||||||
- ERC-20 warning (shown when navigating from AddressToken for non-ETH token)
|
- ERC-20 warning (shown when navigating from AddressToken for non-ETH token)
|
||||||
- **Transitions**:
|
- **Transitions**:
|
||||||
- "Back" → **AddressToken** (if `selectedToken` set) or **AddressDetail**
|
- "Back" → previous screen (Home, AddressDetail, or AddressToken)
|
||||||
|
|
||||||
#### TransactionDetail
|
#### TransactionDetail (`transaction`)
|
||||||
|
|
||||||
- **When**: User tapped a transaction row from AddressDetail or AddressToken.
|
- **When**: User tapped a transaction row on Home, AddressDetail, or
|
||||||
|
AddressToken.
|
||||||
- **Elements** (grouped into logical blocks using light well containers; field
|
- **Elements** (grouped into logical blocks using light well containers; field
|
||||||
labels are self-explanatory so groups have no headings):
|
labels are self-explanatory so groups have no headings):
|
||||||
- "Transaction" heading, "Back" button
|
- "Transaction" heading, "Back" button
|
||||||
@@ -576,91 +650,182 @@ transitions.
|
|||||||
- Raw data (shown when calldata is present): full calldata in monospace
|
- Raw data (shown when calldata is present): full calldata in monospace
|
||||||
dashed border
|
dashed border
|
||||||
- **Transitions**:
|
- **Transitions**:
|
||||||
- "Back" → **AddressToken** (if `selectedToken` set) or **AddressDetail**
|
- "Back" → previous screen (Home, AddressDetail, or AddressToken)
|
||||||
|
|
||||||
#### AddToken
|
#### AddToken (`add-token`)
|
||||||
|
|
||||||
- **When**: User wants to track an ERC-20 token on this address.
|
- **When**: User wants to track an ERC-20 token, reached from "+ Token" on
|
||||||
|
AddressDetail.
|
||||||
- **Elements**:
|
- **Elements**:
|
||||||
- "Add Token" heading, "Back" button
|
- "Back" button, "Add Token" heading
|
||||||
- Instruction text (find contract address on Etherscan)
|
- Instruction text (find contract address on Etherscan)
|
||||||
- Contract address input
|
- Contract address input
|
||||||
- Token info preview (name, symbol — fetched from contract)
|
- Status line ("Looking up token...", cleared or replaced on failure)
|
||||||
- Common token quick-pick buttons
|
- Common token quick-pick buttons (top 25 by market cap), which fill the
|
||||||
|
contract address input
|
||||||
- "Add" button
|
- "Add" button
|
||||||
- **Transitions**:
|
- **Transitions**:
|
||||||
- "Add" (valid contract) → **AddressDetail**
|
- "Add" (valid contract) → tracks the token, pops the stack, and re-renders
|
||||||
- "Back" → **AddressDetail**
|
**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)
|
||||||
|
|
||||||
#### Settings
|
#### Settings (`settings`)
|
||||||
|
|
||||||
- **When**: User tapped Settings gear from Home.
|
- **When**: User tapped the Settings gear.
|
||||||
- **Elements**:
|
- **Elements**:
|
||||||
- "Settings" heading, "Back" button
|
- "Back" button, "Settings" heading
|
||||||
- Wallets: "+ Add wallet" button
|
- Wallets: one row per wallet with its name (tap to rename inline) and an
|
||||||
- Display: "Show tracked tokens with zero balance" checkbox
|
`[x]` delete button, plus a "+ Add wallet" button
|
||||||
- Ethereum RPC: endpoint URL input + "Save" button
|
- Tracked Tokens: one row per tracked token with an `[x]` remove button,
|
||||||
- Blockscout API: endpoint URL input + "Save" 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)
|
||||||
- Token Spam Protection:
|
- Token Spam Protection:
|
||||||
- "Hide tokens with fewer than 1,000 holders" checkbox
|
- "Hide tokens with fewer than 1,000 holders" checkbox
|
||||||
- "Hide transactions from detected fraud contracts" checkbox
|
- "Hide transactions from detected fraud contracts" checkbox
|
||||||
- "Hide dust transactions below N gwei" checkbox + threshold input
|
- "Hide dust transactions below N gwei" checkbox + threshold input
|
||||||
|
- "UTC Timestamps" checkbox
|
||||||
- Allowed Sites: list with remove buttons
|
- Allowed Sites: list with remove buttons
|
||||||
- Denied 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**:
|
- **Transitions**:
|
||||||
- "+ Add wallet" → **AddWallet**
|
- "+ Add wallet" → **AddWallet**
|
||||||
- "Back" (or Settings gear again) → **Home**
|
- "+ 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)
|
||||||
|
|
||||||
#### SiteApproval
|
#### DeleteWallet (`delete-wallet-confirm`)
|
||||||
|
|
||||||
- **When**: A website requests wallet access via `eth_requestAccounts`. Opened
|
- **When**: User tapped the `[x]` next to a wallet in Settings.
|
||||||
in a separate popup by the background script.
|
- **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()`).
|
||||||
- **Elements**:
|
- **Elements**:
|
||||||
- "Connection Request" heading
|
- "Connection Request" heading
|
||||||
- Site hostname (bold)
|
- Phishing warning banner (shown when the hostname is on the phishing
|
||||||
|
blocklist)
|
||||||
|
- Site hostname (bold) + "wants to connect to your wallet"
|
||||||
- Address that will be shared (color dot + full address + etherscan link)
|
- Address that will be shared (color dot + full address + etherscan link)
|
||||||
- "Remember my choice for this site" checkbox
|
- "Remember my choice for this site" checkbox
|
||||||
- "Allow" / "Deny" buttons
|
- "Allow" / "Deny" buttons
|
||||||
- **Transitions**:
|
- **Transitions**:
|
||||||
- "Allow" / "Deny" → closes popup (returns result to background script)
|
- "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
|
||||||
|
|
||||||
#### TxApproval
|
#### TxApproval (`approve-tx`)
|
||||||
|
|
||||||
- **When**: A connected website requests a transaction via
|
- **When**: A connected website requests a transaction via
|
||||||
`eth_sendTransaction`. Opened via the toolbar popup by the background script.
|
`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.
|
||||||
- **Elements**:
|
- **Elements**:
|
||||||
- "Transaction Request" heading
|
- "Transaction Request" heading
|
||||||
|
- Phishing warning banner (shown when the hostname is on the phishing
|
||||||
|
blocklist)
|
||||||
- Site hostname (bold) + "wants to send a transaction"
|
- Site hostname (bold) + "wants to send a transaction"
|
||||||
- Decoded action (if calldata is recognized): action name, token details,
|
- Decoded action (if calldata is recognized): action name, token details,
|
||||||
amounts, steps, deadline (see Transaction Decoding)
|
amounts, steps, deadline (see Transaction Decoding)
|
||||||
- From: color dot + full address + etherscan link
|
- From: color dot + full address + etherscan link
|
||||||
- To/Contract: color dot + full address + etherscan link (or "contract
|
- Contract: color dot + full address + etherscan link (or "contract
|
||||||
creation"), token symbol label if known
|
creation"), token symbol label if known
|
||||||
- Value: amount in ETH (4 decimal places)
|
- Value: amount in ETH (4 decimal places, USD in parentheses)
|
||||||
- Raw data: full calldata displayed inline (shown if present)
|
- Raw data: full calldata displayed inline (shown if present)
|
||||||
- Password input
|
- Password input and an error line
|
||||||
- "Confirm" / "Reject" buttons
|
- "Confirm" / "Reject" buttons
|
||||||
- **Transitions**:
|
- **Transitions**:
|
||||||
- "Confirm" (with password) → closes popup (returns result to background)
|
- "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
|
||||||
- "Reject" → closes popup (returns rejection to background)
|
- "Reject" → closes popup (returns rejection to background)
|
||||||
|
- Popup window closed without answering → the request is rejected with
|
||||||
|
EIP-1193 code 4001
|
||||||
|
|
||||||
#### SignApproval
|
#### SignApproval (`approve-sign`)
|
||||||
|
|
||||||
- **When**: A connected website requests a message signature via
|
- **When**: A connected website requests a message signature via
|
||||||
`personal_sign`, `eth_sign`, or `eth_signTypedData_v4`. Opened via the toolbar
|
`personal_sign`, `eth_sign`, or `eth_signTypedData_v4`. Opened the same way as
|
||||||
popup by the background script.
|
TxApproval, in a separate popup window.
|
||||||
- **Elements**:
|
- **Elements**:
|
||||||
- "Signature Request" heading
|
- "Signature Request" heading
|
||||||
|
- Phishing warning banner (shown when the hostname is on the phishing
|
||||||
|
blocklist)
|
||||||
- Site hostname (bold) + "wants you to sign a message"
|
- 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)"
|
- Type: "Personal message" or "Typed data (EIP-712)"
|
||||||
- From: color dot + full address + etherscan link
|
- From: color dot + full address + etherscan link
|
||||||
- Message: decoded UTF-8 text (personal_sign) or formatted domain/type/
|
- Message: decoded UTF-8 text (personal_sign) or formatted domain/type/
|
||||||
message fields (EIP-712 typed data)
|
message fields (EIP-712 typed data)
|
||||||
- Password input
|
- Password input and an error line
|
||||||
- "Sign" / "Reject" buttons
|
- "Sign" / "Reject" buttons
|
||||||
- **Transitions**:
|
- **Transitions**:
|
||||||
- "Sign" (with password) → signs locally → closes popup (returns signature)
|
- "Sign" (correct password) → signs locally → closes popup (returns
|
||||||
|
signature)
|
||||||
|
- "Sign" (wrong password, or a signing failure) → error line, no screen
|
||||||
|
change
|
||||||
- "Reject" → closes popup (returns rejection to background)
|
- "Reject" → closes popup (returns rejection to background)
|
||||||
|
- Popup window closed without answering → the request is rejected with
|
||||||
|
EIP-1193 code 4001
|
||||||
|
|
||||||
### External Services
|
### External Services
|
||||||
|
|
||||||
@@ -815,6 +980,7 @@ hardcoded test phrase.
|
|||||||
- Create new HD wallet (generates 12-word recovery phrase)
|
- Create new HD wallet (generates 12-word recovery phrase)
|
||||||
- Import HD wallet from existing 12 or 24 word recovery phrase
|
- Import HD wallet from existing 12 or 24 word recovery phrase
|
||||||
- Import single-address wallet from private key
|
- Import single-address wallet from private key
|
||||||
|
- Import multi-address wallet from an extended private key (`xprv`)
|
||||||
- Add multiple addresses within an HD wallet
|
- Add multiple addresses within an HD wallet
|
||||||
- Manage multiple wallets simultaneously
|
- Manage multiple wallets simultaneously
|
||||||
- View ETH balance per address
|
- View ETH balance per address
|
||||||
@@ -986,7 +1152,7 @@ Currently supported:
|
|||||||
|
|
||||||
### Transactions
|
### Transactions
|
||||||
|
|
||||||
- [ ] Gas estimation and fee display before confirming
|
- [x] Gas estimation and fee display before confirming
|
||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
|
|
||||||
|
|||||||
9
TODO.md
9
TODO.md
@@ -44,6 +44,15 @@ undefined identifiers, which is how
|
|||||||
|
|
||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
|
- 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/`
|
||||||
|
([#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,
|
- 2026-08-11: `docs/README.md` rewritten against the code: no competitor names,
|
||||||
all five network destinations documented, password/Settings/Add Wallet
|
all five network destinations documented, password/Settings/Add Wallet
|
||||||
sections corrected ([#163](https://git.eeqj.de/sneak/AutistMask/issues/163)).
|
sections corrected ([#163](https://git.eeqj.de/sneak/AutistMask/issues/163)).
|
||||||
|
|||||||
6
build.js
6
build.js
@@ -29,6 +29,12 @@ function repoRelative(p) {
|
|||||||
// reports every input that contributed to an output in the metafile, which is
|
// reports every input that contributed to an output in the metafile, which is
|
||||||
// the authoritative answer to "is constants.js in this bundle" — unlike
|
// the authoritative answer to "is constants.js in this bundle" — unlike
|
||||||
// searching the minified text, it does not depend on what survived minification.
|
// 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.
|
||||||
function outputsContainingAuditedModule(metafile) {
|
function outputsContainingAuditedModule(metafile) {
|
||||||
return Object.entries(metafile.outputs)
|
return Object.entries(metafile.outputs)
|
||||||
.filter(([outFile, info]) => {
|
.filter(([outFile, info]) => {
|
||||||
|
|||||||
@@ -34,16 +34,51 @@ fail() {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Is the literal $1 present in the file $2? Match (grep exit 0) and no-match
|
||||||
|
# (exit 1) are answers about the emitted output. Anything else (exit 2: the
|
||||||
|
# file could not be read) is not an answer at all, and must not be reported as
|
||||||
|
# "no marker" — that would blame the bundle for a permissions or I/O fault.
|
||||||
has_marker() {
|
has_marker() {
|
||||||
grep -q -F "$1" "$2" 2>/dev/null
|
_hm_status=0
|
||||||
|
grep -q -F -e "$1" -- "$2" || _hm_status=$?
|
||||||
|
case "$_hm_status" in
|
||||||
|
0) return 0 ;;
|
||||||
|
1) return 1 ;;
|
||||||
|
*)
|
||||||
|
fail "grep exited $_hm_status reading $2, so the file could not be
|
||||||
|
searched and its DEBUG state was not checked at all. That is a permissions
|
||||||
|
or I/O fault on the artifact, not a change in the emitted output. Refusing
|
||||||
|
to report success."
|
||||||
|
;;
|
||||||
|
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
|
# 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
|
# 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:
|
# what happens when the __BUILD_DEBUG__ define goes missing from build.js:
|
||||||
# DEBUG stops being known at build time and the debug branch is live again.
|
# DEBUG stops being known at build time. Neither means we are reading output
|
||||||
# Neither means we are reading output we do not understand. Both are hard
|
# we do not understand. Both are hard failures; neither is ever treated as
|
||||||
# failures; neither is ever treated as absence of a problem.
|
# absence of a problem.
|
||||||
read_marker() {
|
read_marker() {
|
||||||
_file="$1"
|
_file="$1"
|
||||||
_on=no
|
_on=no
|
||||||
@@ -52,9 +87,14 @@ read_marker() {
|
|||||||
if has_marker "$MARKER_OFF" "$_file"; then _off=yes; fi
|
if has_marker "$MARKER_OFF" "$_file"; then _off=yes; fi
|
||||||
|
|
||||||
if [ "$_on" = yes ] && [ "$_off" = yes ]; then
|
if [ "$_on" = yes ] && [ "$_off" = yes ]; then
|
||||||
fail "$_file carries both debug markers, so the build-time DEBUG value
|
fail "$_file carries both debug markers, so DEBUG was not resolved at
|
||||||
was never resolved and the debug branch is still live. Check that build.js
|
build time: the ternary in src/shared/constants.js survived into the
|
||||||
still defines __BUILD_DEBUG__."
|
emitted output. This does not mean the debug branch is live in this
|
||||||
|
artifact: an unresolved __BUILD_DEBUG__ is undeclared in extension
|
||||||
|
context, so DEBUG evaluates to false at runtime. It does mean the
|
||||||
|
release/debug distinction is no longer enforced at build time, and which
|
||||||
|
way that fallback happens to evaluate is then an accident a refactor can
|
||||||
|
flip. Check that build.js still defines __BUILD_DEBUG__."
|
||||||
fi
|
fi
|
||||||
if [ "$_on" = no ] && [ "$_off" = no ]; then
|
if [ "$_on" = no ] && [ "$_off" = no ]; then
|
||||||
fail "$_file carries no debug marker, so its DEBUG state cannot be
|
fail "$_file carries no debug marker, so its DEBUG state cannot be
|
||||||
@@ -70,13 +110,43 @@ read_marker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# The manifest says which bundles must carry a marker. This says no other
|
# The manifest says which bundles must carry a marker. This says no other
|
||||||
# emitted bundle may carry one, which catches a manifest that has gone stale
|
# emitted file may carry one, which catches a manifest that has gone stale
|
||||||
# or short rather than trusting whatever it happens to list.
|
# or short rather than trusting whatever it happens to list.
|
||||||
|
#
|
||||||
|
# Deliberately unfiltered by extension. build.js selects manifest entries with
|
||||||
|
# an endsWith(".js") test; repeating that literal here would mean a bundle
|
||||||
|
# emitted under some other extension escaped the manifest AND this check at
|
||||||
|
# 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() {
|
check_unlisted_bundles() {
|
||||||
_listing="$(find dist -type f -name '*.js' | sort)"
|
_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)"
|
||||||
|
|
||||||
while read -r _file; do
|
while read -r _file; do
|
||||||
[ -n "$_file" ] || continue
|
[ -n "$_file" ] || continue
|
||||||
if grep -q -x -F "$_file" "$MANIFEST"; then
|
if is_listed "$_file"; then
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
if has_marker "$MARKER_ON" "$_file" ||
|
if has_marker "$MARKER_ON" "$_file" ||
|
||||||
@@ -113,12 +183,18 @@ main() {
|
|||||||
fail "$MANIFEST is empty, so no emitted bundle was found to contain
|
fail "$MANIFEST is empty, so no emitted bundle was found to contain
|
||||||
src/shared/constants.js. That is never correct, so it is a failure and not
|
src/shared/constants.js. That is never correct, so it is a failure and not
|
||||||
a pass."
|
a pass."
|
||||||
|
[ -r "$MANIFEST" ] ||
|
||||||
|
fail "$MANIFEST is not readable, so nothing was inspected. That is a
|
||||||
|
permissions or I/O fault, not a pass."
|
||||||
|
|
||||||
count=0
|
count=0
|
||||||
while read -r file; do
|
while read -r file; do
|
||||||
[ -n "$file" ] || continue
|
[ -n "$file" ] || continue
|
||||||
[ -f "$file" ] ||
|
[ -f "$file" ] ||
|
||||||
fail "$MANIFEST lists $file, which does not exist."
|
fail "$MANIFEST lists $file, which does not exist."
|
||||||
|
[ -s "$file" ] ||
|
||||||
|
fail "$MANIFEST lists $file, which is empty. An empty bundle
|
||||||
|
carries no marker and proves nothing, so this is a failure and not a pass."
|
||||||
read_marker "$file"
|
read_marker "$file"
|
||||||
[ "$MARKER" = "$expected" ] ||
|
[ "$MARKER" = "$expected" ] ||
|
||||||
fail "$file is $MARKER but this build expects $expected."
|
fail "$file is $MARKER but this build expects $expected."
|
||||||
|
|||||||
Reference in New Issue
Block a user