Commit Graph

9984 Commits

Author SHA1 Message Date
M ebbcfa26fb refactor: remove Namecoin label from search results
Per review: .bit resolution is just NIP-05, no special labeling needed.
2026-03-26 10:25:31 +11:00
M e7cde18371 feat: show Namecoin label on .bit search results without ViewModel state
Derive the label from the existing searchTerm — if it ends with .bit,
show a chain-emoji label above each user result. No new StateFlow or
ViewModel state management needed.
2026-03-26 09:49:34 +11:00
M 1ca904b415 refactor: remove Namecoin label from search results per review
Remove namecoinResolvedUser StateFlow and the chain-emoji label
from search results. .bit resolution still works through the
existing NIP-05 path — just no special UI decoration.
2026-03-26 09:37:56 +11:00
M 67fd48c5b8 refactor: simplify .bit search resolution per review feedback
Address @vitorpamplona's review comments on the last commit:

1. Remove NamecoinResolutionState sealed class and status banners
   — the existing NIP-05 resolver already handles .bit, no need for
   separate Namecoin-specific UI state (spinner, chain emoji, error)

2. Remove separate toNip05IdOrNull() resolution path
   — widen the existing `if (term.contains('@'))` gate in both
   SearchBarViewModel and UserSuggestionState to also accept bare
   .bit domains (synthesize _@domain.bit → existing NIP-05 flow)

3. Remove d/ and id/ identifier support from search
   — per feedback, only NIP-05 style resolution (.bit) in search

4. Remove special Namecoin result rendering in ImportFollowList
   — just show UserLine for all results, no separation needed

5. Keep a lightweight 'Namecoin' label on resolved users in search
   — namecoinResolvedUser StateFlow tracks the .bit-resolved user,
   shown as a small label above the UserCompose row

Net: -405 lines, +50 lines across 6 files.
2026-03-26 08:43:39 +11:00
M 0d83af8912 feat: resolve bare .bit domains and show Namecoin resolution status in UI
Widen the existing NIP-05 resolution gate in UserSuggestionState and
SearchBarViewModel to also accept bare .bit domains and d//id/ Namecoin
identifiers. A synthesised Nip05Id is passed to the existing
nip05Client.get() path — which already routes .bit to the
NamecoinNameResolver — so no separate resolution logic is needed.

Add NamecoinResolutionState (Idle/Resolving/Resolved/Error) as a
StateFlow so the UI can show progress. ImportFollowListSelectUserScreen
and SearchScreen display an animated status banner (spinner while
resolving, chain emoji on success, warning on error) and label
Namecoin-resolved profiles in the results list.
2026-03-26 07:40:25 +11:00
M 2e02edc333 refactor: rename trustAllCerts → usePinnedTrustStore
The field no longer means 'trust all certificates' — since the Samsung
One UI 7 fix, it means 'use the pinned trust store (hardcoded +
TOFU-pinned certs + system CAs) instead of system-only trust.'

The old name was actively misleading and could cause a future
contributor to interpret the flag literally, potentially reintroducing
the trust-all pattern that Samsung Knox and GrapheneOS reject.

Renamed across all 4 files:
- ElectrumxServer.kt: field definition + updated KDoc
- ElectrumXClient.kt: createSocket() usage + comments
- NamecoinSettings.kt: parseServerString() usage + comments
- NamecoinSettingsTest.kt: test assertions
2026-03-26 06:33:43 +11:00
M 7f451ee7c7 fix: harden TLS for GrapheneOS and security-conscious Android ROMs
Address compatibility and security issues identified by reviewing
GrapheneOS source (hardened Conscrypt, strict TLS enforcement):

1. .onion: prefer pinned factory, fall back to trust-all

   GrapheneOS patches Conscrypt with stricter TLS enforcement that may
   reject no-op X509TrustManagers even for proxied sockets. The .onion
   server's cert is already in PINNED_ELECTRUMX_CERTS (same operator as
   electrumx.testls.space), so we now use cachedPinnedSslFactory() as
   the primary path. onionSslFactory() (trust-all) is kept as a fallback
   on SSLHandshakeException only — this handles cert rotation or unknown
   .onion servers gracefully.

