Interface VoucherBackupPort


public interface VoucherBackupPort
Port for voucher backup operations (private user storage).

This port defines the interface for backing up and restoring vouchers to/from private user storage. In the Nostr implementation, this uses NIP-17 (private direct messages) with NIP-44 (versioned encryption) for secure, private backup.

Hexagonal Architecture

This is a port (interface) in hexagonal architecture terminology. The actual implementation (adapter) is provided by the infrastructure layer (e.g., NostrVoucherBackupRepository in cashu-voucher-nostr module).

Design Principles

  • Infrastructure-agnostic: No dependencies on Nostr or any specific storage
  • Pluggable: Can be implemented with Nostr, IPFS, encrypted cloud storage, etc.
  • Privacy-first: Backups are private to the user (encrypted with user's key)
  • Testable: Easy to mock for unit testing application services

Why Backup is Needed

Unlike deterministic secrets (NUT-13), vouchers are non-deterministic. If a user loses their wallet, they cannot regenerate voucher secrets from a seed phrase. Therefore, vouchers MUST be backed up to recoverable storage.

Security Considerations

  • Backups are encrypted with the user's Nostr private key (or equivalent)
  • Only the user can decrypt their own voucher backups
  • The backup port does not handle encryption - that's the adapter's responsibility

Example Usage

 // Backing up vouchers
 List<SignedVoucher> vouchers = wallet.getVouchers();
 backupPort.backup(vouchers, userNostrPrivateKey);

 // Restoring vouchers after wallet loss
 List<SignedVoucher> restored = backupPort.restore(userNostrPrivateKey);
 wallet.addVouchers(restored);
 
See Also:
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    backup(List<SignedVoucher> vouchers, String userPrivateKey)
    Backs up a list of vouchers to private user storage.
    default void
    deleteBackups(String userPrivateKey)
    Deletes all backups for the given user.
    default boolean
    hasBackups(String userPrivateKey)
    Checks if backups exist for the given user.
    restore(String userPrivateKey)
    Restores vouchers from private user storage.
  • Method Details

    • backup

      void backup(List<SignedVoucher> vouchers, String userPrivateKey)
      Backs up a list of vouchers to private user storage.

      This method encrypts and stores the vouchers in a way that only the user can retrieve them using their private key. The backup is typically incremental - calling this multiple times may append to or replace previous backups depending on the implementation.

      Backup format considerations:

      • Vouchers should be serialized in a stable format
      • Backup should include metadata (timestamp, version)
      • Encryption should use strong, modern algorithms (e.g., NIP-44)

      Implementation Notes

      Nostr implementation (NIP-17 + NIP-44):

      • Creates encrypted DM to self with voucher data
      • Uses NIP-44 versioned encryption
      • Tags with "cashu-voucher-backup" for easy retrieval
      Parameters:
      vouchers - the list of vouchers to backup (must not be null, can be empty)
      userPrivateKey - the user's private key for encryption (format depends on implementation)
      Throws:
      IllegalArgumentException - if parameters are invalid
      RuntimeException - if backup fails (network, storage, encryption, etc.)
    • restore

      List<SignedVoucher> restore(String userPrivateKey)
      Restores vouchers from private user storage.

      This method retrieves and decrypts all voucher backups associated with the user's private key. If multiple backups exist, they are merged and deduplicated (by voucher ID, with newest timestamp winning).

      The returned list includes all vouchers that have ever been backed up, regardless of their current status. The caller is responsible for:

      • Checking voucher status against the public ledger
      • Filtering out redeemed/expired vouchers if desired
      • Handling conflicts with existing wallet state

      Implementation Notes

      Nostr implementation:

      • Queries all NIP-17 DMs tagged "cashu-voucher-backup"
      • Decrypts each using NIP-44
      • Merges and deduplicates by voucher ID
      Parameters:
      userPrivateKey - the user's private key for decryption (format depends on implementation)
      Returns:
      list of restored vouchers (never null, but may be empty if no backups found)
      Throws:
      IllegalArgumentException - if userPrivateKey is invalid
      RuntimeException - if restore fails (network, storage, decryption, etc.)
    • hasBackups

      default boolean hasBackups(String userPrivateKey)
      Checks if backups exist for the given user.

      This is a convenience method to check if any voucher backups are available without actually downloading and decrypting them.

      Default implementation calls restore(String) and checks if the result is non-empty. Implementations may override with a more efficient check.

      Parameters:
      userPrivateKey - the user's private key (format depends on implementation)
      Returns:
      true if at least one backup exists, false otherwise
      Throws:
      IllegalArgumentException - if userPrivateKey is invalid
      RuntimeException - if check fails (network, storage, etc.)
    • deleteBackups

      default void deleteBackups(String userPrivateKey)
      Deletes all backups for the given user.

      This is an optional operation. Some implementations may not support deletion (e.g., immutable storage like Nostr relays). Default implementation throws UnsupportedOperationException.

      Warning: This operation is destructive and cannot be undone. Use with caution.

      Parameters:
      userPrivateKey - the user's private key (format depends on implementation)
      Throws:
      UnsupportedOperationException - if implementation doesn't support deletion
      IllegalArgumentException - if userPrivateKey is invalid
      RuntimeException - if deletion fails (network, storage, etc.)