Commit graph

557 commits

Author SHA1 Message Date
Local Dev
c79a513836 Aegis: a connected site keeps the wallet the user approved
Dapp calls resolved their wallet afresh every time: Ethereum took the
first ready wallet on the site's chain, Solana and Tron the sidebar
selection. A site connected to wallet B was served wallet A, choosing
another wallet in the sidebar re-pointed every connected Solana/Tron
site and told it the new address, and a connected site could list
every EVM wallet's address by looping wallet_switchEthereumChain and
reading the account after each switch.

Grants now record the wallet id and address the user approved, and
calls use exactly that wallet (older grants are bound on first use; a
missing wallet is an error, not a substitute). A switch to a chain
whose wallet has a different address is asked for. A site can no
longer "add" a built-in chain id with its own RPC and get a second
mainnet wallet; chainMeta has no chainId for built-in networks, so
that check never matched.
2026-10-04 04:05:45 +02:00
Local Dev
bd6e990598 Aegis: BCH payments list only the payees and show a site's OP_RETURN data
The HD wallet's plan listed the change output as a recipient with no
address, so a dapp payment overlay showed "To #2: undefined" and an
Amount and Total inflated by the change; the imported wallet's total
counted change and left out the fee. Plans now list payees only, with
total = payees + fee.

A site's memo went on-chain as OP_RETURN data without appearing on the
overlay, and could ride on a silent allowance payment. It is now a row,
and a payment carrying data always asks. A 32-byte-hash cashaddr was
forced into a 20-byte template, producing an unspendable script; it is
refused.
2026-10-04 04:01:58 +02:00
Local Dev
df7f26552a Aegis: judge EIP-712 risk from its structure and encode it strictly
Non-Permit typed data was flagged only when its primaryType was on a
short list (Seaport, SafeTx, ...); any other order, relay or
account-abstraction type got a plain Sign button and no PIN. Every
signed field is now listed with its declared type, and a payload that
names an address other than the user's and the verifying contract
together with an amount, or carries raw bytes, gets the danger button
and the PIN; text-only payloads stay ordinary.

The encoder signed "false" as true, turned non-hex characters into zero
bytes, wrapped integers past their width (2^256+5 signed as 5) and
signed a non-array as an empty array, each while the overlay showed
the original value. Such input is now refused before any overlay.
Domain rows and the chain check use only the fields EIP712Domain
declares; others are labelled as not signed.
2026-10-04 03:59:28 +02:00
Local Dev
cc8a87c5d6 Aegis: dapp overlays show fees and flag risky Solana, Ethereum and Tron calls
Solana: a ComputeBudget price the site added was paid on top of the
base fee but shown as "program ComputeB...: not decoded", so a
transaction could burn the balance in priority fees behind a plain
Sign button. The maximum network fee is now a row, and Assign, durable
nonces, Approve/ApproveChecked, SetAuthority, closing a token account
to someone else and very high fees get a warning and the danger button.
signAndSend also requires one signature slot per required signer.

Ethereum: only allowances of 2^255 and up counted as unlimited; 2^96
and up now does, and Permit2 approve, increaseApproval, NFT
safeTransferFrom and multicall are decoded. The estimate shown was
gas x the node's price even when the site set a far higher tip, which
is what is actually paid; it now uses base fee + the real tip (or the
full legacy gasPrice) and warns when the site's fee is far above the
network's or a fifth of the balance. A personal_sign over 32 raw bytes
is a hash a Safe or an order book will take as approval of something
unseen, so it gets the danger button and the PIN.

Tron: TRC10 sent along with a contract call (call_token_value) was
never read, contract types Aegis does not decode were shown by name as
if harmless, a truncated TRC20 call rendered as "undefined", and the
validity window was hidden. Those are now shown, flagged or refused;
the TronGrid draft check also refuses a memo, a permission id or an
expiration more than a day away.
2026-10-04 03:56:45 +02:00
Local Dev
d38da383d9 Aegis: stay-unlocked needs a real keystore and the right password
Remember-me sealed the master password with whatever safeStorage
offered, which on Linux without a keyring is a constant key, i.e. the
password in the clear in the add-on store; and it stored any string
without checking it. It now uses the same keystore test as the PIN,
verifies the password with the vault first, and drops a blob sealed
under no real keystore. Settings says that remember-me leaves the
master password readable to anything running as the user, which the
PIN's TPM protection does not change.
2026-10-04 03:49:40 +02:00
Local Dev
e72c0ed96b Aegis: check every BTC/DGB input against its previous transaction
Coin selection, change and the fee on the overlay came from the
Electrum server's listunspent values, and a legacy signature does not
commit to the value it spends. A server that under-reported a P2PKH
coin made Aegis sign away the difference as fee: a 1,000,000 sat coin
reported as 100,000 produced a transaction paying 901,180 sat while
the overlay said 1,180. Segwit v0 commits only to its own input, which
leaves the two-request variant open.

