Replace NIP-04 messaging with NIP-17 (NIP-44 + NIP-59 gift wrapping)
Modernize the entire customer-merchant communication layer from deprecated NIP-04 (kind 4, AES-256-CBC) to NIP-17 private direct messages using NIP-44 v2 encryption (ChaCha20 + HMAC-SHA256) and NIP-59 gift wrapping (rumor/seal/gift-wrap protocol). No backwards compatibility retained. New modules: - nostr/nip44.py: NIP-44 v2 encryption verified against official spec vectors - nostr/nip59.py: NIP-59 gift wrap with wrap/unwrap convenience functions - tests/: 44 unit tests for NIP-44 and NIP-59 Key changes: - Subscription filters: kind 4 → kind 1059 gift wraps - Message handler: _handle_nip04_message → _handle_gift_wrap (unwrap + route) - send_dm/reply_to_structured_dm: NIP-59 gift wrap to recipient + self-archive - Merchant model: removed NIP-04 crypto methods (decrypt/encrypt/build_dm_event) - helpers.py: removed NIP-04 functions, kept Schnorr signing + key normalization - views_api.py: consolidated DM sending through send_dm() service function Reliability improvements: - Event deduplication via bounded LRU set in NostrClient - Subscription health monitor (resubscribes after 120s of silence) - Preserved 5-minute lenient time window from prior work Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
319d5eeb04
commit
725944ae9c
13 changed files with 869 additions and 165 deletions
29
models.py
29
models.py
|
|
@ -7,12 +7,7 @@ from typing import Any, List, Optional, Tuple
|
|||
from lnbits.utils.exchange_rates import btc_price, fiat_amount_as_satoshis
|
||||
from pydantic import BaseModel
|
||||
|
||||
from .helpers import (
|
||||
decrypt_message,
|
||||
encrypt_message,
|
||||
get_shared_secret,
|
||||
sign_message_hash,
|
||||
)
|
||||
from .helpers import sign_message_hash
|
||||
from .nostr.event import NostrEvent
|
||||
|
||||
######################################## NOSTR ########################################
|
||||
|
|
@ -67,28 +62,6 @@ class Merchant(PartialMerchant, Nostrable):
|
|||
def sign_hash(self, hash_: bytes) -> str:
|
||||
return sign_message_hash(self.private_key, hash_)
|
||||
|
||||
def decrypt_message(self, encrypted_message: str, public_key: str) -> str:
|
||||
encryption_key = get_shared_secret(self.private_key, public_key)
|
||||
return decrypt_message(encrypted_message, encryption_key)
|
||||
|
||||
def encrypt_message(self, clear_text_message: str, public_key: str) -> str:
|
||||
encryption_key = get_shared_secret(self.private_key, public_key)
|
||||
return encrypt_message(clear_text_message, encryption_key)
|
||||
|
||||
def build_dm_event(self, message: str, to_pubkey: str) -> NostrEvent:
|
||||
content = self.encrypt_message(message, to_pubkey)
|
||||
event = NostrEvent(
|
||||
pubkey=self.public_key,
|
||||
created_at=round(time.time()),
|
||||
kind=4,
|
||||
tags=[["p", to_pubkey]],
|
||||
content=content,
|
||||
)
|
||||
event.id = event.event_id
|
||||
event.sig = self.sign_hash(bytes.fromhex(event.id))
|
||||
|
||||
return event
|
||||
|
||||
@classmethod
|
||||
def from_row(cls, row: dict) -> "Merchant":
|
||||
merchant = cls(**row)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue