Skip to content

Follow-ups to #1479: ShopinBit image auth and Fact0rn Tor migration - #1493

Merged
julian-CStack merged 6 commits into
stagingfrom
pr1479/fix
Nov 3, 2026
Merged

julian-CStack merged 6 commits into
stagingfrom
pr1479/fix

Conversation

@sneurlax

@sneurlax sneurlax commented Nov 1, 2026 •

Copy link
Copy Markdown
Member

Summary

Depends on #1479 and is stacked on its head (0f421bc). You can merge that then this or this and close that--kroplabeskidu's authorship of those commits is preserved either way. Until that PR merges the diff here also shows its three commits; review by commit. Please merge with a merge commit, not a squash: the history contains the #1479 head unchanged, so merging this PR alone marks #1479 merged with the contributor's authorship kept.

#1479 routes remote images through the Tor-aware HTTP wrapper and adds Tor support for Ethereum. These five commits fix the gaps that leaves.

Images

  • Load ShopinBit image attachments with header auth. Attachment images were fetched from a query-auth URL carrying the token and customer key. The HTTP wrapper logs failed requests and dart:io puts the URL in its exceptions, so those credentials could land in the log file. The images are now fetched from the plain URL with the Authorization and External-Customer-Key headers.
  • Scope cached ShopinBit attachments by customer key. TorAwareNetworkImage keyed its cache on the URL alone, so an attachment fetched under one customer key would be served from cache to a later key without an authenticated request. An optional cacheScope is now part of the key and the ticket view passes the customer key. The scope is captured together with the request response, because FutureBuilder keeps showing the previous snapshot while a new future is pending and that snapshot must not be paired with a later customer's scope.

Fact0rn

  • Migrate the Fact0rn default node to allow Tor. Add Tor support for Ethereum, fix clearnet image loads in Tor mode #1479 marks the shipped Fact0rn default node Tor-ready, but updateDefaults keeps a saved node's tor/clearnet flags, so existing installs kept the clearnet-only node and Fact0rn would not refresh with Tor on. A v17 to v18 migration enables Tor on that node only when it still matches the old shipped default on every field the user can edit (host, port, name, SSL, failover, login, clearnet only). A customised node is left as is. Clearnet stays enabled, so nothing changes with Tor off.

Ethereum

  • Let ETH nodes choose Tor or clearnet. The Tor/clearnet radios were hidden for Ethereum when web3dart could not be proxied. With Add Tor support for Ethereum, fix clearnet image loads in Tor mode #1479 the ETH client honours the node's flags and throws on a mismatch, so a node stored as Tor-only or clearnet-only could not be fixed from the settings page the error points at. The radios now show for ETH like every other coin. No other change to the form.
  • Fail ETH RPCs when the Tor preference changed after the client was built. The SOCKS proxy is bound when the client is created, and updateTransactions, the tx loop above it and the token wallet's tx loop each reuse one lazily built client for many RPCs. Toggling Tor mid-operation left the rest of that operation on the old transport. A thin client wrapper remembers whether it was built proxied, re-reads the preference on every send, and throws before sending if they disagree. It does not rebuild, reroute or retry, so a broadcast that hits the check is not sent rather than replayed on a different transport. The next operation builds a fresh client under the current preference.

Not included

  • No local-node Tor bypass for ETH. Monero, Wownero and Salvium have the same node/preference guard without a bypass, and this PR keeps that parity.
  • No request timeouts or image size limits. Those need numbers measured over Tor and belong in their own PR.
  • No retry for SVG icons that failed to load. flutter_svg's cache never clears a failed pending entry, so the right fix is in the dependency.

Verification

  • dart format --set-exit-if-changed clean on every changed file in each commit
  • dart analyze lib test: no new lines versus staging
  • flutter test: all passed on each commit
  • ShopinBit attachments fetched from the sandbox with header auth are byte-identical to the query-auth fetch (no requests made against production)
  • Migration run end to end against a database created on staging
  • Fact0rn over Tor in the running app: a fresh wallet with the default node synchronised through the local arti SOCKS port with no DNS queries or direct connects to the node (checked under strace); the same wallet also refreshed over clearnet with Tor off
  • ETH over Tor in the running app, also under strace; the add/edit node view shows the radios for ETH with "Allow both" selected by default

Tests added

  • test/db_version_migration_test.dart: v18 lets the default Fact0rn node use Tor; v18 leaves an edited Fact0rn default node alone (six single-field edits)
  • test/networking/tor_aware_network_image_test.dart: cache is scoped by cacheScope
  • test/wallets/ethereum_tor_proxy_test.dart: client refuses to send after the Tor preference flips in either direction, and still sends when it is unchanged