Every non-taproot input's previous transaction is now fetched, its txid
recomputed, and its output's value and script compared with the plan;
the fee of the finalized PSBT must equal the approved one.
2026-10-04 03:49:39 +02:00
Local Dev
3264c6d019 Aegis: WizardConnect relay keys from the real root, overlay names the pairing origin
mountWallet zeroed the vault root after mounting, but the WizardConnect
adapter kept a reference to that same buffer and read it again for
every new pairing's relay key. Every pairing made after mount therefore
got a Nostr identity derived from 32 zero bytes and the pairing URI
alone, so anyone who saw the URI (the QR, a script on the dapp page)
could read the relay traffic, xpubs included, and speak as the wallet.
The adapter now gets, and keeps, its own copy.

The signing overlay and the PIN request named the dapp by its own
userPrompt, so a dapp paired once could present itself as any site.
The pairing origin the host verified is now recorded per URI and shown
instead; the dapp's text is a quoted row with invisible and bidi
characters removed. One sign request per connection may be on screen
at a time, and revoking a site in Aegis ends its pairings too.
2026-10-04 03:45:34 +02:00
Local Dev
561cb122ea Vault PIN: tie it to the TPM and never store it unsealed
Theseus's own quick-unlock PIN had the same limit as Aegis's: once the
DPAPI seal is opened (as the user, or from a disk image plus the
Windows password) the 6-digit PIN falls to an offline search. The PIN
is now also the authorization value of a Platform Crypto Provider TPM
key whose secret is mixed into the wrapping key, so the chip's lockout
bounds guessing; lib/tpm-pin.cjs is the same module Aegis uses.

set() now refuses when there is no real OS keystore (Linux basic_text
included) instead of writing the blob in the clear, an unsealed record
from an older build is deleted, and Settings says what the PIN actually
protects against on this machine.
2026-10-04 03:42:02 +02:00
Local Dev
cda17fc885 Aegis 0.32.0: tie the PIN to the TPM, never store it unsealed
A 6-digit PIN behind PBKDF2 + DPAPI falls in minutes to anything that
can open DPAPI (malware running as the user, a disk image plus the
Windows password). The PIN is now also the authorization value of a
TPM key from the Microsoft Platform Crypto Provider; the key releases a
secret mixed with PBKDF2(pin), so the stored blob alone opens nothing
and the chip's own lockout (32 failures, then one per 10 minutes)
limits guesses however the blob was obtained. Reached through Windows
PowerShell's CNG classes with the PIN on stdin, so no native module.
Machines without a TPM keep the software PIN, and Settings now says
plainly what that protects against.