2. TOFU: require explicit user confirmation before pinning

   Previously, Test Connection auto-pinned every cert on success. An
   attacker performing MITM during first test would get their cert
   permanently trusted. Now each new cert triggers an AlertDialog showing
   the full SHA-256 fingerprint. Users must explicitly accept ('Trust')
   or reject each cert — aligning with GrapheneOS's philosophy of
   explicit trust decisions.

3. Clarify trustAllCerts semantics

   The field name is misleading post-refactor: it now means 'use pinned
   trust store' not 'trust all certificates'. Added TODO to rename to
   usePinnedTrustStore and updated inline comments to prevent future
   misinterpretation.

Note: hostname verification on raw SSLSocket is a pre-existing gap
(not introduced by the Samsung fix PR) — SSLSocket.createSocket() uses
the host parameter for SNI only, not hostname verification. A follow-up
should add endpointIdentificationAlgorithm='HTTPS' or fingerprint-based
verification for pinned certs.
2026-03-26 06:26:18 +11:00
M a4953f628d doc: verify .onion ElectrumX cert via Tor, document pinning
Connected to the .onion hidden service via Tor SOCKS proxy and
confirmed it serves the SAME certificate as electrumx.testls.space:
  SHA-256: 53:65:D5:BB:26:19:F5:40:1C:D8:8E:FC:AF:FB:A5:B2:...

The .onion cert is already covered by the first pinned cert entry.
Added comments documenting this relationship and instructions for
fetching .onion certs via Tor for future updates.

The .onion still uses onionSslFactory() (trust-all) as the primary
path — this is correct since Tor provides its own authentication.
The pinned cert serves as defense-in-depth.
2026-03-25 12:13:49 +11:00
M 3afe0c9978 fix: bypass cert pinning for .onion ElectrumX servers
Tor hidden services are authenticated by their onion address (the
public key hash), making TLS certificate verification redundant.

The .onion server in TOR_ELECTRUMX_SERVERS was going through
pinnedSslFactory() but its cert isn't in the pinned list (and can't
be fetched without Tor). This would cause .onion connections to fail
with SSLHandshakeException when Tor mode is active.

Fix: .onion addresses now use a dedicated onionSslFactory() with
trust-all, which is safe because:
1. Tor provides end-to-end encryption
2. The onion address IS the server identity proof
3. Samsung Knox trust-all rejection doesn't apply to proxied sockets
2026-03-25 12:10:45 +11:00
M b8b51db0b5 feat: TOFU cert pinning for custom ElectrumX servers
When a user adds a custom ElectrumX server and runs Test Connection,
the server's TLS certificate is automatically captured and pinned
(Trust On First Use). This allows custom servers with self-signed
certificates to work on Samsung/Xiaomi/OnePlus devices.

Changes:
- ElectrumXClient: addPinnedCert(), setDynamicCerts() for runtime
  cert management; testServer() now captures server cert PEM and
  SHA-256 fingerprint from SSL session
- NamecoinSharedPreferences: persist pinned certs to DataStore
- AppModules: load pinned certs on startup, sync to ElectrumXClient
- NamecoinSettings: custom servers always set trustAllCerts=true
  (ElectrumX servers almost universally use self-signed certs)
- UI: shows cert fingerprint in test results, auto-pins on success
- ServerTestResult: new serverCertPem + certFingerprint fields

Flow: Add server → Test Connection → cert auto-captured and pinned →
future connections trust that cert even on Samsung Knox devices.
2026-03-25 12:05:05 +11:00
M 49698de99c feat: add Test Connection diagnostics to Namecoin settings
Add per-server connection testing with detailed error reporting:
- Test Connection button tests each ElectrumX server individually
- Shows streaming results:  success with response time,  failure
  with human-readable error (TLS handshake failed, connection refused,
  timeout, DNS failed, invalid response, etc.)
- Diagnostic card shows: last test timestamp + success count, device
  info (manufacturer/model/Android/API), TLS version negotiated
- ElectrumXClient.testServer() method for single-server diagnostics
  with TLS version capture from SSL session

This gives users (and bug reporters) immediate visibility into why
Namecoin resolution may be failing silently on their device.
2026-03-25 11:52:05 +11:00
M 15a2d77a0f fix: pin ElectrumX server certs instead of trust-all TrustManager
Samsung One UI 7 (Android 16) silently rejects TLS connections that use
a no-op X509TrustManager which accepts all certificates. This breaks
Namecoin resolution on all Samsung devices running One UI 7, including
Galaxy A15 (SM-A156E) and Galaxy S24 Ultra (SM-S938B).

Replace trustAllSslFactory() with pinnedSslFactory() that:
- Pins the actual self-signed certificates of known ElectrumX servers
- Also includes system CA certificates for servers with real certs
- Uses a proper TrustManagerFactory chain that Samsung Knox accepts

Additional OEM compatibility hardening:
- Cache the SSLSocketFactory (avoid expensive rebuild per connection)
- Request TLSv1.2 explicitly (Xiaomi MIUI/HyperOS and OnePlus ColorOS
  Conscrypt forks may default to TLS 1.0 for raw socket upgrades)
- Enforce TLSv1.2+ enabled protocols on the SSLSocket
- KeyStore fallback to PKCS12 if default type fails (Xiaomi)
- Defensive try/catch on system CA cert re-insertion (some OEMs return
  certs that cannot be added to a new KeyStore)

Tested on Android 16 (API 36) emulator — all ElectrumX servers connect
(hostname, IP-address, factory reuse) and .bit resolution works E2E.

Pinned certs:
- electrumx.testls.space:50002 (expires 2027-05-04)
- nmc2.bitcoins.sk:57002 (expires 2030-10-22)
2026-03-25 11:41:12 +11:00
Vitor Pamplona d847c06979 Merge branch 'main' of https://github.com/vitorpamplona/amethyst
* 'main' of https://github.com/vitorpamplona/amethyst:
  New Crowdin translations by GitHub Action
2026-03-24 17:23:31 -04:00
Vitor Pamplona 0d8b4e8baa merge 2026-03-24 17:21:52 -04:00
Vitor Pamplona 70d034e50c Merge pull request #1930 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-03-24 17:20:31 -04:00
Vitor Pamplona f11172216d Improvements to the status of attestations. Validity first, then Processing status. 2026-03-24 17:20:11 -04:00
Crowdin Bot cc850c5b7f New Crowdin translations by GitHub Action 2026-03-24 21:17:34 +00:00
Vitor Pamplona 728ff9a4cd Merge pull request #1926 from vitorpamplona/claude/reply-click-navigation-7lKuO
feat: scroll to replied message when clicking reply preview in chat
2026-03-24 17:16:16 -04:00
Vitor Pamplona 6f9fc23a64 Merge pull request #1929 from vitorpamplona/claude/relay-info-dialog-uuE8W
feat: make profile relay rows open relay info dialog
2026-03-24 17:16:01 -04:00
Claude bcdaf8630c feat: make relay rows clickable to open relay info dialog on profile page
Adds onClick parameter to RelayCompose and navigates to RelayInformationScreen
when a relay row is tapped in the profile relay tab.

https://claude.ai/code/session_01PBFQz53xzXoFsEHD5Ghyqr
2026-03-24 20:34:01 +00:00
Vitor Pamplona 2d25bb2592 Sorts followers into a set to avoid LazyColumn key conflicts. 2026-03-24 14:23:21 -04:00
Vitor Pamplona 405d1d0519 Merge pull request #1928 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-03-24 13:42:23 -04:00
Crowdin Bot 88042f06d4 New Crowdin translations by GitHub Action 2026-03-24 17:40:05 +00:00
Vitor Pamplona 8437a819f8 Merge pull request #1909 from KotlinGeekDev/kmp-completeness
Kmp completeness, part 3 - adios, Swift bridge.
2026-03-24 13:38:44 -04:00
Vitor Pamplona cef07a2460 Fixes single label domains with non ascii chars around them 2026-03-24 13:33:14 -04:00
Vitor Pamplona 2a2c61973e Avoids crashing the app in weird urls. 2026-03-24 13:30:36 -04:00
KotlinGeekDev 349781d9be Use uri-reference-kmp in commonMain. Remove platform-specific implementations. 2026-03-24 16:34:13 +01:00
KotlinGeekDev 334aabbf02 Merge branch 'upstream-main' into kmp-completeness 2026-03-24 16:12:14 +01:00
KotlinGeekDev 2933454fb6 Merge branch 'main' of https://github.com/vitorpamplona/amethyst into upstream-main
# Conflicts:
#	quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/URLs.ios.kt
2026-03-24 16:11:04 +01:00
Vitor Pamplona 09054d6ac5 Fixes pool rendering when one label is large and the other is small 2026-03-24 10:58:59 -04:00
Claude 4d8be5e272 feat: scroll to replied message when clicking reply preview in chat
When a user clicks on the reply preview (inner quote) in a chat message,
the chat feed now scrolls to the original replied-to message in the same
screen instead of doing nothing.

