Commit Graph

1233 Commits

Author SHA1 Message Date
Vitor Pamplona ffe5e14b2b Display content warning reason 2026-03-11 14:10:55 -04:00
Vitor Pamplona 9bb87b38f5 Merge pull request #1808 from vitorpamplona/claude/add-content-warning-description-5BF4B
Add optional description field for sensitive content warnings
2026-03-11 13:43:47 -04:00
Claude 2b0518a675 feat: allow users to add a description to the sensitive content warning
- Add contentWarningReason() helper to TagArrayExt and EventExt for reading the reason from existing events
- Add contentWarningDescription state to ShortNotePostViewModel, wired into event building and draft load/save/reset
- Update ContentSensitivityExplainer to accept description state and render an OutlinedTextField for user input
- Pass description state from ShortNotePostScreen to ContentSensitivityExplainer
- Add "Reason (optional)" placeholder string resource

https://claude.ai/code/session_01P2nkYdNiWXiAcfMPTRTVEW
2026-03-11 16:51:37 +00:00
Vitor Pamplona 3bd2f4251b Increasing sha256 pool size 2026-03-11 12:33:11 -04:00
Vitor Pamplona 3fdde60a37 Merge branch 'main' of https://github.com/vitorpamplona/amethyst
* 'main' of https://github.com/vitorpamplona/amethyst:
  New Crowdin translations by GitHub Action
  fix: resolve conflicts with upstream PR #1789 merge
  fix(desktop): remove noisy debug logs and silence SLF4J warnings
  feat(desktop): add bunker heartbeat indicator to sidebar navigation
  fix(desktop): verify user pubkey via get_public_key after nostrconnect login
  fix(desktop): address code review findings for NIP-46 bunker login
  feat(desktop): add nostrconnect:// login flow for QR-based signer pairing
  revert: remove QR code scanning from login
  feat(desktop): webcam QR scanning via ffmpeg for bunker login
  feat(desktop): add webcam QR code scanning for bunker login
  feat(desktop): add QR code scanning for bunker login
  fix(desktop): clear stored credentials on logout
  feat(desktop): update login hints to mention bunker:// option
  fix(desktop): simplify settings logout to just a button
  feat(desktop): add logout option to menu bar and settings
  test: add NIP-46 test suite for desktop, quartz, and fix pre-existing chess test errors
  feat(desktop): add NIP-46 remote signer (bunker://) login
2026-03-11 08:42:44 -04:00
Vitor Pamplona 71574a5ce0 tracks and displays connection tentatives on relay settings 2026-03-11 08:42:32 -04:00
Vitor Pamplona ca9074e6f5 better relay parsing messaging 2026-03-11 08:17:14 -04:00
nrobi144 edf764709d fix: resolve conflicts with upstream PR #1789 merge
- Add missing commons domain files (BunkerLoginUseCase, NostrConnectLoginUseCase)
- Restore CoroutineScope in NostrSignerRemote for suspend decrypt call
- Update isolation test: upstream removed `since` filter (PR #1789)
- Add new INostrClient interface methods to TrackingNostrClient mock

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 10:35:56 +02:00
nrobi144 5475d6c2bc fix(desktop): verify user pubkey via get_public_key after nostrconnect login
The nostrconnect flow was trusting params[0] from the signer's connect
message as the user's pubkey. Some signers (e.g. nsec.app) don't put
the actual user pubkey there, causing all relay subscriptions to query
the wrong identity — contact lists, profiles, and DMs all returned empty.

Now calls remoteSigner.getPublicKey() after the handshake to get the
verified pubkey from the signer. Also stabilizes FeedScreen relay
subscriptions with distinctUntilChanged() and adds relay.primal.net
to defaults.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 10:20:18 +02:00
nrobi144 3a1e38a2f2 fix(desktop): address code review findings for NIP-46 bunker login
- Add bounds check in fromBunkerUri for missing query params (P2-1)
- Preserve bunker keys on transient force-logout (P2-3)
- Replace debug printlns with DebugConfig.log() (P2-4)
- Replace unused Unstable with Disconnected state (P2-5)
- Move validateBunkerUri to account package (P3-9)
- Fix Compose state update from IO thread (P3-11)
- Add disconnectNip46Client() to onDispose cleanup (P3-12)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 10:16:10 +02:00
nrobi144 12c91aae3d feat(desktop): add nostrconnect:// login flow for QR-based signer pairing
Adds client-initiated NIP-46 (nostrconnect://) flow so users can pair
with a remote signer (e.g. Amber) by scanning a QR code instead of
manually copying a bunker:// URI.

Changes:
- Fix RemoteSignerManager to decrypt NIP-44 content before parsing
- Add CoroutineScope to NostrSignerRemote for async event callbacks
- Add loginWithNostrConnect() to AccountManager with 120s timeout
- Add QrCodeCanvas composable using ZXing for QR generation
- Add "Connect" tab to LoginCard showing QR + copyable URI + waiting state
- Wire nostrconnect flow through LoginScreen

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 10:16:10 +02:00
nrobi144 1821b9ff71 test: add NIP-46 test suite for desktop, quartz, and fix pre-existing chess test errors
Add comprehensive test coverage for NIP-46 bunker login across quartz and desktopApp:

Quartz (4 files, 48 tests):
- ResponseParserTest: all 7 response parsers (success/error/unexpected)
- FromBunkerUriTest: URI parsing, validation, edge cases
- ConvertExceptionsTest: SignerResult→Exception mapping
- NostrConnectEventTest: canDecrypt, talkingWith, verifiedRecipientPubKey

Desktop (6 files, 45 tests):
- BunkerUriUtilsTest: validateBunkerUri + stripBunkerSecret
- AccountManagerKeyLoginTest: nsec/npub/invalid login, save, generate
- AccountManagerLogoutTest: logout, forceLogout, state transitions
- AccountManagerLoadAccountTest: internal/bunker/missing-key scenarios
- AccountManagerBunkerLoginTest: hasBunkerAccount, setConnectingRelays
- AccountManagerHeartbeatTest: start/stop, no-crash with internal signer

Production changes:
- AccountManager: constructor private→internal, add homeDir param for test injection, extract stripBunkerSecret to internal top-level, constants internal
- desktopApp/build.gradle.kts: add mockk test dependency

Fix pre-existing chess test compilation errors:
- ChessStateReconstructorTest: add missing jester subpackage imports
- ChessGameEventTest: altText()→alt() + add nip31Alts import

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 10:16:09 +02:00
Vitor Pamplona b4184d2235 Moves the upload file button closer to the image upload 2026-03-10 15:54:03 -04:00
Vitor Pamplona b2a8a422b2 - Breaks the new Import Follow interface into two screens
- Improves user suggestion search by evaluating specific nip-05s and npubs
2026-03-10 15:48:04 -04:00
Vitor Pamplona 558e8a2dd2 Adds constructor to DualCase class 2026-03-10 14:37:55 -04:00
Vitor Pamplona 1de38ad9ec Creates an interface for Nip05Client 2026-03-10 14:37:40 -04:00
Vitor Pamplona 835001bd6c Making nip05 client stable 2026-03-10 14:22:06 -04:00
Vitor Pamplona ab9ecdc939 Adds methods to follow a bunch of users at the same time 2026-03-10 11:12:23 -04:00
Vitor Pamplona ff4356ce31 Moves away from calling relay feeds "favorites" 2026-03-10 09:26:09 -04:00
Vitor Pamplona 50a578cfdc Fixes preview of relay information screen 2026-03-10 08:50:51 -04:00
Vitor Pamplona 97a3fcc9df Merge pull request #1785 from mstrofnone/feat/import-follow-list-namecoin
feat: import follow list with Namecoin resolution during signup
2026-03-10 08:14:24 -04:00
Vitor Pamplona 88e6825028 Merge pull request #1789 from nrobi144/fix/nip46-quartz-bugs
fix(quartz): fix NIP-44 key mutation and NIP-46 connect response handling
2026-03-10 08:08:08 -04:00
nrobi144 e56b0d2b83 fix(quartz): connect() returns Unit, caller calls getPublicKey separately
Per Amber maintainer: connect never returns a pubkey — response is
"ack" or the secret string. Rewrote ConnectResponse.parse() to check
result/error fields directly on base BunkerResponse (matching Jackson
deserialization). connect() is now a pure protocol handshake; callers
call getPublicKey() separately as a domain concern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 07:24:57 +02:00
Vitor Pamplona 2387a1bb91 Improves the order of search results 2026-03-09 11:25:00 -04:00
nrobi144 39393d328b fix(quartz): fix NIP-44 key mutation and NIP-46 connect response handling
Two bugs in quartz's NIP-46 remote signer:

1. FixedKey.getEncoded() returned the raw byte array reference. javax.crypto.Mac
   zeroes the key via destroy() after HMAC computation, corrupting the NIP-44
   saltPrefix ("nip44-v2") after the first computeConversationKey call. All
   subsequent NIP-44 decryptions with different key pairs fail with Invalid Mac.
   Fix: return key.copyOf() instead of key.

2. NostrSignerRemote.connect() only handled pubkey responses. Amber (and other
   signers) may respond with "ack" or "already connected" error. Added
   ConnectResponse parser that maps these to success and falls back to
   getPublicKey() to retrieve the actual pubkey.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 07:49:58 +02:00
Vitor Pamplona 991f1dfca5 spotless apply 2026-03-08 09:58:41 -04:00
M 8456b38dea feat: import follow list with Namecoin resolution during signup
Add a new signup step that lets users bootstrap their feed by importing
another profile's follow list. Supports all identifier types:

  - npub1... (NIP-19 bech32)
  - 64-char hex pubkey
  - alice@example.com (NIP-05 HTTP)
  - alice@example.bit / d/name / id/name (Namecoin blockchain)

Flow: Enter identifier → Resolve → Fetch kind 3 → Preview with
select/deselect → Apply follows → Done. Users can search multiple
profiles before continuing.

Changes to existing files:
  - NamecoinNameResolver: add resolveDetailed() + NamecoinResolveOutcome
  - NamecoinNameService: add resolveDetailed(), resolvePubkey()
  - AccountSessionManager: add isNewAccount flag, finishNewAccountSetup()
  - AccountScreen: route new accounts to ImportFollowListSection

New files:
  - FollowListImporter: identifier resolution + kind 3 fetch + parsing
  - ImportFollowListViewModel: state machine for the import flow
  - ImportFollowListScreen: UI with preview, select/deselect, search again
  - FollowListImporterTest: 14 unit tests
2026-03-08 15:38:54 +11:00
Claude 812f465608 refactor: improve URLDetector readability
- UrlDetector: simplify space handler in readDefault() — both branches
  of if/else were calling the same readEnd(InvalidUrl), making the
  conditional dead code; now we always call readEnd after attempting
  to read the domain
- UrlDetector: remove redundant inner buffer.isNotEmpty() check in
  readEnd(), already guarded by the outer condition
- UrlDetector: rename processColon() parameter from length to
  startLength to eliminate the var length = length self-shadowing
- UrlDetector: replace ArrayList<Url>() with mutableListOf<Url>()
  for idiomatic Kotlin
- DomainNameReader: replace lastSection.deleteRange(0, lastSection.length)
  with lastSection.clear() which expresses the intent directly
- DomainNameReader: move isDotPercent() and isXn() extension functions
  from inside the class body to private file-level functions — extension
  functions defined on a class instance are unusual and confusing

https://claude.ai/code/session_01Pci2AC45yQxQw6F6g7jWdd
2026-03-08 00:54:38 +00:00
Vitor Pamplona 9054e45310 Fixes test case 2026-03-07 16:55:12 -05:00
Vitor Pamplona 0e3ca7ac35 Merge branch 'main' of https://github.com/vitorpamplona/amethyst
* 'main' of https://github.com/vitorpamplona/amethyst: (35 commits)
  New Crowdin translations by GitHub Action
  fix chess tests
  Replace subsequent checks with '!isNullOrEmpty()' call
  use forEach: no intermediate list created.
  Use filterIsInstance to avoid dual iteration
  Lambda argument should be moved out of parentheses
  replace null checks with Elvis
  merge call chain with flatMap (slight performance improvement)
  New Crowdin translations by GitHub Action
  New Crowdin translations by GitHub Action
  update cz, pt, de, sv
  was this meant to be withContext?
  add names to boolean params
  remove unused imports
  Explicit type arguments can be inferred
  remove redundant modifiers
  correct package name
  If-Null return/break/... foldable to '?:'
  Declaration has type inferred from a platform call, which can lead to unchecked nullability issues. Specify type explicitly as nullable or non-nullable.
  Declaration has type inferred from a platform call, which can lead to unchecked nullability issues. Specify type explicitly as nullable or non-nullable.
  ...

# Conflicts:
#	amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ReactionsSettingsScreen.kt
2026-03-07 16:47:16 -05:00
Vitor Pamplona 966d02d89e Removes top level domain number of char limitations to accept nostr: uris 2026-03-07 16:41:11 -05:00
Vitor Pamplona e3f99051db Applies new UrlDetector to the RichTextViewer 2026-03-07 16:38:25 -05:00
Vitor Pamplona 030921c963 Adds treatment for the transition between ASCII and non-ASCII in the middle of urls 2026-03-07 15:19:24 -05:00
Vitor Pamplona 109a5e7cd7 Adds single label domains to parse nostr: urls too 2026-03-07 10:51:19 -05:00
davotoula 5658b14ad4 fix chess tests 2026-03-06 23:26:40 +01:00
Vitor Pamplona f4d401bc56 Switches to our own version of the Url Detector 2026-03-06 10:58:59 -05:00
M 4ecfbbb844 fix: add missing StateFlow import, merge duplicate KDoc blocks, and fix rebase conflicts
- Add missing 'import kotlinx.coroutines.flow.StateFlow' in SearchBarViewModel.kt
- Merge duplicate KDoc blocks on nameShowWithFallback in ElectrumXClient.kt
- Move NamecoinLookupException to ElectrumXServer.kt (avoid redeclaration)
- Remove duplicate NameShowResult/ElectrumxServer from ElectrumXClient.kt
- Fix ElectrumxClient -> ElectrumXClient renames in NamecoinNameService
- Extract namecoinElectrumxClient in AppModules.kt for NamecoinNameService.init()
- Update package paths from nip05.namecoin to nip05DnsIdentifiers.namecoin
2026-03-06 14:22:49 +11:00
M 050fd3a412 feat: propagate distinct error types from ElectrumX to search UI
Add NamecoinLookupException sealed class to distinguish:
- NameNotFound: name queried successfully but doesn't exist on blockchain
- NameExpired: name exists but expired (>36000 blocks since last update)
- ServersUnreachable: all ElectrumX servers failed with connection errors

Previously, all three cases returned null from nameShowWithFallback,
making it impossible for the UI to show meaningful feedback.

Changes:
- ElectrumxClient.connectAndQuery: throws NameNotFound/NameExpired
  instead of returning null for definitive blockchain answers
- ElectrumxClient.nameShow: lets NamecoinLookupException propagate
  (only catches connection/IO errors as null)
- ElectrumxClient.nameShowWithFallback: short-circuits on NameNotFound/
  NameExpired (no point trying other servers for definitive answers),
  throws ServersUnreachable when all servers fail with connection errors
- SearchBarViewModel: new namecoinSearchState flow with typed states
  (Idle/Loading/Resolved/NotFound/Expired/ServersUnreachable) for UI
  to show loading spinners, resolved profiles, and specific error
  messages. Derived namecoinResolvedUser from this flow.

Discovered while porting to notedeck (damus-io/notedeck#1314).
2026-03-06 14:15:11 +11:00
M ee418bdd0a fix: address race conditions and improve Namecoin NIP-05 resolution
Fixes discovered while porting Namecoin NIP-05 to Primal Android
(PrimalHQ/primal-android-app#934):

1. Race condition: stale intermediate lookups overwrite final result
   - Changed map to mapLatest in SearchBarViewModel so that previous
     in-flight ElectrumX lookups are cancelled when the query changes
   - Without this, typing 'd/testls' character by character causes
     stale results from 'd/test', 'd/testl' etc. to arrive after
     the correct 'd/testls' result and overwrite it with null

2. CancellationException swallowed in catch block
   - mapLatest cancels previous coroutines via CancellationException
   - The generic catch was catching it and emitting null, wiping the
     valid result. Now re-throws CancellationException

3. Root lookup fails when names object has no underscore key
   - extractFromDomainValue tried names[localPart] then names[underscore]
     which is the same thing for root lookups
   - Now falls back to first available entry for root lookups when
     no underscore key exists
   - Non-root lookups still fail correctly (no false matches)

4. Global Mutex serializes all lookups
   - Single Mutex in ElectrumxClient blocked unrelated lookups to
     different servers. A 25s timeout on one server stalled everything
   - Now uses per-server mutexes via ConcurrentHashMap

5. customServers set but never read
   - NamecoinNameService.setCustomServers() stored the list but the
     resolver was constructed with the default serverListProvider
   - Now wires customServers through to the resolver

6. resolveLive uses orphaned CoroutineScope
   - Now accepts an optional external scope parameter so callers can
     tie resolution to their own lifecycle

Adds 2 new tests: root fallback to first entry, non-root no-fallback.
2026-03-06 14:14:29 +11:00
Vitor Pamplona 4839535355 Fixes test case for new class names 2026-03-04 13:29:09 -05:00
Vitor Pamplona 1fa93788db android target seems to be creating some issues between plugin dependencies after adding spm 2026-03-04 12:19:47 -05:00
Vitor Pamplona da01c6ccd1 Moves smp plugin to version catalog 2026-03-04 12:18:55 -05:00
Vitor Pamplona d662cd6b64 Merge pull request #1757 from KotlinGeekDev/kmp-completeness
KMP Completeness, Part 1.
2026-03-04 10:27:24 -05:00
Vitor Pamplona 089600d7f0 Fixes test case 2026-03-04 10:26:21 -05:00
Vitor Pamplona 8501c86663 Further organizes Calendar events 2026-03-04 10:25:51 -05:00
Vitor Pamplona d3bab2f8cb Separate generics functions 2026-03-04 10:19:10 -05:00
Vitor Pamplona b563ab44b0 Merge pull request #1762 from vitorpamplona/claude/nip52-calendar-compliance-yXoXR
Add NIP-52 Calendar event builders and tag helpers
2026-03-04 10:06:03 -05:00
Vitor Pamplona 470b1680d0 Moves electrum client to the jvmAndroid scope 2026-03-04 10:00:33 -05:00
Vitor Pamplona 193561c336 Migrates to LruCache 2026-03-04 09:32:31 -05:00
Vitor Pamplona 9abd61e2de Improves package layout for nip64 chess 2026-03-04 09:25:38 -05:00