A PIN is no longer stored when there is no real OS keystore (including
Linux's basic_text backend, whose key is a constant); a pre-0.31 plain
blob is sealed or deleted and remembered, so the panel can tell the
user to change the master password if the profile was ever copied.
2026-10-04 03:42:02 +02:00
Local Dev
0514d2d4e3 Merge aegis-pin-view: Aegis 0.31.1 restores the earlier PIN screens 2026-10-04 03:40:18 +02:00
Local Dev
4117a010c4 Aegis 0.31.1: the PIN screens look and behave as they did before 0.31
0.31 moved the PIN check into index.js and, with it, replaced the
15-minute lockout after five wrong PINs by "PIN off until the master
password", with new wording on every PIN screen. The user wants the
screens as they were. The wording, the lockout and the switch to the
master password are back; the check stays in index.js, so the lockout is
now enforced by the host and the panel still never sees the PIN blob.
After the lockout every further wrong PIN locks it again.
2026-10-04 03:40:10 +02:00
Local Dev
af95af4540 Merge master: Theseus 0.3.76 release 2026-10-04 03:38:28 +02:00
Local Dev
d355bbbf87 Theseus: bundle Pithos 0.3.11
New installs carry the same Pithos the extension channel serves, including
drives on Silent Mode and the Sia account card.
2026-10-04 03:36:50 +02:00
Local Dev
7d080c3383 Theseus 0.3.76: Pithos at pithos.sia, music in background tabs, Aegis 0.31
Built-in extensions can answer paths under a name they ship with, so
Pithos opens at pithos.sia/<user>/<drive>/<folder> instead of a
loopback address, signed in only while the vault is unlocked. A tab
playing sound is no longer frozen in the background, so music keeps
playing when you switch tabs. A widened left panel covers the page
instead of squeezing it and the right sidebar. The tab that was open
at close loads on launch. Bundles Pithos 0.3.10 (views, compact sidebar
layout, music player, updater footer, Account page) and Aegis 0.31.0
(the audit fixes).
2026-10-04 03:36:15 +02:00
Local Dev
399e763745 Theseus: bundle Pithos 0.3.10 2026-10-04 03:29:32 +02:00
Local Dev
bdc8f951c6 Theseus: built-in extensions can answer paths under a name they ship with
Pithos needs its full-page app at pithos.sia/<user>/<drive>/<folder>
instead of a loopback address. A new site-route capability lets a
built-in add-on declare names in its manifest (siteRoutes) and register
a handler for them; the bns:// handler asks it first for every path but
the root, and a handler that returns nothing hands the request back to
the name's own site. Community add-ons cannot use it, since answering
for a name is impersonating it.
2026-10-04 03:29:30 +02:00
Local Dev
556a22b062 Theseus: bundle Pithos 0.3.9 2026-10-04 03:18:25 +02:00
Local Dev
6fd44db1d6 Theseus: the tab that was open at close loads on launch
Restore left every tab dormant, the active one included, so a fresh launch
showed the right tab highlighted over an empty page until it was clicked,
which reads as a broken restore. The active tab now loads as soon as the
toolbar has painted; every other restored tab stays dormant until it is
activated, so launch still costs one page renderer.
2026-10-04 03:03:17 +02:00
Local Dev
5e67f81a94 Theseus: bundle Pithos 0.3.8 with the menu and Account page 2026-10-04 03:01:00 +02:00
Local Dev
155b445c68 Theseus: bundle Pithos 0.3.8 2026-10-04 02:38:21 +02:00
Local Dev
6b9ada6dbd Record Aegis 0.30.1 (published from d2ddee5 + the Tron fix) in master's history 2026-10-04 02:29:35 +02:00
Local Dev
80146c8c22 Merge aegis-031-fixes: the 0.31.0 audit findings
PIN checked by the host with a hard five-guess limit, permits described
from what is signed, unreadable WizardConnect requests refused, PIN
clearances bound to their request, permissions re-read after the PIN
wait, and the Tron duplicate-field fix (also shipped alone as 0.30.1).
2026-10-04 02:29:32 +02:00
Local Dev
916a748889 Aegis: sends name their wallet, amounts with spaces are refused, BCMR cleanup
- send, sendToken and consolidate now require the wallet id the panel
  reviewed them for; a missing id used to skip the check, and the Solana
  token send sent none, so a selection change under the PIN pad sent from
  another wallet.
- "1 0" was read as 10: a space inside an amount is now refused.
- A BCMR registry list saved before https was enforced is filtered on read,
  and names lose the soft hyphen, Arabic letter mark, Mongolian vowel
  separator, line/paragraph separators and Unicode tag characters too.
2026-10-04 02:26:15 +02:00
Local Dev
7447d57e96 Aegis: a BCH payment re-reads permissions after waiting for the PIN
signAndSend took a permissions snapshot, waited up to two minutes for the
PIN, then wrote the snapshot back. Revoking the site meanwhile still let
the allowance payment go out and restored the revoked allowance, and any
other permission change made during the wait was lost. After the wait it
now re-reads permissions, refuses an allowance payment whose allowance was
revoked, replaced or no longer covers it, and changes only this origin's
sendTx.
2026-10-04 02:24:04 +02:00
Local Dev
a5ce638848 Theseus: a background tab that is playing sound is not frozen
Freezing background tabs stopped music and talks the moment you
switched to another tab, which no other browser does. A tab that is
audible when its freeze is due is checked again later and frozen only
once it falls quiet.
2026-10-04 02:23:08 +02:00
Local Dev
449a967e21 Theseus: bundle Pithos 0.3.7 with the music player 2026-10-04 02:23:07 +02:00
Local Dev
4511a933f4 Aegis: a PIN clears only the transaction it was entered for
One global 90 s clearance was opened by every PIN proof. Opening the
wallet or ticking a setting let the next dapp transaction from any site
through without a PIN; a dapp waiting in its poll could take the clearance
the user had just made for their own send; and with two sites waiting the
second one's request was dropped.

Each waiting dapp transaction now has an id, and only a proof naming that
id releases it; a proof given for "transaction" in the panel clears the
panel's next send only; any other proof clears nothing. The panel answers
waiting sites one at a time. Promote to HD now asks for the PIN like any
other spend instead of failing when PIN-per-transaction is on.
2026-10-04 02:23:02 +02:00
Local Dev
2faa3d808a Aegis: a WizardConnect request the overlay cannot read is not signed
wc-sign accepted a flat request (tx and sourceOutputs at the top) that
buildWcApproval does not read, so any paired dapp could get a signature
after an overlay showing only the wallet, an input count and the sighash.
The signer now takes only the nested WizardConnect shape, and the overlay
refuses, without showing anything, a request whose outputs or spent
inputs it cannot decode. Total out now sums every output, not the first 8.
2026-10-04 02:21:11 +02:00
Local Dev
e02d4698ea Aegis: a permit is described from what the signature covers
describePermit read td.message directly, and the EIP-712 encoder ignores
keys a type does not declare. A dapp could put a decoy allowed:false or
details:{amount:"1"} beside an unlimited permit and the overlay showed
the decoy, not risky, under the plain Sign button, with the same digest.

The overlay and the message preview are now built from the declared
fields only, the permit variant is picked from the declared type, and
dropped fields are counted on the overlay. Amounts of 2^96 units and up
are flagged as effectively unlimited, marketplace orders and Safe
transactions get the warning too, and the encoder refuses a non-hex
address instead of signing it as zero bytes.
2026-10-04 02:19:42 +02:00
Local Dev
b85605416e Aegis: the PIN is checked by the host, and guessing ends at five
The panel fetched the PIN blob and decrypted it itself, then reported its
own failures. The lockout therefore counted only what a well-behaved panel
chose to report, a 15-minute timer handed out five more guesses forever,
and anything able to run in the panel could take the blob and search the
million PINs offline in minutes.

The blob now never leaves index.js: pinSet builds it after checking the
master password against the vault, pinUnwrap counts each guess before
trying it, and five wrong guesses switch the PIN off until the master
password is entered. The panel keeps its PIN pads and only sends digits.
A blob from an older build (200k iterations) is re-made at 600k under a
fresh salt on the next correct PIN. Only the topmost PIN pad listens to
typed digits, so two stacked pads cannot both take one entry.
2026-10-04 02:17:26 +02:00
Local Dev
61144e821e Theseus: a widened left panel covers the page instead of squeezing it
Widening an add-on's left panel shrank the open tab to a 120 px strip
and, with the right sidebar open, pushed the sidebar narrower too. Now
the widened panel lies over the tab area like a page of its own, up to
the right sidebar, which keeps its width; the tab underneath keeps its
size. Choosing a tab, opening Settings or a new tab, or using the
address bar narrows the panel back to a bar beside the page, the way a
maximized right sidebar already steps back.
2026-10-04 02:16:23 +02:00
Local Dev
6ba16261ab Theseus: bundle Pithos 0.3.7 2026-10-04 02:16:11 +02:00
Local Dev
bd113f9b47 Aegis 0.30.1: the Tron duplicate-field fix, ahead of 0.31.0
0.30.0 is on the update channel and bundled in Theseus 0.3.75 with a Tron
decoder that a hostile site can use to show one transfer and sign another.
This is 0.30.0 plus that fix only; 0.31.0 is still under review.
2026-10-04 02:11:42 +02:00
Local Dev
1db2c4265b Aegis: refuse a Tron transaction whose fields appear twice
The decoder read the first copy of a singular protobuf field; java-tron
keeps the last. Any.value is opaque bytes, so a TransferContract carrying
two recipients and two amounts hashes to the same txid either way: the
overlay showed "1 TRX to X" while the chain would move 999 TRX to
another address. It also defeated the plan-time and sign-time draft checks
against a hostile node. A repeated singular field, or a known field with
the wrong wire type, now refuses the transaction.
2026-10-04 02:11:41 +02:00
Local Dev
c906e7b8ed Aegis: refuse a Tron transaction whose fields appear twice
The decoder read the first copy of a singular protobuf field; java-tron
keeps the last. Any.value is opaque bytes, so a TransferContract carrying
two recipients and two amounts hashes to the same txid either way: the
overlay showed "1 TRX to X" while the chain would move 999 TRX to
another address. It also defeated the plan-time and sign-time draft checks
against a hostile node. A repeated singular field, or a known field with
the wrong wire type, now refuses the transaction.
2026-10-04 02:10:51 +02:00
Local Dev
80fe82abee Theseus: an add-on can limit which sites get its bridge; vault secrets stay first-party
- Page-inject policy. An add-on may keep { mode, origins } under the
  reserved storage key "__pageInjectPolicy"; in "allowed" mode its bridge is
  injected, and its page messages accepted, only on the listed origins. It
  is read from the store because the decision is made synchronously at
  document start and must hold while an on-demand add-on is still dormant.
  A wallet injected into every page tells every page the user has one.
  api.features.pageInjectPolicy lets an add-on tell an old host apart.
- vault.imports (raw imported seeds and keys, not namespaced per add-on) and
  vault.lifecycle unlock/setup/lock (the master password, and an
  unthrottled oracle for it) are for add-ons that ship with Theseus. A
  community extension with vault-derive could read the wallet's imported
  keys. Others use vault.requestUnlock, where Theseus draws the prompt.
2026-10-04 01:55:40 +02:00
Local Dev
884f3948b8 Aegis: fees that follow the network, connections that come back, its own name on Solana
Still 0.31.0 (unpublished batch).

- ETH nonce. The pending count from a load-balanced RPC often misses a
  transaction this wallet sent seconds ago, so two sends in a row shared a
  nonce and the second failed or replaced the first. The nonce is taken at
  signing, from the RPC or from what the wallet itself last broadcast,
  whichever is higher, and broadcasts are serialised per wallet.
- Chains without EIP-1559 (no baseFeePerGas) get a legacy EIP-155
  transaction; they rejected the type-2 envelope, so a network added by a
  dapp could receive but never send. The tip is clamped to the fee cap.
- Bitcoin and DigiByte take their fee rate from the Electrum server's
  estimate instead of a constant, size each output from its real script
  (a taproot destination was undercounted), and round the size up before
  pricing. Bitcoin inputs signal replace-by-fee. DigiByte keeps its 20
  sat/vB floor and does not signal RBF, which it does not have.
- Electrum: a wallet with live subscriptions went quiet for good when its
  server dropped. The client reconnects with backoff, pings to catch dead
  sockets, times out a silent connect, and hands the replayed subscription
  answers on as notifications so the wallet refreshes. dispose() ends it.
- Max with an SPL token selected did nothing; it now fills the exact token
  balance.
- Removing a wallet retired its derivation index for good. Add wallet now
  takes the lowest free index, so the same wallet comes back.
- Solana: registered through the Wallet Standard as "Aegis" instead of
  setting isPhantom, with silent connect for already-connected sites.
- "Only show the wallet to sites I enable": Aegis keeps the host's
  page-inject allow-list in step with enabled and connected sites.
2026-10-04 01:55:38 +02:00
Local Dev
14d9df31cc fix(theseus/error): show branded error page on BCNR→clearnet fallback failures
flytastic.ru (and any other site where the BCNR lookup NXDOMAINs and
the clearnet fallback fails with a cert / network error) was leaving
the tab blank instead of showing the error page.

Cause — tab.internalNav was overloaded. loadBns's fallbackToWeb sets
internalNav=true before loadURL("https://host/") so will-navigate
doesn't re-route the programmatic nav back through navigateTab. The
did-fail-load handler was using the SAME flag to suppress recursion
on its own loadFile(error.html) call — so a cert error during the
clearnet fallback was silently swallowed.

Narrow the suppression to its real target: skip did-fail-load only
when the failing URL is file:// (our own error.html / home.html
loads). Clearnet HTTPS failures from a programmatic loadURL now
surface the branded error page like any other failed navigation. The
will-navigate guard (its original purpose) is untouched.
2026-10-04 01:50:31 +02:00
Local Dev
faea4147d2 feat(theseus/error): CF Bot Fight 503 hint with .bch mirror suggestion
When a top-level HTTPS load returns 503, sniff the body for CF Bot
Fight markers (cloudflare + blocked/challenge/attention-required, or
cf-chl). If it matches, replace the CF interstitial with a branded
error page carrying kind=cf-blocked. The page explains why Electron
browsers get 503 (TLS ClientHello fingerprint below HTTP, no user-
agent tweak fixes it) and offers next steps.