https://claude.ai/code/session_01UF4VxoWGvvvwtLYBLBYw9w
2026-03-24 14:51:39 +00:00
Vitor Pamplona c913c0e1ab Merge pull request #1921 from vitorpamplona/claude/hide-video-controls-k09Ga
Hide video controls on playback start
2026-03-24 10:20:55 -04:00
Vitor Pamplona 30ff9ab09b Merge pull request #1918 from vitorpamplona/claude/draggable-video-progress-CQODi
feat: add drag-to-seek on video progress indicator
2026-03-24 10:12:31 -04:00
Vitor Pamplona 159f1a121b Merge pull request #1916 from vitorpamplona/claude/add-multiple-choice-polls-CQUAv
feat: add multiple choice poll type selector
2026-03-24 10:07:33 -04:00
Vitor Pamplona 9b5b50f237 Merge branch 'main' of https://github.com/vitorpamplona/amethyst
* 'main' of https://github.com/vitorpamplona/amethyst:
  code review: - Removed redundant equality guards in SideEffect — MutableState already suppresses no-op writes for value types - Changed mutableStateOf({}) to mutableStateOf(null) with explicit nullable type — clearer intent, no accidental no-op invocation -  stopRecording() now early-returns with ?: return when not recording, so the Toast only shows for genuinely failed recordings (too short)
  entire solid recording indicator bar stops recording when tapped, not just the small stop icon.
  New Crowdin translations by GitHub Action
  update skill
  update translations: CZ, DE, PT, SE
2026-03-24 10:00:10 -04:00
Vitor Pamplona 898e6ac677 Added credits 2026-03-24 09:41:23 -04:00
Vitor Pamplona d6d4bdc5e3 avoids duplicating quote tags by key + value 2026-03-24 09:40:02 -04:00
Vitor Pamplona c39eca5172 Add new utility methods 2026-03-24 09:39:09 -04:00
Vitor Pamplona 3d9efa9938 Tries to solve a duplicate user in a lazy column bug 2026-03-24 09:33:50 -04:00
Vitor Pamplona 11dabd46ba Checks if p tags are user pubkeys when loading drafts. 2026-03-24 09:33:37 -04:00
Vitor Pamplona 94e708b5fc Reduces the need to compute naddr to index articles in bookmarks 2026-03-24 09:32:38 -04:00
Vitor Pamplona 8d81d6d57c Removes the clickable NIP-05 url in the @ tagging of users 2026-03-24 09:30:40 -04:00
Vitor Pamplona 8c4b2fe62b Makes sure quotes only happen once in events. 2026-03-24 09:30:07 -04:00
Vitor Pamplona 514e90ff17 Fixes non http uris in the references tag 2026-03-24 09:13:48 -04:00
KotlinGeekDev 4c14554263 Merge branch 'vitorpamplona:main' into kmp-completeness 2026-03-24 13:27:40 +01:00
David Kaspar 22142d17f9 Merge pull request #1924 from davotoula/larger-stop-area-for-voice-recording
Larger stop area for voice recording
2026-03-24 10:59:41 +01:00
davotoula e976bf9e2e code review:
- Removed redundant equality guards in SideEffect — MutableState already suppresses no-op writes for value types
- Changed mutableStateOf({}) to mutableStateOf(null) with explicit nullable type — clearer intent, no accidental no-op invocation
-  stopRecording() now early-returns with ?: return when not recording, so the Toast only shows for genuinely failed recordings (too short)
2026-03-24 09:25:07 +01:00
davotoula 4e43b14b09 entire solid recording indicator bar stops recording when tapped, not just the small stop icon. 2026-03-24 09:25:07 +01:00
David Kaspar 6f3308e45c Merge pull request #1923 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-03-24 09:00:06 +01:00
Crowdin Bot 1dbe552821 New Crowdin translations by GitHub Action 2026-03-24 07:35:59 +00:00