Skip to content

Implementation of Key management#34

Closed
chebizarro wants to merge 23 commits into
MostroP2P:mainfrom
chebizarro:key_management
Closed

Implementation of Key management#34
chebizarro wants to merge 23 commits into
MostroP2P:mainfrom
chebizarro:key_management

Conversation

@chebizarro

@chebizarro chebizarro commented Jan 3, 2025

Copy link
Copy Markdown
Contributor

This pull request implements key management as per the Mostro protocol specification.

An identity key is generated from a mnemonic when the user first opens the client and ephemeral trade keys are derived and used for each action.

Both identity and full privacy mode are implemented but identity mode is currently hard coded as the mostro daemon panics when attempting to unwrap a message with a null signature (see MostroP2P/mostro#414).

This PR also implements session management, with the identity key and details of each order stored using the secure storage mechanism of the respective platform between app restarts.

This PR also includes an initial implementation of the cant-do message type, with errors displayed to the user.

There is currently no mechanism to reset the user keys but this will be implemented in a forthcoming PR once the UX is finalized.

This PR has been tested against the current mostro daemon code base but there will still be edge cases that could cause issues with making and taking orders.

Summary by CodeRabbit

Based on the comprehensive summary of changes, here are the updated release notes:

  • New Features

    • Added advanced key management system with secure storage and key derivation.
    • Introduced session management for improved application state tracking.
    • Enhanced privacy controls with full privacy mode setting.
    • Implemented asynchronous app initialization for better loading experience.
    • Added new utilities for creating and managing Nostr events.
    • Introduced a new OrderNotifier for managing order state and updates.
    • Added support for handling new payload types in the application.
  • Bug Fixes

    • Improved error handling in message and order processing.
    • Refined navigation logic for order-related actions.
    • Enhanced null safety in order handling to prevent potential errors.
  • Refactoring

    • Restructured message and order model implementations.
    • Updated cryptographic key generation and storage mechanisms.
    • Simplified repository and service layer interactions.
    • Streamlined session management and message handling logic.
  • Security Improvements

    • Implemented more robust secure storage for sensitive data.
    • Enhanced key management with improved derivation techniques.
    • Updated session handling to ensure sensitive information is not exposed.

@coderabbitai

coderabbitai Bot commented Jan 3, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

This pull request introduces significant architectural changes to the Mostro Mobile application, focusing on key management, session handling, and initialization processes. The modifications enhance the application's security and initialization flow by introducing new classes like KeyManager, SessionManager, and KeyDerivator. The changes restructure how cryptographic keys are generated, stored, and managed, with a new emphasis on secure storage and privacy settings. The application now has a more robust initialization process that checks for master keys, manages sessions, and ensures proper key derivation.

Changes

File/Category Change Summary
App Initialization Added appInitializerProvider to manage app startup, including key generation, session initialization, and message loading
Key Management Introduced KeyDerivator, KeyManager, KeyStorage for secure key generation and management
Session Handling Replaced SecureStorageManager with new SessionManager for more flexible session control
Models Updated models like Order, Session, MostroMessage to support new key and privacy management
Storage Added SharedPreferencesKeys and SecureStorageKeys enums for structured key management
Configuration Modified app settings to use fullPrivacyMode instead of isFirstLaunch

Sequence Diagram

sequenceDiagram
    participant App
    participant AppInitializer
    participant KeyManager
    participant SessionManager
    participant MostroRepository

    App->>AppInitializer: Initialize
    AppInitializer->>KeyManager: Check Master Key
    alt No Master Key
        KeyManager->>KeyManager: Generate Master Key
    end
    AppInitializer->>SessionManager: Initialize Sessions
    AppInitializer->>MostroRepository: Load Messages
    AppInitializer-->>App: Initialization Complete
Loading

Poem

🐰 A Rabbit's Ode to Secure Keys

With whiskers twitching, code so bright,
Keys dancing in the cryptic light,
Sessions managed, privacy tight,
Our app now leaps with pure delight!

🔐✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (37)
lib/features/take_order/screens/take_sell_order_screen.dart (1)

122-122: Handle potential null value gracefully.

By switching to order?.amount, val may be null. Currently, if order is null, the screen prompts the user to enter an invoice for “null sats,” which may be confusing. Consider using a fallback value or preventing invoice submission when val is null.

Below is a possible improvement to handle a null val more gracefully:

-final val = order?.amount;
+final val = order?.amount ?? 0;
...
Text(
  "Please enter a Lightning Invoice for $val sats:",
  style: TextStyle(color: AppTheme.cream1, fontSize: 16),
),
...
onPressed: () {
  final invoice = invoiceController.text.trim();
  if (invoice.isNotEmpty && val != 0) {
    orderDetailsNotifier.sendInvoice(orderId, invoice, val);
  }
},
lib/services/nostr_service.dart (5)

82-84: Validate the private key input.
Currently, the method directly delegates to NostrUtils.generateKeyPairFromPrivateKey(privateKey). Consider adding input validation or exception handling so that invalid keys produce meaningful error messages rather than unexpected runtime exceptions within NostrUtils.


100-101: Add logging for decryption attempts.
While the method properly checks _isInitialized, the success or failure of decryption is not logged. Consider adding debug or info logs for improved traceability, especially since decryption failures are a common source of silent errors.


109-110: Add error handling for rumor creation.
The code delegates to NostrUtils.createRumor. Consider wrapping this in try-catch or verifying success to handle potential exceptions or null returns gracefully (if the utility method can fail).

Also applies to: 111-113


115-116: Add logging for sealing process.
Similar to rumor creation, the sealing process depends on a utility method. If an exception occurs, it may be challenging to locate the exact source. A small debug statement before or after the NostrUtils.createSeal call would assist in diagnosing issues in production.

Also applies to: 117-119


121-122: Clarify usage of createWrap parameters.
The method is straightforward, but consider clarifying how the sealedContent is derived and how recipientPubKey is validated—either via inline comments or parameter documentation. This will help other contributors integrate the method correctly.

Also applies to: 123-125

lib/data/models/cant_do.dart (2)

3-4: Consider documenting the class.
Providing a short class-level doc comment can help clarify the purpose and usage of this payload.


12-16: Implement the toJson method or remove the throw.
Currently, the method is unimplemented, which may lead to runtime errors if serialization is attempted.

Here’s a possible minimal implementation:

 Map<String, dynamic> toJson() {
-  throw UnimplementedError();
+  return {
+    'cant_do': cantDo,
+  };
 }
lib/data/models/session.dart (1)

12-12: Naming consistency between orderId and the JSON key event_id.
Using event_id in JSON but orderId in code may cause confusion. For consistency, consider aligning these names if possible.

lib/features/order/notfiers/order_notifier.dart (1)

24-37: Subscription error handling and logging are done well.
Consider a more robust logging mechanism or user feedback if the subscription fails repeatedly. Current design is appropriate for initial release.

lib/data/repositories/mostro_repository.dart (1)

74-80: saveMessages()
Iterates over _messages, writing each item. Be mindful of potential concurrency or performance with large message sets.

lib/data/repositories/session_manager.dart (2)

13-17: Expiration policy and constants
Defining sessionExpirationHours, cleanupIntervalMinutes, and maxBatchSize is straightforward. Evaluate if 48 hours is adequate in your usage context.


88-96: _decodeSession
Injecting the derived keys into the session map before calling Session.fromJson is clever. Confirm that using the same master key for each decode is expected.

lib/services/mostro_service.dart (2)

54-61: Consistent message creation for invoices
Using newMessage with Action.addInvoice keeps the logic consistent. The array payload [null, invoice, null] might benefit from a comment explaining these placeholders.


108-119: Unifying message creation
newMessage provides a single place to define the NIP-59 order structure. Consider adding a brief comment describing each field’s eventual use (e.g., request_id, trade_index).

lib/shared/utils/nostr_utils.dart (2)

147-165: Clarity in naming
The label “Rumor” might be non-obvious to new contributors. Consider adding a doc comment explaining that createRumor encrypts the kind=1 event content.


167-181: Duplicate logic with createRumor
createSeal shares a similar encryption flow. If the logic remains the same, consider unifying them to reduce repetition.

lib/app/app_settings.dart (3)

6-6: Typographical oversight
It’s spelled intial. Recommend renaming to initial for clarity.

-  factory AppSettings.intial() => AppSettings(fullPrivacyMode: false);
+  factory AppSettings.initial() => AppSettings(fullPrivacyMode: false);

8-9: copyWith method
Using a required fullPrivacyMode enforces explicit updates. Future expansions might benefit from optional named parameters if more properties are introduced.


11-11: Extra blank line
No functional impact, but consider removing if unintended.

lib/shared/providers/mostro_service_provider.dart (1)

5-6: Consider documenting the reason for separate providers.
The introduction of session_manager_provider.dart and storage_providers.dart is beneficial for a more modular design. However, it might be good to include short explanatory comments near these imports to clarify their roles—for instance, whether they provide secure or ephemeral session data.

lib/shared/providers/app_init_provider.dart (1)

7-22: Validate the order in which initialization steps occur.
The initialization sequence appears correct: master key check → generate key → session manager init → message loading → notifiers setup. However, be cautious about potential issues if any of these steps fail or take longer than expected (e.g., network calls, large message sets). Consider adding minimal logging or error handling to ensure that partial failures are properly traced and reported.

lib/features/key_manager/key_storage.dart (3)

10-12: Handle potential write failures or concurrency.
While writing the master key is straightforward, it's recommended to handle or log any possible failure scenarios (e.g., write(...) throwing an exception). Also verify that multiple concurrent writes from different screens or threads won't cause conflicts.


18-20: Make sure mnemonic usage is ephemeral if possible.
Use caution in storing mnemonics for prolonged periods. Best practice often emphasizes ephemeral in-memory usage for seed phrases to mitigate compromise risk. A disclaimer or doc note might be beneficial.


26-28: Handle possible index misconfiguration.
Storing an integer index for keys is straightforward, but ensure that the system references the correct index (especially if the user might reset or restore data). A fallback or validation step might help avoid corrupted states.

lib/main.dart (1)

18-20: Consider lazy initialization.

The SharedPreferencesAsync() and FlutterSecureStorage() instances are initialized eagerly during app startup. Consider deferring their instantiation until needed (lazy initialization) to improve startup performance, unless you have a specific requirement to initialize them at launch.

lib/features/key_manager/key_derivator.dart (3)

6-8: Keep class documentation short and clear.

The class doc comments are an excellent start. Consider adding an example usage snippet for KeyDerivator so other developers understand typical usage patterns.


17-20: Add negative tests.

isMnemonicValid returns a boolean, but consider how you handle invalid mnemonics in the broader system. It may be prudent to add negative test cases or explicit logging for invalid results in the calling code.


34-43: Handle neutered node scenarios robustly.

You already throw an exception if child.privateKey == null. It may be beneficial to detect whether the node is neutered at creation time or provide a fallback path. This can prevent partial, unhandled failures if the derivation path is not as expected.

lib/data/models/mostro_message.dart (2)

7-9: Document new fields.

The addition of id and tradeIndex is useful, but add doc comments to help future maintainers understand their purpose, especially how tradeIndex is derived or expected to be used.


12-12: Parameter order clarity.

The constructor’s parameters have grown. Consider rearranging or documenting them to clarify which fields are optional vs. required, and what each one represents.

lib/app/app.dart (2)

45-49: Loading state UI is straightforward.
Presenting a loading indicator is good. Consider adding a brand-appropriate splash or skeleton screen if there's potential for a prolonged initialization period.


50-54: Error state handling is appropriate.
Displaying the error message is good for debugging. For production, ensure that sensitive or cryptic error messages aren't exposed to the user.

test/services/key_derivator_test.dart (2)

46-50: Auto-generated mnemonic is validated.
Ensuring generated mnemonics pass your own validation logic is key. Could add negative tests where an invalid mnemonic is rejected to confirm error handling.


66-67: Future test group is ready for more.
Looks like a placeholder for additional Mostro-specific key derivation tests. Good forward planning.

Would you like me to draft any additional tests to accelerate coverage?

lib/data/models/order.dart (1)

59-62: Validate that always-including these fields is acceptable.
Be aware that always serializing created_at, expires_at, buyer_token, and seller_token, even if null, can introduce potential confusion or break systems expecting optional fields to be omitted.

pubspec.yaml (1)

91-91: Confirm the reintroduction of mockito.
Reinstating mockito helps with test mocks, but ensure that older or replaced mocking libraries are fully deprecated to avoid conflicts.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7aea2fb and da5b982.

⛔ Files ignored due to path filters (1)
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (38)
  • lib/app/app.dart (1 hunks)
  • lib/app/app_routes.dart (0 hunks)
  • lib/app/app_settings.dart (1 hunks)
  • lib/app/config.dart (1 hunks)
  • lib/data/models/cant_do.dart (1 hunks)
  • lib/data/models/enums/storage_keys.dart (1 hunks)
  • lib/data/models/mostro_message.dart (1 hunks)
  • lib/data/models/order.dart (2 hunks)
  • lib/data/models/payload.dart (2 hunks)
  • lib/data/models/session.dart (1 hunks)
  • lib/data/repositories/mostro_repository.dart (3 hunks)
  • lib/data/repositories/secure_storage_manager.dart (0 hunks)
  • lib/data/repositories/session_manager.dart (1 hunks)
  • lib/features/add_order/notifiers/add_order_notifier.dart (2 hunks)
  • lib/features/key_manager/key_derivator.dart (1 hunks)
  • lib/features/key_manager/key_manager.dart (1 hunks)
  • lib/features/key_manager/key_manager_errors.dart (1 hunks)
  • lib/features/key_manager/key_manager_provider.dart (1 hunks)
  • lib/features/key_manager/key_storage.dart (1 hunks)
  • lib/features/order/notfiers/order_notifier.dart (1 hunks)
  • lib/features/order/providers/order_notifier_provider.dart (1 hunks)
  • lib/features/take_order/notifiers/take_buy_order_notifier.dart (1 hunks)
  • lib/features/take_order/notifiers/take_sell_order_notifier.dart (1 hunks)
  • lib/features/take_order/screens/take_sell_order_screen.dart (1 hunks)
  • lib/main.dart (1 hunks)
  • lib/notifiers/mostro_orders_notifier.dart (0 hunks)
  • lib/services/mostro_service.dart (2 hunks)
  • lib/services/nostr_service.dart (3 hunks)
  • lib/shared/notifiers/app_settings_controller.dart (2 hunks)
  • lib/shared/providers/app_init_provider.dart (1 hunks)
  • lib/shared/providers/mostro_service_provider.dart (2 hunks)
  • lib/shared/providers/session_manager_provider.dart (1 hunks)
  • lib/shared/providers/shared_preferences_provider.dart (0 hunks)
  • lib/shared/providers/storage_providers.dart (1 hunks)
  • lib/shared/utils/nostr_utils.dart (1 hunks)
  • pubspec.yaml (2 hunks)
  • test/models/order_test.dart (1 hunks)
  • test/services/key_derivator_test.dart (1 hunks)
💤 Files with no reviewable changes (4)
  • lib/notifiers/mostro_orders_notifier.dart
  • lib/app/app_routes.dart
  • lib/shared/providers/shared_preferences_provider.dart
  • lib/data/repositories/secure_storage_manager.dart
✅ Files skipped from review due to trivial changes (1)
  • lib/app/config.dart
🔇 Additional comments (101)
lib/services/nostr_service.dart (1)

23-23: Favor consistent callback structure for maintainability.
The inline callback for onRelayListening is succinct, but consider inline documentation or at least a single comment if additional logic is introduced later (e.g., tracking all active relays, handling partial connections, etc.).

lib/data/models/cant_do.dart (1)

6-8: Validate presence and type of cant_do.
Consider verifying that json['cant_do'] is valid (e.g., non-null and a string). Throwing a more descriptive error can help with debugging when the field is missing or malformed.

lib/data/models/payload.dart (2)

1-1: Import statement check.
The import for cant_do.dart looks good, but ensure it does not introduce dependency cycles.


14-15: Confirm 'cant_do' key usage.
This logic is correct for handling the new cant_do payload. Verify that server responses consistently include this key and that it matches the renamed type if you decide to rename it.

lib/data/models/session.dart (4)

7-10: Consider verifying if keys should be serialized internally or handled only by SessionManager.
Storing complete key pairs directly in this class could lead to unintentional exposures if the object is serialized. Currently, toJson() avoids outputting these keys, which is good; however, explicitly clarifying whether these fields must remain in memory or if they need extra protection would improve clarity.


14-20: Constructor readability is good.
The constructor organizes required parameters effectively. Ensure that orderId defaults remain meaningful if not provided.


22-27: Confirm the intent to exclude cryptographic keys from toJson().
This approach is appropriate from a security standpoint, but if you intend to reconstruct the session object from JSON alone, the keys won't be restored unless you re-inject them, which you do later via SessionManager. Validate that this design aligns with app requirements.


32-37: Potential mismatch with toJson() for master/trade keys.
fromJson reads master_key and trade_key, yet these fields are absent in the toJson() output. This design offloads key restoration to separate storage, which is acceptable if carefully handled. Otherwise, storing partial data may lead to confusion.

lib/features/key_manager/key_manager.dart (7)

12-15: Method hasMasterKey() is straightforward.
This simple check is clear and efficient. Be sure to handle any potential storage exceptions upstream if needed.


17-26: Validate master key generation coverage and error handling.
While generating a new mnemonic and master key is correct, consider explicit error handling if _derivator.generateMnemonic() or _derivator.extendedKeyFromMnemonic(...) fails unexpectedly.


28-37: Good practice to throw MasterKeyNotFoundException.
Ensuring a consistent exception for missing keys is helpful. Consider clarifying if this condition indicates a first-time user or if it implies potential data corruption.


39-42: Retrieval of mnemonic is correct.
No concerns: returning null if no mnemonic is found is intuitive.


44-58: Incrementing the trading key index after derivation is appropriate.
Ensure concurrency control if multiple trade keys might be derived in parallel, e.g., by different parts of the code. Also double check that skipping await _storage.storeTradeKeyIndex(currentIndex + 1); on error won’t cause index misalignment.


60-69: deriveTradeKeyFromIndex(int index) method is efficient.
This approach is straightforward. Potential concurrency or re-entrancy issues with storing or skipping index updates do not apply here, so it’s simpler.


71-73: Method getCurrentKeyIndex() is neat.
This is a clean wrapper around _storage.readTradeKeyIndex().

lib/features/order/notfiers/order_notifier.dart (4)

9-14: Constructor clarifies initial state retrieval.
Instantiating state from getOrderById or defaulting to Action.notFound is sensible. Properly handles the scenario where the order does not exist.


39-41: Error handling with notifications is succinct.
This helps ensure the user is aware of streaming or connectivity issues. Possibly add reconnection logic if needed.


43-80: Switch-case usage for different actions is well-organized.
The separate handling for each Action is readable. Consider adding comments for unimplemented Action cases or merging them into a catch-all category only if you’re sure they never occur in normal operation.


83-87: Dispose logic is correct.
Canceling the subscription prevents memory leaks and ensures an orderly teardown.

lib/data/repositories/mostro_repository.dart (11)

2-3: Import usage recognized.
Reading and writing with json plus secure storage is sensible for sensitive data handling.


13-13: Storing the FlutterSecureStorage instance is fine.
Secure storage is a good choice for sensitive data. Just be careful when reading large volumes of data if performance is critical.


16-16: Changed _subscriptions key type
Now using int (aligned with session.keyIndex), which clarifies the subscription mapping.


18-18: Constructor injection
The repository now depends on both MostroService and FlutterSecureStorage. This is a positive shift for testability and single-responsibility.


20-21: Getter methods for messages
getOrderById and allMessages are straightforward. No immediate concerns.


23-41: Subscription logic persists messages to secure storage
Good approach for real-time updates. Make sure _messages remains consistent if storage writes fail. Potentially consider concurrency or partial failures.


43-44: Resubscribe by orderId
This is simplistic. As soon as orderId yields a session, re-establish the stream. Validate session != null upstream if the service unexpectedly returns null.


70-70: Asynchronous cancellation
Changing cancelOrder to a Future<void> is good for ensuring the call has completed.


82-86: saveMessage(MostroMessage)
Storing single messages is more granular than saveMessages(). Good approach for incremental updates.


88-91: deleteMessage
Cleanly deletes from in-memory cache and secure storage. This keeps data consistent and prevents orphans.


93-105: loadMessages()
Attempts to deserialize all known message entries. The try/catch is crucial to avoid halting on corrupted entries. Possibly add logging for partial failures.

lib/data/repositories/session_manager.dart (11)

8-12: Use of in-memory map _sessions
Reflecting sessions by keyIndex is logical. Keep in mind concurrency if multiple parts of the code might update sessions simultaneously.


18-20: Constructor auto-runs _initializeCleanup()
This is a useful pattern for housekeeping. Ensure that in test scenarios, you manage or mock out the timer.


22-36: Initialization from storage
Decoding all session entries in init() is good. Consider chunking or pagination if storage grows large.


38-53: newSession
Retrieves master key, obtains the next index, derives a trade key, and creates a Session. This is well-structured, but ensure concurrency is safe if multiple sessions or key derivations happen at once.


55-60: saveSession
Serializes and writes the session. The secure approach is consistent with the rest of the code.


62-68: getSessionByOrderId
Uses a simple .firstWhere approach. This is concise and left out concurrency complexities.


70-86: loadSession
Loads a session from storage if not cached. The error handling is correct. Might consider logging or removing the failing entry if decode fails.


98-102: deleteSession
Removes session from _sessions and secure storage. Straightforward.


104-134: clearExpiredSessions
Properly checks for expired sessions, removing them in manageable batches. This ensures that corrupted entries are also removed, which is beneficial for data integrity.


136-143: Cleanup timer
Periodic disposal of expired sessions is a nice strategy. Evaluate if user activity might require a more dynamic or event-based approach.


145-150: Dispose pattern
Cancels the timer to avoid memory leaks. Good practice.

lib/services/mostro_service.dart (13)

2-3: Imports for hashing and hex encoding
No issues found. Usage of crypto and convert is consistent and correct for cryptographic hashing and hex operations.


9-9: New import for session manager
Integration with the new SessionManager aligns with the key management refactoring in the PR.


14-14: Addition of SessionManager field
Storing _sessionManager as a final property centralizes session handling within MostroService.


16-16: Constructor updated to accept SessionManager
This change injects session capabilities into the service and keeps responsibilities clear.


19-28: Consider adding error handling in the subscription flow
Decryption errors in asyncMap will propagate as stream errors. This might be acceptable, but ensure the UI or calling code can gracefully handle and display such errors.


32-34: Simple pass-through
Fetching the session by order ID is straightforward. No issues noted.


39-39: Enhanced code structure for order-taking
Creating a new session for each order and leveraging newMessage clarifies the workflow for takeSellOrder. It improves readability and maintainability.

Also applies to: 48-49


65-68: Symmetry with takeSellOrder
Implementation parallels takeSellOrder with consistent handling for takeBuyOrder.


73-88: Robust handling of partial or full privacy
This method cleanly adjusts content based on the fullPrivacy flag. Signing logic is correct for the hashed JSON. Consider adding checks if message['order'] is null or malformed.


94-95: cancelOrder procedure
Straightforward usage of newMessage with Action.cancel. No immediate issues.


99-101: sendFiatSent utility
Consistent approach to building and sending the message. No concerns found.


103-106: releaseOrder procedure
Same pattern of message creation and sending, consistent with other actions.


146-161: Potential mismatch in key usage
createRumor is always passed session.tradeKey as the sender key pair, even when fullPrivacy is false and keySet = session.masterKey. Confirm this aligns with your intended cryptographic design and usage of keys.

lib/shared/utils/nostr_utils.dart (1)

198-227: Orchestrated encryption for NIP-59 events
This multi-step flow (rumor, seal, wrap) looks well-structured. Validate that isValidPrivateKey supports all key types (e.g., BIP32, ephemeral) to avoid cryptographic edge cases.

lib/app/app_settings.dart (2)

2-2: Renamed property for privacy
Switching from isFirstLaunch to fullPrivacyMode better reflects the feature’s function.


4-4: Mandatory constructor parameter
Enforcing initialization of fullPrivacyMode ensures its state is never ambiguous.

lib/features/key_manager/key_manager_errors.dart (2)

1-7: MasterKeyNotFoundException
Clear exception for missing master key scenarios. The custom message aids debugging.


9-15: TradeKeyDerivationException
Targeted exception class for derivation failures. Separating it from other errors improves maintainability.

lib/shared/providers/storage_providers.dart (2)

5-7: secureStorageProvider introduction
Providing a single FlutterSecureStorage instance across the app ensures consistency and easier testing.


9-11: sharedPreferencesProvider stub
Throwing UnimplementedError is an effective placeholder. Just ensure it’s overridden properly in main so no runtime error occurs.

lib/shared/providers/session_manager_provider.dart (2)

1-4: Imports look good.
All necessary imports are present for Riverpod, session management, key management, and storage.


6-10: Provider definition is coherent.
The sessionManagerProvider correctly composes the SessionManager by injecting required dependencies (keyManager, secureStorage) via ref.read. This approach aligns well with Riverpod best practices.

lib/features/order/providers/order_notifier_provider.dart (2)

1-4: Imports are appropriate.
Essential imports for the notifier, models, and repository have been included. Satisfies the requirements for Riverpod-based state management.


6-15: Use of StateNotifierProvider.family is correct.
The code properly constructs an OrderNotifier based on the orderId, ensuring each order is tracked separately. The usage of .watch() to retrieve the repository is clean and aligns with Riverpod.

lib/shared/notifiers/app_settings_controller.dart (3)

3-4: Imports updated to use shared providers and typed storage keys.
This is an improvement in maintainability. Explicit references to storage_keys.dart and storage_providers.dart reduce the chance of typos and mismatches.


14-16: Default privacy mode set to true.
By defaulting to true, users start with full privacy mode if no preference is set. Ensure this matches the desired UX.


18-18: State copy is straightforward.
Updating AppSettings with fullPrivacyMode is consistent with the new setting logic.

lib/features/key_manager/key_manager_provider.dart (1)

7-15: Key manager composition is sound.
Dependencies are retrieved from secureStorageProvider and sharedPreferencesProvider, encapsulated in KeyStorage, and combined with a specific derivation path in KeyDerivator. The pattern is consistent and modular.

lib/shared/providers/mostro_service_provider.dart (1)

16-17: Confirm that the secureStorageProvider meets all storage requirements.
While passing secureStorage to MostroRepository is logical, verify that MostroRepository is fully aware of encryption and data lifecycles. For example, confirm that this storage is suitable for all repository interactions where sensitive data is handled, and that error handling is in place to manage read/write failures.

lib/data/models/enums/storage_keys.dart (2)

1-25: Validate string-to-enum conversion logic.
Enums with a _valueMap significantly reduce the risk of typos when referencing storage keys. Double-check that each key's string correctly matches the usage throughout the codebase, especially around key_index vs. full_privacy. Additionally, ensure that the thrown ArgumentError is handled gracefully upstream.


27-53: Ensure consistency across secure storage keys.
The structure mirrors that of SharedPreferencesKeys, which is great for consistency. Review possible future expansions (e.g., ephemeral keys, refresh tokens) to confirm the naming scheme remains straightforward and predictable. This uniform approach helps maintain clarity and prevents collisions.

lib/features/key_manager/key_storage.dart (3)

5-9: Confirm that both FlutterSecureStorage and SharedPreferencesAsync align with security requirements.
Depending on the threat model, verify that storing the trade key index in shared preferences doesn't leak sensitive usage patterns. Consider disclaimers or documentation if partial data exposure is acceptable.


14-16: Balance convenience with security on read operations.
Reading the master key can be sensitive. Confirm that there are guardrails in place if this is called from multiple points, and that your code never logs or exposes the returned value.


30-32: Default index is 1; verify this matches the upstream logic.
Ensure the logic that increments or checks this index correlates with your app’s derivation strategy. If the app expects an initial index of 0 in certain scenarios, this could lead to subtle off-by-one issues.

lib/main.dart (2)

3-3: Ensure proper usage of these new imports.

The imports for flutter_secure_storage, storage_providers, and shared_preferences introduce secure storage and preference management. Confirm that platform differences (e.g., iOS Keychain vs. Android Keystore) are properly handled and that the new providers are used consistently throughout the codebase.

Also applies to: 8-8, 10-10


26-27: Double-check error handling on provider overrides.

While overriding these providers works for injecting shared preferences and secure storage, consider adding error trapping in case initialization fails (e.g., device-specific storage issues). This ensures you can handle such incidents gracefully during runtime.

test/models/order_test.dart (1)

38-38: Validate changes in JSON structure.

Switching from content to payload for accessing order reflects a new JSON structure. Ensure all usage across the codebase is consistently updated to avoid missing references to content. Also confirm that older references to content or a hybrid structure won't cause runtime errors or test failures.

lib/features/key_manager/key_derivator.dart (5)

1-4: Confirm library compatibility and updates.

These imports (bip39, bip32, convert, dart_nostr) rely on active maintenance and correct versioning. Ensure you're using up-to-date, stable versions of these cryptographic libraries and confirm they don’t conflict with each other or with the rest of the application.


11-12: Non-validated derivation path.

While you accept derivationPath in the constructor, confirm that you handle incorrect or unexpected formats. You might wish to add a format check or at least some default in case the derivation path is invalid.


13-16: Leverage cryptographic randomness best practices.

Your generateMnemonic() function delegates to bip39.generateMnemonic(). Ensure that the underlying random source meets cryptographic-grade randomness. In general, bip39 is secure, but be sure it remains updated.


21-27: Validate child index usage.

masterPrivateKeyFromMnemonic derives a child path by appending /0. Ensure this aligns with your specs for identity mode vs. ephemeral trade keys. Some standards use m/44'/... while others might differ. Confirm the correct path for your use case.


44-48: Check for off-by-one risk in key pair derivation.

privateToPublicKey uses dart_nostr to generate a public key. Confirm you’re deriving the correct index for your ephemeral or identity keys before calling this method to avoid accidental mismatch or reuse.

lib/data/models/mostro_message.dart (2)

19-20: Ensure backward compatibility.

You’re still writing 'request_id': id in the JSON. If older code expects 'request_id', confirm that it also handles the new field name 'id' properly or consider renaming the JSON key if consistent with your domain model.


30-35: Verify robust error handling and fallback logic.

Your factory method transitions from 'content' to 'payload', checks for 'cant-do', extracts 'tradeIndex', and sets 'id'. Ensure all edge cases are covered—especially if order, payload, or cant-do is missing or incomplete. This also applies to the new fields 'trade_index' and 'id', which might be absent in older or partial messages.

Also applies to: 41-42, 45-51

lib/features/take_order/notifiers/take_buy_order_notifier.dart (1)

39-39: Use caution with null assertion on state.id!.
While it's likely handled by upstream logic, forcing a null check with ! can throw an unhandled exception if id becomes unexpectedly null. Consider adding validation or a fallback to ensure safe navigation.

lib/app/app.dart (3)

10-10: Good addition of app_init_provider.dart.
Importing app_init_provider is essential for asynchronous initialization. Ensure that it remains a stable dependency to prevent circular imports.


17-17: Initialization state handling is well-structured.
Storing the initAsyncValue in a local variable clarifies the read operation from the provider. This improves readability compared to chaining method calls.


19-44: Handle final route changes in data state carefully.
Inside the data branch, you listen to the auth state and navigate the user accordingly. Confirm that the app won't re-trigger identical navigations when the AuthState transitions remain unchanged. If re-navigations are problematic, consider gating repeated calls based on the prior state.

lib/features/take_order/notifiers/take_sell_order_notifier.dart (1)

36-36: Method signature update to allow int? amount is consistent.
Ensuring amount can be null aligns with optional user inputs; confirm your repository and upstream calls can handle this scenario gracefully.

test/services/key_derivator_test.dart (6)

1-3: Test file organization looks good.
Import statements are minimal and purposeful. Great job keeping test dependencies clean.


4-6: Documentation references are clear and helpful.
Linking to NIP-06 ensures future readers can understand these test vectors.


7-9: Logical test grouping.
Creating a dedicated group for NIP-06 tests clarifies the purpose. Keep grouping consistent for future expansions.


10-26: Test Vector 1 covers essential checks.
The mnemonic validity, private key derivation, and public key checks comprehensively validate the first example. No improvements needed here.


28-44: Test Vector 2 demonstrates consistency.
Another thorough coverage of mnemonic validity, private, and public key derivations. Good job verifying a second vector for robust coverage.


52-63: Child key derivation test is thorough.
Verifying the derived key length alongside the exact expected hex fosters confidence in correctness.

lib/features/add_order/notifiers/add_order_notifier.dart (1)

30-31: Consider double-checking ID initialization to avoid null usage.
Currently, the ID is set to null, presumably awaiting assignment from an external source (e.g., a back-end response). Ensure that subsequent logic accounts for a potentially null ID, or supply a placeholder value if needed to prevent any runtime crashes before the id is set.

lib/data/models/order.dart (2)

36-36: Confirm that a default premium of 0 meets expected business logic.
Previously, the default was 1, so changing it to 0 could affect pricing or calculations downstream. Ensure no features implicitly rely on premium being 1.


54-55: Always including min_amount and max_amount might introduce null fields.
If the server or other clients expect these fields to be absent rather than null, it could cause data format issues. Verify that sending them as null is safe.

pubspec.yaml (2)

75-75: Check for compatibility of bip32 ^2.0.0 with existing cryptographic flows.
Switching from bip32_bip44 to bip32 might impact key derivation. Verify that all modules expecting BIP44 functionalities are updated accordingly.


92-92: Make use of build_runner for efficient code generation.
Having added build_runner can streamline code generation tasks (e.g., JSON serializable). Verify your build scripts are updated to leverage this dependency.

Comment on lines +77 to +78
//await AuthUtils.savePrivateKeyAndPin(
// keyPair.private, ''); // Consider adding a password parameter

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Ensure deliberate handling of private keys.
These lines are commented out but highlight a key area of concern: secure storage and retrieval of private keys. Before re-enabling, ensure that the private keys are protected by secure storage mechanisms (e.g., encrypted keystore) or appropriate password protection.

Would you like help making this more secure or a quick example code snippet demonstrating best practices with secure storage?

Comment thread lib/data/models/cant_do.dart Outdated
Comment on lines +122 to +144
Future<void> sendMessage(String orderId, String receiverPubkey,
Map<String, dynamic> content) async {
try {
final session = _sessionManager.getSessionByOrderId(orderId);
String finalContent;
if (!session!.fullPrivacy) {
content['order']?['trade_index'] = session.keyIndex;
final sha256Digest =
sha256.convert(utf8.encode(jsonEncode(content['order'])));
final hashHex = hex.encode(sha256Digest.bytes);
final signature = session.tradeKey.sign(hashHex);
finalContent = jsonEncode([content, signature]);
} else {
finalContent = jsonEncode([content, null]);
}
final event =
await createNIP59Event(finalContent, receiverPubkey, session);
await _nostrService.publishEvent(event);
} catch (e) {
// catch and throw and log and stuff
print(e);
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Null-safety and error handling
Using the forced non-null (session!) could cause runtime failures if the session is missing. A safer approach would be to handle null explicitly. Also, using structured logs might be preferable to print(e).

Comment on lines +183 to +192
static Future<NostrEvent> createWrap(NostrKeyPairs wrapperKeyPair,
String sealedContent, String recipientPubKey) async {
final wrapEvent = NostrEvent.fromPartialData(
kind: 1059,
content: sealedContent,
keyPairs: wrapperKeyPair,
tags: [
["p", recipientPubKey]
],
createdAt: createdAt,
createdAt: DateTime.now(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Wrap event creation
Using DateTime.now() here can reveal local system timing. For maximum privacy, consider adopting the randomNow() approach as in createSeal.

Comment thread lib/features/key_manager/key_derivator.dart
break;
case Action.payInvoice:
navProvider.go('/pay_invoice/${state.requestId!}');
navProvider.go('/pay_invoice/${state.id!}');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Prevent potential runtime error if state.id is null.
Similarly to the previous block, calling state.id! without verifying non-null can cause a crash. Validate id before navigation.

switch (state.action) {
case Action.newOrder:
navProvider.go('/order_confirmed/${state.requestId!}');
navProvider.go('/order_confirmed/${state.id!}');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Guard against null id before navigation.
Using state.id! assumes the field will never be null at this point. If there's any chance the ID could remain uninitialized, the app will crash. Consider guarding against null or providing an alternative path.

- navProvider.go('/order_confirmed/${state.id!}');
+ if (state.id != null) {
+   navProvider.go('/order_confirmed/${state.id}');
+ } else {
+   notifProvider.showInformation('Order ID is missing; cannot proceed.');
+ }

Committable suggestion skipped: line range outside the PR's diff.

Fixes type

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

@Catrya Catrya left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error when taking an order that I previously cancelled

When I take a sales order I use trade key X. If I cancel it before entering the invoice, the order is republished in pending status again. If I take it again later, I use trade key Y to send the take-sell action. When I enter the invoice, this appears in the mostrod logs:

2025-01-07T04:02:08.499413Z ERROR mostrod::app::add_invoice: Buyer pubkey not found for order c1fdf86b-99df-4f3c-a6b3-26ca787bf017!

I think it is because the client is sending the message with the add-invoice action with trade key X instead of with trade key Y, which is the correct one. I assume this because the same error occurs in mostro-cli, and when I take that order for the second time, it does not go through the screen of whether to take the order or not, but instead goes directly to the screen of entering the invoice, this one:
Captura desde 2025-01-06 23-10-36

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
lib/features/take_order/screens/add_lightning_invoice_screen.dart (1)

Line range hint 41-54: Enhance security for sensitive invoice data.

Given that this PR implements key management functionality, we should ensure sensitive payment data is handled securely.

Consider implementing:

  1. Secure text input that prevents screenshots
  2. Clear invoice data from memory after submission
  3. Avoid logging invoice details
  TextFormField(
    controller: invoiceController,
    style: const TextStyle(color: AppTheme.cream1),
+   obscureText: false, // Consider making this configurable
+   enableSuggestions: false,
+   autocorrect: false,
    decoration: InputDecoration(
      border: OutlineInputBorder(
        borderRadius: BorderRadius.circular(8),
      ),
      labelText: "Lightning Invoice",
      labelStyle: const TextStyle(color: AppTheme.grey2),
      hintText: "Enter invoice here",
      hintStyle: const TextStyle(color: AppTheme.grey2),
      filled: true,
      fillColor: AppTheme.dark1,
+     // Add visual indicator for secure input
+     prefixIcon: const Icon(Icons.security),
    ),
  ),

Also, ensure to clear the invoice data:

@override
void dispose() {
  // Clear sensitive data
  invoiceController.clear();
  super.dispose();
}
🧹 Nitpick comments (1)
lib/features/take_order/screens/add_lightning_invoice_screen.dart (1)

Line range hint 88-93: Enhance invoice submission with validation and feedback.

The current implementation lacks proper validation and user feedback for the invoice submission process.

Consider adding:

  1. Lightning invoice format validation
  2. Loading state during submission
  3. Error handling
  4. Success feedback
  onPressed: () {
+   if (!mounted) return;
    final invoice = invoiceController.text.trim();
-   if (invoice.isNotEmpty) {
-     mostroRepo.sendInvoice(orderId, invoice);
+   if (invoice.isEmpty) {
+     ScaffoldMessenger.of(context).showSnackBar(
+       const SnackBar(content: Text('Please enter an invoice')),
+     );
+     return;
+   }
+   
+   // Basic BOLT11 invoice format validation
+   if (!invoice.toLowerCase().startsWith('ln')) {
+     ScaffoldMessenger.of(context).showSnackBar(
+       const SnackBar(content: Text('Invalid Lightning invoice format')),
+     );
+     return;
+   }
+   
+   showDialog(
+     context: context,
+     barrierDismissible: false,
+     builder: (context) => const Center(child: CircularProgressIndicator()),
+   );
+   
+   try {
+     await mostroRepo.sendInvoice(orderId, invoice);
+     if (!mounted) return;
+     Navigator.pop(context); // Dismiss loading
+     context.go('/success'); // Navigate to success screen
+   } catch (e) {
+     if (!mounted) return;
+     Navigator.pop(context); // Dismiss loading
+     ScaffoldMessenger.of(context).showSnackBar(
+       SnackBar(content: Text('Failed to submit invoice: ${e.toString()}')),
+     );
    }
  },
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d17946 and f295e4a.

📒 Files selected for processing (3)
  • lib/features/key_manager/key_manager_provider.dart (1 hunks)
  • lib/features/take_order/notifiers/take_sell_order_notifier.dart (1 hunks)
  • lib/features/take_order/screens/add_lightning_invoice_screen.dart (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/features/take_order/notifiers/take_sell_order_notifier.dart
  • lib/features/key_manager/key_manager_provider.dart
🔇 Additional comments (1)
lib/features/take_order/screens/add_lightning_invoice_screen.dart (1)

6-6: LGTM! Clean import additions.

The new imports are well-organized and properly support the enhanced order management functionality.

Also applies to: 10-10

Comment thread lib/features/take_order/screens/add_lightning_invoice_screen.dart Outdated
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🔭 Outside diff range comments (1)
lib/features/take_order/screens/add_lightning_invoice_screen.dart (1)

Line range hint 104-109: Add validation and error handling to the submit flow.

The submit flow could benefit from:

  1. Lightning invoice format validation
  2. Error handling similar to the cancel flow
  3. Loading state during submission
                       onPressed: () {
                         final invoice = invoiceController.text.trim();
-                        if (invoice.isNotEmpty) {
-                          mostroRepo.sendInvoice(orderId, invoice);
+                        if (!isValidLightningInvoice(invoice)) {
+                          ScaffoldMessenger.of(context).showSnackBar(
+                            const SnackBar(content: Text('Please enter a valid Lightning invoice')),
+                          );
+                          return;
+                        }
+                        try {
+                          mostroRepo.sendInvoice(orderId, invoice);
+                          context.go('/');
+                        } catch (e) {
+                          ScaffoldMessenger.of(context).showSnackBar(
+                            SnackBar(content: Text('Failed to submit invoice: ${e.toString()}')),
+                          );
                         }
                       },
🧹 Nitpick comments (1)
lib/features/take_order/screens/add_lightning_invoice_screen.dart (1)

71-81: Enhance error handling and logging.

Consider improving the error handling:

  1. Add logging for unexpected action types in the default case
  2. Consider tracking cancellation errors in analytics for better monitoring
                           switch (message.action) {
                             case action.Action.takeBuy:
                               ref.read(takeBuyOrderNotifierProvider(orderId).notifier).dispose();
                               break;
                             case action.Action.takeSell:
                               ref.read(takeSellOrderNotifierProvider(orderId).notifier).dispose();
                               break;
                             default:
-                              // Log unexpected action type
+                              debugPrint('Unexpected action type: ${message.action}');
+                              // Consider adding analytics tracking here
                               break;
                           }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f295e4a and d81f1cb.

📒 Files selected for processing (1)
  • lib/features/take_order/screens/add_lightning_invoice_screen.dart (2 hunks)
🔇 Additional comments (2)
lib/features/take_order/screens/add_lightning_invoice_screen.dart (2)

6-6: LGTM! Import statements are properly organized.

The new imports are necessary for the enhanced cancel order flow and follow proper conventions.

Also applies to: 10-10


63-92: ⚠️ Potential issue

Fix critical issues in the cancel order flow.

There are several issues in the current implementation:

  1. mostroRepo.cancelOrder(orderId) is called twice (before and inside try-catch)
  2. The navigation call after try-catch is unreachable
  3. Navigation occurs even if cancellation fails

Apply this diff to fix the issues:

-                        mostroRepo.cancelOrder(orderId);
                         try {
                           if (message == null) {
                             context.go('/');
                             return;
                           }
                           
                           // Dispose notifier first
                           switch (message.action) {
                             case action.Action.takeBuy:
                               ref.read(takeBuyOrderNotifierProvider(orderId).notifier).dispose();
                               break;
                             case action.Action.takeSell:
                               ref.read(takeSellOrderNotifierProvider(orderId).notifier).dispose();
                               break;
                             default:
                               // Log unexpected action type
                               break;
                           }
                           
                           // Then cancel order
                           mostroRepo.cancelOrder(orderId);
                           context.go('/');
                         } catch (e) {
                           // Show error to user
                           ScaffoldMessenger.of(context).showSnackBar(
                             SnackBar(content: Text('Failed to cancel order: ${e.toString()}')),
                           );
-                        }
-                        context.go('/');
+                        }

Run this script to check for similar patterns in other files:

✅ Verification successful

Confirmed: Double cancellation issue is isolated to this file

The review comment is correct. The double cancellation and navigation issues are unique to add_lightning_invoice_screen.dart. Other files in the codebase implement the cancel order flow correctly with a single call to cancelOrder.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential double cancellation patterns in other files
# Look for files that might have similar cancel order implementations

rg -l "cancelOrder.*context\.go" 

Length of output: 34


Script:

#!/bin/bash
# Search for cancelOrder calls and their context
rg "cancelOrder" -A 5 -B 5

# Search for files containing both mostroRepo and context.go
rg -l "mostroRepo.*context\.go|context\.go.*mostroRepo"

Length of output: 6261

@Catrya Catrya left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @chebizarro

When a buyer takes a sales order and cancels it before entering the invoice, the client shows it again in the order list because it is again in Pending status (that's fine) But then when they tries to take it again, it doesn't even go to waiting-buyer-invoice status but the order remains in Pending, however from the client it goes directly to the screen to enter the invoice and when doing so mostrod shows: 2025-01-14T16:09:27.602868Z ERROR mostrod::app::add_invoice: Buyer pubkey not found for order 0450429e-8b4d-4491-b05f-2495bdd1bc5e!

  • I can't test that same error when taking a purchase order, because this screen appears when taking it (order goes to status waiting-payment)
    Captura desde 2025-01-14 11-25-42

  • If I try to take a sell order with range this comes out
    Captura desde 2025-01-14 11-18-16

  • If I try to take a purchase order with range even if I put the amount of sats I want to buy, mostrod sends Cant-do with out_of_range_fiat_amount I suppose the client is not sending that amount

  • Range orders cannot be created yet

  • When creating orders the fixed button does not work. It also requires that the amount of sats must be completed, otherwise it will not be created, however that amount of sats is not sent to mostrod because it is always published at market price

@grunch

grunch commented Feb 22, 2025

Copy link
Copy Markdown
Member

This PR code is moved to wip branch right? can we close this one?

@grunch

grunch commented Feb 23, 2025

Copy link
Copy Markdown
Member

I'm closing this one in favor of wip branch, re-open it if is needed @chebizarro

@grunch grunch closed this Feb 23, 2025
chebizarro added a commit that referenced this pull request Apr 27, 2025
* added KeyManager class

* Add key manager and related providers

* added full privacy mode setting to app settings

* Changed SecureStorageManager to SessionManager

* Moved session storage/retrieval to SessionManager

* Added separate wrap, seal and rumor functions

* master key and trade key integration

* minor edits

* Minor fixes to session expiration

* implementation of key manager features

* verified sending new orders with full privacy

* message and session serialization and retrieval

* updated mostro message to handle cant-do

* Implementation of order persistence between restarts

* change order > content to order > payload

* Initialize and load sessions at startup

* Change rumor content to array

* Debugging signing

* Added support for cant-do

* add buy/sell order now working

* Update lib/data/models/cant_do.dart

Fixes type

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* should fix #34 (review)

* Update lib/features/take_order/screens/add_lightning_invoice_screen.dart

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* added localization extension for retrieving localized strings based on Action type and AbstractOrderNotifier to consolidate orders

* Consolidate all OrderNotifiers as subclasses of AbstractOrderNotifier

* minor changes to order notifier and notification notifiers

* Filter user orders and updated Add Order screen to match web client

* Added OrderBook feature

* Added Drawer to Home Screen

* Unifed order provider fixed

* added Chat and Database support

* Rationalised TakeOrderNotifier

* removed bloc dependancy

* Added integration and mocked unit tests

* Integration tests for Create Sell Order

* Added Key Management and Relay screens

* Added extra key manager methods for importing existing key

* Added rating feature

* renamed order book and chat to trades and messages respectively

* switch persistence to sembat and updated dart_nostr to latest version

* updated mostro storage to use sembast

* Clear caches

* update tests

* Added Mostro Instance Screen and updated OrderNotifier strings

* Add QR Code Reader to Lightning Invoice screen

* Separate our Lightning invoice components to widgets

* Consolidated Drawer Screens

* Order Screens complete

* Updated launch icons

* Major revisions

* Changes to startup and added web support

* Added public test nostr relay and daemon as default

* set permissions for secure storage

* UX clean up

* Add mostro pubkey filter getting events

* fixed privacy mode

* added default relay

* Updated Settings Screen

* update build workflow

* More buildflow fixes

* Updated Take Order Screen and Home Screen Order List

* improve Lightning Invoice Screen

* Improve images

* Add currency flag to my trades widget

* Fix alignment on currency flag

* Fix take order bug

* fix for build action

* works in full privacy mode

* refactored app settings to be more reactive

* More settings refactoring

* Modified signing function

* start of mostro service refactor

* Refactored Mostro Service
Updated My Trades Detail Screens
Added 'Fiat Sent' and 'Release' buttons to My Trades Detail Screens
Refactored Order Providers
Added Mobile App Version and Git Hash to About Screen

* Fixes error creating new order with ln address #38
Updated release build script
Updated dependencies

* Addresses When creating a new identity, the orders from the previous identity are not forgotten #36

* Started ChatRoom refactor
Updated Action and CantDo enums
Updated CantDo and Action string suggestions

* Updated i10n strings to latest suggestions
Included separate CantDo strings in i10n
Added MostroMessageDetail widget to TradeDetailScreen

* Implementation of Rate Counterpart

* Partial implementation of Increment trade index only on success #35

* Changed AddLightingForm to back to the Home Screen on back/close

* Revert Increment trade index only on success #35 fix

* Major refactor of MostroService including deprecation of MostroRepository
All MostroRepoistory in memory persistence operations are now embedded in MostroStorage which is now a direct dependency of MostroService

* Added BaseStorage abstract class
Refactored Session Management
Refactored Order Hnadling
Major breaking changes

* Pay Invoice button added as per Add a Show Invoice button to the seller in status Waiting-payment #49

* Cancel button should appear for relevant order states Button cancel in all screens in active status #42

* First cut of Mostro Chat

* Updated Drawer
Added Walkthrough Feature

* Refdactored Data Storage and Notifiers

* Updated Settings and Account Screens

* add IT locale

add IT locale translations arb file

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Francisco Calderón <[email protected]>
Co-authored-by: devbtcp <[email protected]>
chebizarro added a commit that referenced this pull request May 8, 2025
* added KeyManager class

* Add key manager and related providers

* added full privacy mode setting to app settings

* Changed SecureStorageManager to SessionManager

* Moved session storage/retrieval to SessionManager

* Added separate wrap, seal and rumor functions

* master key and trade key integration

* minor edits

* Minor fixes to session expiration

* implementation of key manager features

* verified sending new orders with full privacy

* message and session serialization and retrieval

* updated mostro message to handle cant-do

* Implementation of order persistence between restarts

* change order > content to order > payload

* Initialize and load sessions at startup

* Change rumor content to array

* Debugging signing

* Added support for cant-do

* add buy/sell order now working

* Update lib/data/models/cant_do.dart

Fixes type

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* should fix #34 (review)

* Update lib/features/take_order/screens/add_lightning_invoice_screen.dart

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* added localization extension for retrieving localized strings based on Action type and AbstractOrderNotifier to consolidate orders

* Consolidate all OrderNotifiers as subclasses of AbstractOrderNotifier

* minor changes to order notifier and notification notifiers

* Filter user orders and updated Add Order screen to match web client

* Added OrderBook feature

* Added Drawer to Home Screen

* Unifed order provider fixed

* added Chat and Database support

* Rationalised TakeOrderNotifier

* removed bloc dependancy

* Added integration and mocked unit tests

* Integration tests for Create Sell Order

* Added Key Management and Relay screens

* Added extra key manager methods for importing existing key

* Added rating feature

* renamed order book and chat to trades and messages respectively

* switch persistence to sembat and updated dart_nostr to latest version

* updated mostro storage to use sembast

* Clear caches

* update tests

* Added Mostro Instance Screen and updated OrderNotifier strings

* Add QR Code Reader to Lightning Invoice screen

* Separate our Lightning invoice components to widgets

* Consolidated Drawer Screens

* Order Screens complete

* Updated launch icons

* Major revisions

* Changes to startup and added web support

* Added public test nostr relay and daemon as default

* set permissions for secure storage

* UX clean up

* Add mostro pubkey filter getting events

* fixed privacy mode

* added default relay

* Updated Settings Screen

* update build workflow

* More buildflow fixes

* Updated Take Order Screen and Home Screen Order List

* improve Lightning Invoice Screen

* Improve images

* Add currency flag to my trades widget

* Fix alignment on currency flag

* Fix take order bug

* fix for build action

* works in full privacy mode

* refactored app settings to be more reactive

* More settings refactoring

* Modified signing function

* start of mostro service refactor

* Refactored Mostro Service
Updated My Trades Detail Screens
Added 'Fiat Sent' and 'Release' buttons to My Trades Detail Screens
Refactored Order Providers
Added Mobile App Version and Git Hash to About Screen

* Fixes error creating new order with ln address #38
Updated release build script
Updated dependencies

* Addresses When creating a new identity, the orders from the previous identity are not forgotten #36

* Started ChatRoom refactor
Updated Action and CantDo enums
Updated CantDo and Action string suggestions

* Updated i10n strings to latest suggestions
Included separate CantDo strings in i10n
Added MostroMessageDetail widget to TradeDetailScreen

* Implementation of Rate Counterpart

* Partial implementation of Increment trade index only on success #35

* Changed AddLightingForm to back to the Home Screen on back/close

* Revert Increment trade index only on success #35 fix

* Major refactor of MostroService including deprecation of MostroRepository
All MostroRepoistory in memory persistence operations are now embedded in MostroStorage which is now a direct dependency of MostroService

* Added BaseStorage abstract class
Refactored Session Management
Refactored Order Hnadling
Major breaking changes

* Pay Invoice button added as per Add a Show Invoice button to the seller in status Waiting-payment #49

* Cancel button should appear for relevant order states Button cancel in all screens in active status #42

* First cut of Mostro Chat

* Updated Drawer
Added Walkthrough Feature

* Refdactored Data Storage and Notifiers

* Updated Settings and Account Screens

* add IT locale

add IT locale translations arb file

* added background services

* Added changes to background interface and upgraded MacOS settings

* synchronize background services

* Now uses two separate databases

* ensure NostrService init

* Rebuild of out of date annotated classes

* add isRunning property to BackgroundService

* Remove extra event call

* Add lifecycle manager and refactor background service database paths

* Revert MostrService and ChatRoomNotifier to subscribing directly in the foreground

* Set background services to only run on app suspend

* Startup modifications

* Refactored background service

* Replace route builders with pageBuilder to add fade transitions between screens

* Added isRunning callback

* renamed notification icon

* Add background service capabilities and persistent notifications for iOS/Android

* Mo background changes

* Avoid race conditions when app is backgrounded

* Add logging and improve app state transitions between foreground/background

* Add NostrResponsiveButton widget and refactor order repository reload logic

* Add async state handling and refresh functionality to trades screen

* Refactor buttons using NostrResponsiveButton and improve state management for trade actions

* Refactor message handling to use Sembast storage streams instead of EventBus

* Add stream providers and watch methods for sessions and messages

* Refactor storage and session providers, add error handling and remove unused code

* Add auto-reset to button and improve order request ID generation for uniqueness

* Fix order stream to emit cached events immediately and handle empty states

* Refactor storage repositories to use base class and improve message handling

* Add FSM-based order status tracking and update UI to use canonical status provider

* Refactor message stream to use watchAllMessages and emit latest message

* More refactoring of MostroStorage

* Modified status source in TradesDetailScreen and MostroMessageDetailWidget

* Change Lifecycle to mobile only and Modify MostroStorage

* Separated events and orders databases into separate files to prevent  race conditions between the main and background isolates

* Fix order not saving pubkeys when serialized

* Refactor message storage and retrieval to use latest messages consistently

* Fix message watching and improve order notifier initialization

* Add TradeState model and providers to manage trade status and actions

* Cleanup TradeDetailScreen

* Convert FutureProvider to StreamProvider for real-time order updates

* Make mostroService and eventStorage providers keepAlive and remove cancel action handling

* Add dispose logic for order notifiers and handle order cancellation cleanup

* Refactor NostrResponsiveButton to use direct action/orderId instead of state providers

* Rename NostrResponsiveButton to MostroReactiveButton and update references

* Fix chat message deduplication and add sorting by creation timestamp

* Add notification permissions and enhance notification settings for Android/iOS

* Simplify reloadData by removing event clearing and empty list emission

* Improve chat reliability and add event persistence with lifecycle management

* Replace event provider with mostro storage and remove duplicate event check

* Only request notifications on Android and filter sessions newer than 48 hours

* Only subscribe to sessions created within the last 24 hours

* Refactor session updates and add terminal status checks for active orders

* Refactor button styles and remove hardcoded dimensions from reactive buttons

* Filter chats older than 36h and fix session orderId update logic

* Fix order notifier disposal and add Italian localization

* Refactor background service and storage management; remove unused repositories and improve button functionality

* Refactor notification handling, improve order update logic, and enhance button customization

* Refactor notification service to use a single instance of FlutterLocalNotificationsPlugin and update MostroReactiveButton styles to use outlined and text button themes; remove unused rxdart dependency

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Francisco Calderón <[email protected]>
Co-authored-by: devbtcp <[email protected]>
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