If a .bch name has a `p` record proxying the same origin, the page
surfaces it as a one-click retry — preserving the original path, so
/faq becomes /faq on the mirror rather than the mirror's root. Mirror
lookup walks the warm sharedIndex, so it's synchronous and works
offline. If no mirror exists, links to silentmode.st/mirrors where
users can mint one via Sirius.

Guarded against races — the 250 ms delay before body sniff re-checks
that the tab is still on the same URL and not destroyed, both before
and after the executeJavaScript resolves, so a JS-redirect after the
503 doesn't cause misclassification.
2026-10-04 01:50:09 +02:00
Local Dev
2dfa9e9c3e Theseus: an add-on's key namespace cannot be taken by another add-on
- `absorbs` lets one add-on derive under another's vault namespace. A
  community install has the field stripped, but an update of one is placed
  as shipped, so a second version could declare absorbs:["aegis"] and derive
  the wallet's keys. It is now honoured only for ids that ship inside
  Theseus, at the one place that matters: vault.derive.
- The legacy ids Aegis absorbs ("bchwallet", "siawallet") no longer have a
  bundled folder, so nothing stopped a catalog extension from installing
  under one and deriving `bchwallet/...`. They are reserved at install and
  refused at derive.
- A page-to-add-on message is accepted only from the tab's top-level frame.
  The origin shown to the user is the top-level URL, so a subframe that
  reached the channel would have been credited with its parent's origin.