@sneurlax sneurlax changed the title Follow-ups to #1479: ShopinBit image auth, Fact0rn migration, ETH transport controls Follow-ups to #1479: ShopinBit image auth and Fact0rn Tor migration Nov 1, 2026
@sneurlax
sneurlax added this pull request to stack #1495 November 1, 2026 21:45
@codecov

codecov Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 12.38095% with 276 lines in your changes missing coverage. Please review.
✅ Project coverage is 11.61%. Comparing base (6fb054b) to head (36d1f49).
⚠️ Report is 3 commits behind head on staging.

Files with missing lines Patch % Lines
...in_selection/exchange_currency_selection_view.dart 0.00% 69 Missing ⚠️
...earance_settings/sub_widgets/stack_theme_card.dart 0.00% 37 Missing ⚠️
lib/networking/tor_aware_network_image.dart 26.66% 33 Missing ⚠️
lib/pages/shopinbit/shopinbit_ticket_detail.dart 0.00% 33 Missing ⚠️
lib/pages/cakepay/cakepay_vendors_view.dart 0.00% 22 Missing ⚠️
...nge_view/sub_widgets/exchange_provider_option.dart 0.00% 18 Missing ⚠️
...nfo_row/sub_widgets/wallet_info_row_coin_icon.dart 0.00% 13 Missing ⚠️
lib/services/shopinbit/src/client.dart 0.00% 11 Missing ⚠️
lib/wallets/wallet/impl/ethereum_wallet.dart 41.17% 10 Missing ⚠️
lib/utilities/test_stellar_node_connection.dart 0.00% 6 Missing ⚠️
... and 10 more
Additional details and impacted files
@@             Coverage Diff             @@
##           staging    #1493      +/-   ##
===========================================
+ Coverage    11.59%   11.61%   +0.02%     
===========================================
  Files         1133     1134       +1     
  Lines       114059   114185     +126     
===========================================
+ Hits         13223    13263      +40     
- Misses      100836   100922      +86     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

kroplabeskidu and others added 6 commits November 2, 2026 18:36
web3dart was handed a plain http Client, so ETH and ERC-20 RPC could not
use Tor and the coin was flagged as not Tor-ready. Give it an IOClient
wrapping a SOCKS5-proxied HttpClient instead, the same way Solana does it,
and do the same for the node connection test.

Also add the usual node tor/clearnet mismatch check and set torSupport.
Nano and Banano already send every request through Tor, and Fact0rn uses
the regular ElectrumX client, so they only needed the torSupport flag.

The Stellar node test proxied its first request but then created a
StellarSDK with the default client, so the follow-up ledger query went
out directly.
Image.network and SvgPicture.network use their own HTTP clients and ignore
the Tor setting, so token logos, exchange and coin logos, CakePay card
images, ShopinBit attachments and theme previews were fetched directly
even in Tor mode.

Add TorAwareNetworkImage and TorAwareSvgNetworkLoader, which go through
the app's HTTP wrapper, and use them at all call sites.
The attachment images were fetched from a query-auth URL carrying the
token and customer key. Now that they go through the HTTP wrapper,
which logs failed requests, and dart:io puts the request URL in its
exceptions, those credentials could end up in the log file.

Fetch the plain URL with the Authorization and External-Customer-Key
headers instead. TorAwareNetworkImage takes the headers but keeps
keying the image cache on the URL alone, so a re-mounted attachment
still comes from the cache.

client.dart wasn't formatted on staging, so its diff includes one
formatting change.
updateDefaults keeps the saved node's tor and clearnet flags, so existing
installs kept the old clearnet-only Fact0rn default even though it now
allows Tor. With Tor turned on that node is rejected and Fact0rn cannot
refresh or pass the node test.

Add a one-time migration that enables Tor on the saved Fact0rn default
node. Only a node that still matches the old shipped default on every
field the user can edit (host, port, name, SSL, failover, login, clearnet
only) is touched, so a node the user customised keeps its settings.
Clearnet stays enabled, so nothing changes with Tor off, and later
choices are left alone.
TorAwareNetworkImage keys its cache on the url alone, so an attachment
path fetched under one customer key would be served from cache to a
later customer key without an authenticated request. Add an optional
cacheScope that is part of the key, and pass the ShopinBit customer key
there. The bearer token stays out of the key so a refreshed token does
not refetch.

The key is captured together with the request response rather than read
from the widget when building the image: FutureBuilder keeps showing the
previous snapshot while a new future is pending, and that snapshot must
not be paired with a later customer's scope.
@julian-CStack
julian-CStack merged commit 9089f30 into staging Nov 3, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants