diff --git a/lnbits/core/services/users.py b/lnbits/core/services/users.py index af45a432..6e651bb3 100644 --- a/lnbits/core/services/users.py +++ b/lnbits/core/services/users.py @@ -1,3 +1,5 @@ +import json +import time from pathlib import Path from uuid import uuid4 @@ -94,6 +96,14 @@ async def create_user_account_no_ckeck( except Exception as e: logger.error(f"Failed to create default pay link for user {account.username}: {e}") + # Publish Nostr kind 0 metadata event if user has username and Nostr keys + if account.username and account.pubkey and account.prvkey: + try: + await _publish_nostr_metadata_event(account) + logger.info(f"Published Nostr metadata event for user {account.username}") + except Exception as e: + logger.error(f"Failed to publish Nostr metadata for user {account.username}: {e}") + user = await get_user_from_account(account, conn=conn) if not user: raise ValueError("Cannot find user for account.") @@ -231,7 +241,6 @@ async def _create_default_pay_link(account: Account, wallet) -> None: create_pay_link = lnurlp_crud.create_pay_link CreatePayLinkData = lnurlp_models.CreatePayLinkData - pay_link_data = CreatePayLinkData( description="Bitcoinmat Receiving Address", wallet=wallet.id, @@ -251,3 +260,104 @@ async def _create_default_pay_link(account: Account, wallet) -> None: except Exception as e: logger.error(f"Failed to create default pay link: {e}") # Don't raise - we don't want user creation to fail if pay link creation fails + +async def _publish_nostr_metadata_event(account: Account) -> None: + """Publish a Nostr kind 0 metadata event for a new user""" + try: + import importlib + import sys + import secp256k1 + + # Note: We publish directly to nostrrelay database, no need to get relay URLs + + # Create Nostr kind 0 metadata event + metadata = { + "name": account.username, + "display_name": account.username, + "about": f"LNbits user: {account.username}" + } + + event = { + "kind": 0, + "created_at": int(time.time()), + "tags": [], + "content": json.dumps(metadata) + } + + # Sign the event using LNbits utilities + from lnbits.utils.nostr import sign_event + + # Convert hex private key to secp256k1 PrivateKey + private_key = secp256k1.PrivateKey(bytes.fromhex(account.prvkey)) + + # Sign the event + signed_event = sign_event(event, account.pubkey, private_key) + + # Publish directly to nostrrelay database (hacky but works around WebSocket issues) + await _insert_event_into_nostrrelay(signed_event, account.username) + + except Exception as e: + logger.error(f"Failed to publish Nostr metadata event: {e}") + # Don't raise - we don't want user creation to fail if Nostr publishing fails + + + + +async def _insert_event_into_nostrrelay(event: dict, username: str) -> None: + """Directly insert Nostr event into nostrrelay database (hacky workaround)""" + try: + import importlib + import sys + + # Try to import nostrrelay from various possible locations + nostrrelay_crud = None + NostrEvent = None + try: + nostrrelay_crud = importlib.import_module("lnbits.extensions.nostrrelay.crud") + NostrEvent = importlib.import_module("lnbits.extensions.nostrrelay.relay.event").NostrEvent + except ImportError: + try: + # Check if nostrrelay is in external extensions path + extensions_path = settings.lnbits_extensions_path or "/var/lib/lnbits/extensions" + if extensions_path not in sys.path: + sys.path.insert(0, extensions_path) + nostrrelay_crud = importlib.import_module("nostrrelay.crud") + NostrEvent = importlib.import_module("nostrrelay.relay.event").NostrEvent + except ImportError: + # Try from the lnbits-nostrmarket project path + nostrmarket_path = "/home/padreug/Projects/lnbits-nostrmarket" + if nostrmarket_path not in sys.path: + sys.path.insert(0, nostrmarket_path) + nostrrelay_crud = importlib.import_module("nostrrelay.crud") + NostrEvent = importlib.import_module("nostrrelay.relay.event").NostrEvent + + if not nostrrelay_crud or not NostrEvent: + logger.warning("Could not import nostrrelay - skipping direct database insert") + return + + # Use a default relay_id for the proof of concept + relay_id = "test1" + logger.debug(f"Using relay_id: {relay_id} for nostrrelay event") + + # Create NostrEvent object for nostrrelay + nostr_event = NostrEvent( + id=event["id"], + relay_id=relay_id, + publisher=event["pubkey"], + pubkey=event["pubkey"], + created_at=event["created_at"], + kind=event["kind"], + tags=event.get("tags", []), + content=event["content"], + sig=event["sig"] + ) + + # Insert directly into nostrrelay database + await nostrrelay_crud.create_event(nostr_event) + + logger.info(f"Successfully inserted Nostr metadata event for {username} into nostrrelay database") + + except Exception as e: + logger.error(f"Failed to insert event into nostrrelay database: {e}") + logger.debug(f"Exception details: {type(e).__name__}: {str(e)}") +