giftwrap for bot

This commit is contained in:
Believethehype
2024-04-15 17:31:51 +02:00
parent 6935284f79
commit e7d9c217f1
3 changed files with 185 additions and 142 deletions

View File

@@ -65,6 +65,7 @@ class Bot:
create_sql_table(self.dvm_config.DB) create_sql_table(self.dvm_config.DB)
admin_make_database_updates(adminconfig=self.admin_config, dvmconfig=self.dvm_config, client=self.client) admin_make_database_updates(adminconfig=self.admin_config, dvmconfig=self.dvm_config, client=self.client)
# add_sql_table_column(dvm_config.DB) # add_sql_table_column(dvm_config.DB)
class NotificationHandler(HandleNotification): class NotificationHandler(HandleNotification):
@@ -87,14 +88,12 @@ class Bot:
handle_dm(nostr_event, False) handle_dm(nostr_event, False)
except Exception as e: except Exception as e:
print(f"Error during content NIP04 decryption: {e}") print(f"Error during content NIP04 decryption: {e}")
elif nostr_event.kind() == KindEnum.GIFT_WRAP(): elif nostr_event.kind().match_enum(KindEnum.GIFT_WRAP()):
try: try:
handle_dm(nostr_event, True) handle_dm(nostr_event, True)
except Exception as e: except Exception as e:
print(f"Error during content NIP59 decryption: {e}") print(f"Error during content NIP59 decryption: {e}")
def handle_msg(self, relay_url, msg): def handle_msg(self, relay_url, msg):
return return
@@ -102,15 +101,14 @@ class Bot:
sender = nostr_event.author().to_hex() sender = nostr_event.author().to_hex()
if sender == self.keys.public_key().to_hex(): if sender == self.keys.public_key().to_hex():
return return
decrypted_text = ""
try: try:
sealed = " " sealed = " "
if giftwrap: if giftwrap:
print("Decrypting NIP59 event")
try: try:
# Extract rumor # Extract rumor
unwrapped_gift = UnwrappedGift.from_gift_wrap(self.keys, nostr_event) unwrapped_gift = UnwrappedGift.from_gift_wrap(self.keys, nostr_event)
sender = unwrapped_gift.sender() sender = unwrapped_gift.sender().to_hex()
rumor: UnsignedEvent = unwrapped_gift.rumor() rumor: UnsignedEvent = unwrapped_gift.rumor()
# Check timestamp of rumor # Check timestamp of rumor
@@ -126,15 +124,21 @@ class Bot:
print(f"Error during content NIP59 decryption: {e}") print(f"Error during content NIP59 decryption: {e}")
else: else:
decrypted_text = nip04_decrypt(self.keys.secret_key(), nostr_event.author(), nostr_event.content()) try:
decrypted_text = nip04_decrypt(self.keys.secret_key(), nostr_event.author(),
nostr_event.content())
except Exception as e:
print(f"Error during content NIP04 decryption: {e}")
if decrypted_text != "":
user = get_or_add_user(db=self.dvm_config.DB, npub=sender, client=self.client,
config=self.dvm_config)
user = get_or_add_user(db=self.dvm_config.DB, npub=sender, client=self.client, config=self.dvm_config)
print("[" + self.NAME + "]" + sealed + "Message from " + user.name + ": " + decrypted_text) print("[" + self.NAME + "]" + sealed + "Message from " + user.name + ": " + decrypted_text)
# if user selects an index from the overview list... # if user selects an index from the overview list...
if decrypted_text[0].isdigit(): if decrypted_text != "" and decrypted_text[0].isdigit():
split = decrypted_text.split(' ') split = decrypted_text.split(' ')
index = int(split[0]) - 1 index = int(split[0]) - 1
# if user sends index info, e.g. 1 info, we fetch the nip89 information and reply with it. # if user sends index info, e.g. 1 info, we fetch the nip89 information and reply with it.
@@ -148,7 +152,7 @@ class Bot:
if user.isblacklisted: if user.isblacklisted:
# If users are blacklisted for some reason, tell them. # If users are blacklisted for some reason, tell them.
answer_blacklisted(nostr_event) answer_blacklisted(nostr_event, giftwrap, sender)
else: else:
# Parse inputs to params # Parse inputs to params
@@ -164,7 +168,8 @@ class Bot:
# and encrypt them # and encrypt them
encrypted_params = nip04_encrypt(self.keys.secret_key(), encrypted_params = nip04_encrypt(self.keys.secret_key(),
PublicKey.from_hex( PublicKey.from_hex(
self.dvm_config.SUPPORTED_DVMS[index].PUBLIC_KEY), self.dvm_config.SUPPORTED_DVMS[
index].PUBLIC_KEY),
params_as_str) params_as_str)
# add encrypted and p tag on the outside # add encrypted and p tag on the outside
encrypted_tag = Tag.parse(['encrypted']) encrypted_tag = Tag.parse(['encrypted'])
@@ -182,7 +187,7 @@ class Bot:
# remember in the job_list that we have made an event, if anybody asks for payment, # remember in the job_list that we have made an event, if anybody asks for payment,
# we know we actually sent the request # we know we actually sent the request
entry = {"npub": user.npub, "event_id": nip90request.id().to_hex(), entry = {"npub": user.npub, "event_id": nip90request.id().to_hex(),
"dvm_key": self.dvm_config.SUPPORTED_DVMS[index].PUBLIC_KEY, "is_paid": False} "dvm_key": self.dvm_config.SUPPORTED_DVMS[index].PUBLIC_KEY, "is_paid": False, "giftwrap": giftwrap}
self.job_list.append(entry) self.job_list.append(entry)
# send the event to the DVM # send the event to the DVM
@@ -193,18 +198,30 @@ class Bot:
elif decrypted_text.lower().startswith("balance"): elif decrypted_text.lower().startswith("balance"):
time.sleep(3.0) time.sleep(3.0)
evt = EventBuilder.encrypted_direct_msg(self.keys, nostr_event.author(), message = "Your current balance is " + str(user.balance) + ("Sats. Zap me to add to your "
"Your current balance is " + str( "balance. I will use your "
user.balance) + " Sats. Zap me to add to your balance. I will use your balance interact with the DVMs for you.\n" "balance interact with the DVMs "
"I support both public and private Zaps, as well as Zapplepay.\n" "for you.\n I support both "
"Alternativly you can add a #cashu token with \"-cashu cashuASomeToken\" to your command.\n Make sure the token is worth the requested amount + " "public and private Zaps, "
"mint fees (at least 3 sat).\n Not all DVMs might accept Cashu tokens." "as well as "
, None).to_event(self.keys) "Zapplepay.\nAlternativly you "
"can add a #cashu token with "
"\"-cashu cashuASomeToken\" to "
"your command.\n Make sure the "
"token is worth the requested "
"amount mint fees (at least 3 "
"sat).\n Not all DVMs might "
"accept Cashu tokens.")
if giftwrap:
self.client.send_sealed_msg(PublicKey.parse(sender), message, None)
else:
evt = EventBuilder.encrypted_direct_msg(self.keys, PublicKey.parse(sender),
message,None).to_event(self.keys)
send_event(evt, client=self.client, dvm_config=dvm_config) send_event(evt, client=self.client, dvm_config=dvm_config)
elif decrypted_text.startswith("cashuA"): elif decrypted_text.startswith("cashuA"):
print("Received Cashu token:" + decrypted_text) print("Received Cashu token:" + decrypted_text)
cashu_redeemed, cashu_message, total_amount, fees = redeem_cashu(decrypted_text, self.dvm_config, cashu_redeemed, cashu_message, total_amount, fees = redeem_cashu(decrypted_text,
self.dvm_config,
self.client) self.client)
print(cashu_message) print(cashu_message)
if cashu_message == "success": if cashu_message == "success":
@@ -213,25 +230,33 @@ class Bot:
else: else:
time.sleep(2.0) time.sleep(2.0)
message = "Error: " + cashu_message + ". Token has not been redeemed." message = "Error: " + cashu_message + ". Token has not been redeemed."
if giftwrap:
self.client.send_sealed_msg(PublicKey.parse(sender), message, None)
else:
evt = EventBuilder.encrypted_direct_msg(self.keys, PublicKey.from_hex(sender), message, evt = EventBuilder.encrypted_direct_msg(self.keys, PublicKey.from_hex(sender), message,
None).to_event(self.keys) None).to_event(self.keys)
send_event(evt, client=self.client, dvm_config=self.dvm_config) send_event(evt, client=self.client, dvm_config=self.dvm_config)
elif decrypted_text.lower().startswith("what's the second best"): elif decrypted_text.lower().startswith("what's the second best"):
time.sleep(3.0) time.sleep(3.0)
evt = EventBuilder.encrypted_direct_msg(self.keys, nostr_event.author(), message = "No, there is no second best.\n\nhttps://cdn.nostr.build/p/mYLv.mp4"
"No, there is no second best.\n\nhttps://cdn.nostr.build/p/mYLv.mp4", if giftwrap:
self.client.send_sealed_msg(PublicKey.parse(sender), message, None)
else:
evt = EventBuilder.encrypted_direct_msg(self.keys, PublicKey.parse(sender),
message,
nostr_event.id()).to_event(self.keys) nostr_event.id()).to_event(self.keys)
send_event(evt, client=self.client, dvm_config=self.dvm_config) send_event(evt, client=self.client, dvm_config=self.dvm_config)
else: else:
# Build an overview of known DVMs and send it to the user # Build an overview of known DVMs and send it to the user
answer_overview(nostr_event) answer_overview(nostr_event, giftwrap, sender)
except Exception as e: except Exception as e:
print("Error in bot " + str(e)) print("Error in bot " + str(e))
def handle_nip90_feedback(nostr_event): def handle_nip90_feedback(nostr_event):
#print(nostr_event.as_json()) # print(nostr_event.as_json())
try: try:
is_encrypted = False is_encrypted = False
status = "" status = ""
@@ -281,14 +306,18 @@ class Bot:
user = get_or_add_user(db=self.dvm_config.DB, npub=entry['npub'], user = get_or_add_user(db=self.dvm_config.DB, npub=entry['npub'],
client=self.client, config=self.dvm_config) client=self.client, config=self.dvm_config)
time.sleep(2.0) time.sleep(2.0)
if entry["giftwrap"]:
self.client.send_sealed_msg(PublicKey.parse(entry["npub"]), content, None)
else:
reply_event = EventBuilder.encrypted_direct_msg(self.keys, reply_event = EventBuilder.encrypted_direct_msg(self.keys,
PublicKey.from_hex(entry['npub']), PublicKey.from_hex(entry['npub']),
content, content,
None).to_event(self.keys) None).to_event(self.keys)
send_event(reply_event, client=self.client, dvm_config=dvm_config)
print(status + ": " + content) print(status + ": " + content)
print( print(
"[" + self.NAME + "] Received reaction from " + nostr_event.author().to_hex() + " message to orignal sender " + user.name) "[" + self.NAME + "] Received reaction from " + nostr_event.author().to_hex() + " message to orignal sender " + user.name)
send_event(reply_event, client=self.client, dvm_config=dvm_config)
elif status == "payment-required" or status == "partial": elif status == "payment-required" or status == "partial":
for tag in nostr_event.tags(): for tag in nostr_event.tags():
@@ -307,22 +336,24 @@ class Bot:
iswhitelisted=user.iswhitelisted, isblacklisted=user.isblacklisted, iswhitelisted=user.iswhitelisted, isblacklisted=user.isblacklisted,
nip05=user.nip05, lud16=user.lud16, name=user.name, nip05=user.nip05, lud16=user.lud16, name=user.name,
lastactive=Timestamp.now().as_secs(), subscribed=user.subscribed) lastactive=Timestamp.now().as_secs(), subscribed=user.subscribed)
evt = EventBuilder.encrypted_direct_msg(self.keys,
PublicKey.from_hex(entry["npub"]),
"Paid " + str(
amount) + " Sats from balance to DVM. New balance is " +
str(balance)
+ " Sats.\n",
None).to_event(self.keys)
message = "Paid " + str(amount) + " Sats from balance to DVM. New balance is " + str(balance) + " Sats.\n"
if entry["giftwrap"]:
self.client.send_sealed_msg(PublicKey.parse(entry["npub"]), message, None)
else:
evt = EventBuilder.encrypted_direct_msg(self.keys,
PublicKey.parse(entry["npub"]),
message,
None).to_event(self.keys)
send_event(evt, client=self.client, dvm_config=dvm_config)
print( print(
"[" + self.NAME + "] Replying " + user.name + " with \"scheduled\" confirmation") "[" + self.NAME + "] Replying " + user.name + " with \"scheduled\" confirmation")
send_event(evt, client=self.client, dvm_config=dvm_config)
else: else:
print("Bot payment-required") print("Bot payment-required")
time.sleep(2.0) time.sleep(2.0)
evt = EventBuilder.encrypted_direct_msg(self.keys, evt = EventBuilder.encrypted_direct_msg(self.keys,
PublicKey.from_hex(entry["npub"]), PublicKey.parse(entry["npub"]),
"Current balance: " + str( "Current balance: " + str(
user.balance) + " Sats. Balance of " + str( user.balance) + " Sats. Balance of " + str(
amount) + " Sats required. Please zap me with at least " + amount) + " Sats required. Please zap me with at least " +
@@ -398,8 +429,11 @@ class Bot:
print("[" + self.NAME + "] Received results, message to orignal sender " + user.name) print("[" + self.NAME + "] Received results, message to orignal sender " + user.name)
time.sleep(1.0) time.sleep(1.0)
if entry["giftwrap"]:
self.client.send_sealed_msg(PublicKey.parse(user.npub), content, None)
else:
reply_event = EventBuilder.encrypted_direct_msg(self.keys, reply_event = EventBuilder.encrypted_direct_msg(self.keys,
PublicKey.from_hex(user.npub), PublicKey.parse(user.npub),
content, content,
None).to_event(self.keys) None).to_event(self.keys)
send_event(reply_event, client=self.client, dvm_config=dvm_config) send_event(reply_event, client=self.client, dvm_config=dvm_config)
@@ -453,7 +487,7 @@ class Bot:
except Exception as e: except Exception as e:
print("[" + self.NAME + "] Error during content decryption:" + str(e)) print("[" + self.NAME + "] Error during content decryption:" + str(e))
def answer_overview(nostr_event): def answer_overview(nostr_event, giftwrap, sender):
message = "DVMs that I support:\n\n" message = "DVMs that I support:\n\n"
index = 1 index = 1
for p in self.dvm_config.SUPPORTED_DVMS: for p in self.dvm_config.SUPPORTED_DVMS:
@@ -466,34 +500,38 @@ class Bot:
index += 1 index += 1
time.sleep(3.0) time.sleep(3.0)
evt = EventBuilder.encrypted_direct_msg(self.keys, nostr_event.author(),
message + "\nSelect an Index and provide an input (" text = message + "\nSelect an Index and provide an input (e.g. \"2 A purple ostrich\")\nType \"index info\" to learn more about each DVM. (e.g. \"2 info\")\n\n Type \"balance\" to see your current balance"
"e.g. \"2 A purple ostrich\")\nType \"index info\" to learn " if giftwrap:
"more about each DVM. (e.g. \"2 info\")\n\n" self.client.send_sealed_msg(PublicKey.parse(sender), text, None)
"Type \"balance\" to see your current balance", else:
evt = EventBuilder.encrypted_direct_msg(self.keys, PublicKey.parse(sender),
text,
nostr_event.id()).to_event(self.keys) nostr_event.id()).to_event(self.keys)
send_event(evt, client=self.client, dvm_config=dvm_config) send_event(evt, client=self.client, dvm_config=dvm_config)
def answer_blacklisted(nostr_event): def answer_blacklisted(nostr_event, giftwrap, sender):
message = "Your are currently blocked from this service."
if giftwrap:
self.client.send_sealed_msg(PublicKey.parse(sender), message, None)
else:
# For some reason an admin might blacklist npubs, e.g. for abusing the service # For some reason an admin might blacklist npubs, e.g. for abusing the service
evt = EventBuilder.encrypted_direct_msg(self.keys, nostr_event.author(), evt = EventBuilder.encrypted_direct_msg(self.keys, nostr_event.author(),
"Your are currently blocked from all " message, None).to_event(self.keys)
"services.", None).to_event(self.keys)
send_event(evt, client=self.client, dvm_config=dvm_config) send_event(evt, client=self.client, dvm_config=dvm_config)
def answer_nip89(nostr_event, index): def answer_nip89(nostr_event, index, giftwrap, sender):
info = print_dvm_info(self.client, index) info = print_dvm_info(self.client, index)
if info is None:
info = "No NIP89 Info found for " + self.dvm_config.SUPPORTED_DVMS[index].NAME
time.sleep(2.0) time.sleep(2.0)
if info is not None:
evt = EventBuilder.encrypted_direct_msg(self.keys, nostr_event.author(), if giftwrap:
info, None).to_event(self.keys) self.client.send_sealed_msg(PublicKey.parse(sender), info, None)
else: else:
evt = EventBuilder.encrypted_direct_msg(self.keys, nostr_event.author(), evt = EventBuilder.encrypted_direct_msg(self.keys, nostr_event.author(),
"No NIP89 Info found for " + info, None).to_event(self.keys)
self.dvm_config.SUPPORTED_DVMS[index].NAME,
None).to_event(self.keys)
send_event(evt, client=self.client, dvm_config=dvm_config) send_event(evt, client=self.client, dvm_config=dvm_config)
def build_params(decrypted_text, nostr_event, index): def build_params(decrypted_text, nostr_event, index):

View File

@@ -5,7 +5,7 @@ from datetime import timedelta
from sys import platform from sys import platform
from nostr_sdk import PublicKey, Keys, Client, Tag, Event, EventBuilder, Filter, HandleNotification, Timestamp, \ from nostr_sdk import PublicKey, Keys, Client, Tag, Event, EventBuilder, Filter, HandleNotification, Timestamp, \
init_logger, LogLevel, Options, nip04_encrypt, NostrSigner, Kind, SubscribeAutoCloseOptions init_logger, LogLevel, Options, nip04_encrypt, NostrSigner, Kind
import time import time

View File

@@ -169,7 +169,7 @@ def list_db(db):
print(e) print(e)
def update_user_balance(db, npub, additional_sats, client, config): def update_user_balance(db, npub, additional_sats, client, config, giftwrap=False):
user = get_from_sql_table(db, npub) user = get_from_sql_table(db, npub)
if user is None: if user is None:
name, nip05, lud16 = fetch_user_metadata(npub, client) name, nip05, lud16 = fetch_user_metadata(npub, client)
@@ -192,7 +192,12 @@ def update_user_balance(db, npub, additional_sats, client, config):
message = ("Added " + str(additional_sats) + " Sats to balance. New balance is " + str( message = ("Added " + str(additional_sats) + " Sats to balance. New balance is " + str(
new_balance) + " Sats.") new_balance) + " Sats.")
evt = EventBuilder.encrypted_direct_msg(keys, PublicKey.from_hex(npub), message, if giftwrap:
client.send_sealed_msg(PublicKey.parse(npub), message, None)
else:
evt = EventBuilder.encrypted_direct_msg(keys, PublicKey.parse(npub), message,
None).to_event(keys) None).to_event(keys)
send_event(evt, client=client, dvm_config=config) send_event(evt, client=client, dvm_config=config)