- The approval overlay ignores everything but Cancel for the first 800 ms.
  A page can raise it without a gesture and knows where the primary button
  lands, which made "double-click here" a way to approve a spend.
2026-10-04 01:41:01 +02:00
Local Dev
f27f3d27c9 Aegis: the PIN is enforced by the host, and every spend is confirmed there
PIN
- The PIN blob wraps the vault master password under six digits and sat in
  plain add-on storage, so a copy of the profile reduced the master password
  to a million offline PBKDF2 guesses. It is sealed with the OS keystore
  before it is stored; a plain blob from an older build is sealed on first
  read. New blobs use 600k iterations.
- "Ask for PIN on every transaction" was decided by the host and enforced
  by nobody: `send` never checked it and dapp transactions had no PIN step.
  A gate is now cleared only by the master password the PIN unwraps,
  verified against the vault, which also opens a single-use transaction
  clearance. Panel sends consume one; dapp transactions ask the open panel
  and wait.

Spending and signing
- Consolidate emptied wallets on the panel's confirmation alone, defaulted
  to every sibling when no list was sent, and swept into whatever was
  selected at click time. It now needs explicit sources and the previewed
  destination, and shows the whole batch on the host overlay.
- Typed data for a chain other than the connected one is refused. Permit
  and Permit2 signatures name the spender, tokens, amounts and expiry, and
  an unlimited one gets the danger action. Previews are no longer cut at
  600/400 characters without saying so.
