from nbdev.showdoc import *
notifyr
Making a decorator that can send messages
We are going to make a decorator that will store a private key in the keychain and send an encrypted message to itself. The private key will also be assigned to the decorated function as an attribute. The user can then log into any type of nostr client that can receive encrypted DMs to get notifications about python processing results or if the function errors out. Other projects like knockknock offer this sort of service, but take more leg work to get an account set up. Being able to randomly generate a Nostr private key makes this quick and painless.
Note: There is some concern about the safety of the current encrypted message implementation. Please do not use this module for any sort of secure communication. You can see a Github issue on the topic here
Another note about keyring: This project is tested and runs on MacOS - the majority of it seems to build on linux, but seems to have some issues running on Linux due to
keyring
dependencies. The keyring documenation may help if you attempt to debug. I believe installing kwallet might be the eventual solution.
First let’s make a helper function that will send the message
send_nostr_message
send_nostr_message (notifyr_client:nostrfastr.client.Client, message:str, recipient_pubkey_hex:str)
a simple function that takes a client and a message and sends the message to the client pubkey from the client pubkey
Type | Details | |
---|---|---|
notifyr_client | Client | A client class that will send an encrypted message for us |
message | str | A message that will be encrypted and sent |
recipient_pubkey_hex | str | |
Returns | None |
Next we are going to make helper functions to get and set credentials from keyring
set_password
set_password (service_name:str, username:str, password:str)
Set password for the user in the specified service.
delete_private_key
delete_private_key ()
delete the nostr hex private key from the computer key ring. This is not used in the decorator function, but may be used if need for testing
get_private_key
get_private_key ()
get the nostr hex private key from the computer key ring
set_private_key
set_private_key (notifyr_privkey_hex:str)
Set the private key in the computer keyring
Type | Details | |
---|---|---|
notifyr_privkey_hex | str | nostr hex private key |
Returns | None |
Let’s test setting and restoring the private key
Clear the private key from keychain
= get_private_key()
priv_key_hex if priv_key_hex is not None:
delete_private_key()assert get_private_key() is None
Try setting a new one
= PrivateKey().hex()
priv_key_hex = priv_key_hex)
set_private_key(notifyr_privkey_hex assert get_private_key() == priv_key_hex
Finally we write the decorator function complete with - nostr client handling - start message, success message, error message handling - and setting the private key to the decorator function for easy user access
convert_to_hex
convert_to_hex (pubkey:str)
make sure the pubkey is hex
Type | Details | |
---|---|---|
pubkey | str | hex or npub (bech32) pubkey |
Returns | str | hex pubkey |
get_notifyr_privkey
get_notifyr_privkey ()
returns a private key from keychain and sets a new one if one doesn’t exist
/Users/runner/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/fastcore/docscrape.py:225: UserWarning: Unknown section Raises
else: warn(msg)
notifyr
notifyr (func=None, recipient_pubkey:str=None, relay_urls:list[str]=None)
A decorator that will set a nostr private key to `func.notifyr_privkey_hex and use that key to send an encrypted message to it’s own public key on the start and termination of the decorated function. The output will send whether the function runs completely or ends in an error with an informative message.
Type | Default | Details | |
---|---|---|---|
func | NoneType | None | the function to be decorated |
recipient_pubkey | str | None | |
relay_urls | list | None | |
Returns | function | the decorated function |
notifyr
notifyr (func=None, recipient_pubkey:str=None, relay_urls:list[str]=None)
A decorator that will set a nostr private key to `func.notifyr_privkey_hex and use that key to send an encrypted message to it’s own public key on the start and termination of the decorated function. The output will send whether the function runs completely or ends in an error with an informative message.
Type | Default | Details | |
---|---|---|---|
func | NoneType | None | the function to be decorated |
recipient_pubkey | str | None | |
relay_urls | list | None | |
Returns | function | the decorated function |
Now we can decorate a couple functions!
= PrivateKey.from_hex(get_private_key()).public_key.bech32()
pubkey @notifyr(recipient_pubkey=pubkey, relay_urls=['ws://127.0.0.1:6969'])
def success():
return True
@notifyr
def another_success():
return True
@notifyr
def raise_error():
raise Exception('Oh no! Process failed!')
And test a successful function
success()
2023-01-08 13:43:02,123 - websocket - WARNING - websocket connected
/Users/ryanarmstrong/python/nostrfastr/nostrfastr/client.py:479: UserWarning: the current implementation of messages should be used with caution
see https://github.com/nostr-protocol/nips/issues/107
warnings.warn('''the current implementation of messages should be used with caution
2023-01-08 13:43:05,131 - websocket - WARNING - websocket connected
True
another_success()
2023-01-08 13:43:08,760 - websocket - WARNING - websocket connected
2023-01-08 13:43:09,101 - websocket - WARNING - websocket connected
2023-01-08 13:43:11,998 - websocket - WARNING - websocket connected
2023-01-08 13:43:12,181 - websocket - WARNING - websocket connected
True
another_success()
2023-01-08 13:43:15,242 - websocket - WARNING - websocket connected
2023-01-08 13:43:15,555 - websocket - WARNING - websocket connected
2023-01-08 13:43:18,802 - websocket - WARNING - websocket connected
2023-01-08 13:43:19,137 - websocket - WARNING - websocket connected
True
And test a failing function
from fastcore.test import test_fail
test_fail(raise_error)
2023-01-08 13:43:24,833 - websocket - WARNING - websocket connected
2023-01-08 13:43:25,179 - websocket - WARNING - websocket connected
2023-01-08 13:43:28,056 - websocket - WARNING - websocket connected
2023-01-08 13:43:28,361 - websocket - WARNING - websocket connected
Remember we can retrieve the private key to log into our messages from the keychain or from success.notifyr_privkey_hex
or raise_error.notifyr_privkey_hex
.
In this case you will either have to trust me that it works… or verify for yourself!