- eth.rpc relayed any eth_* call for sites that never connected.
- The WizardConnect overlay lists the tokens being spent and received.

Send form
- "0,5" was read as 5: the parser deleted commas. Amounts are parsed
  exactly; a decimal comma is a decimal, ambiguous or non-numeric input is
  refused, extra decimals are an error instead of being dropped.
- Send submits the request the summary was computed for, never a fresh read
  of the form, and stays off while a plan is pending or stale.
- Switching wallet resets the form instead of leaving a live button on the
  previous wallet's plan.
- The unlock field kept the master password after unlocking; the PIN pad
  kept its digits and kept counting keystrokes typed elsewhere as PIN
  attempts; an idle lock left a revealed key or seed form on screen.
- Enter confirmed a dialog even with focus on Cancel.
2026-10-04 01:38:53 +02:00
Local Dev
9e7e9d5e8b Aegis 0.31.0: chain adapters stop trusting what they should check
Start of the next batch; 0.30.0 is published.

- Tron panel sends signed whatever /wallet/createtransaction returned while
  the approval showed the local request. The returned bytes are now decoded
  and must be one transfer from this wallet, to that address, for that
  amount, with a matching txID - checked at plan time and again at signing.
- Importing a Solana wallet from a seed phrase threw on every attempt (a
  mis-parenthesised `new require("crypto").createHmac` plus a bare require
  of an ESM-only subpath). SLIP-0010 now uses Node's HMAC, as chain-sol does.
- Imported BCH wallets put token-bearing UTXOs into coin selection. They are
  excluded, as in the HD wallet, and the balance counts what can be spent.
- WizardConnect dropped the token from each spent output before signing, so
  under SIGHASH_UTXOS every signature of a token transaction was invalid.
- A wallet disposed while a refresh was in flight re-armed its poll timer.
- BCMR registry content is bounded before it reaches the panel: control and
  bidi characters stripped, lengths capped, decimals 0-18, icons https/ipfs
  only, registries https only.
2026-10-04 01:38:50 +02:00
Local Dev
84a37b26bf Aegis: README and MPL-2.0 license for its own repository
Aegis is getting a standalone forge repo (silentmode/aegis) split from
this folder. Inside Theseus it was covered by the root LICENSE; on its
own it needs the license and a description in the folder itself.
2026-10-04 00:24:01 +02:00
Local Dev
3de25581b3 Theseus: bundle Pithos 0.3.6
Rebuilt from Pithos/ with scripts/build-theseus-addon.mjs.
2026-10-04 00:09:55 +02:00
Local Dev
1244dae25e Theseus: bundle Pithos 0.3.5
Rebuilt from Pithos/ with scripts/build-theseus-addon.mjs.
2026-10-04 00:05:50 +02:00
Local Dev
41523a5cbf Settings: a legacy "Middle East" location no longer kills the page
Profiles from before the country picker carry locationMode "spoof" with a
region; the Settings page migrates them to a country on load. middle_east
mapped to AE, which was missing from COUNTRIES, so the destructure threw
partway through the page script. Everything wired after that point never
ran: the Ariadne panel stayed on "checking...", showed no collision
policy, left Sources empty, and its on/off switch had no handler, so
flipping it never asked for UAC and changed nothing.

Add the United Arab Emirates (same Dubai coordinates main.js already uses
for the region) and fall back to Germany for any region without a
country, so a stale value can never stop the page again.
2026-10-03 23:28:58 +02:00
Silent Mode
5f02973597 Theseus: Settings language dropdown — supported first, in their own optgroup
The dropdown mixed supported and unsupported languages in one list ranked
by global speakers, so the six languages the translator actually handles
today (en, es, fr, de, el, ru) were scattered between greyed rows. The
user had to scan every entry to find the ones they could pick. The
dropdown is now partitioned into two <optgroup>s — "Supported today"
first with the enabled languages, "Translator coming later (Accept-
Language only)" below with the greyed rows — so the top of the list
is actionable and the roadmap is still visible underneath.
2026-10-03 23:27:05 +02:00
Local Dev
8b74f5cbf9 Merge branch 'master' into claude/zen-archimedes-463527 2026-10-03 23:02:46 +02:00
Local Dev
7185509355 Theseus 0.3.75: previous tabs reopen, extensions start on first use
Ships 2437506 (the restore setting was a no-op with the default quit
clear), the first-use loader for extensions with Aegis 0.29.0 bundled
(~0.7 s less main-thread work at launch, ETH/SOL bridge fixed), the
language picker as an overlay, Pithos 0.3.4 and the Ariadne status row.
2026-10-03 23:02:25 +02:00
Local Dev
7bea16aa28 Merge restore-fix: previous tabs reopen again 2026-10-03 23:02:03 +02:00