jeffthibault / python-nostr Goto Github PK
View Code? Open in Web Editor NEWA Python library for Nostr
License: MIT License
A Python library for Nostr
License: MIT License
Was really glad to see that support for PrivateKey.from_nsec()
. It would also be helpful to have a PublicKey.from_npub()
and possibly a .from_hex()
method for each since, for example, clients need to decode public keys in text to create tags.
I’ve experimented a bit with having a base Key
class that carries some of these generic methods. It works quite well, but does require renaming PrivateKey.raw_secret
to PrivateKey.raw_bytes
and I’m not sure if that would be acceptable from a design standpoint.
How do I use this encryption algorithm used in Nostr_DMs (kind-4) in python? I'm thinking of making a P2P application with this encryption algorithm where Nostr keys could be used but I couldn't use this algorithm, PS: I'm still a beginner in programming.
Let's say I have an event id, How can I find all the replies for that post
>>> import json
>>> import ssl
>>> import time
>>> from nostr.relay_manager import RelayManager
>>>
>>> relay_manager = RelayManager()
>>> relay_manager.add_relay("wss://nostr-pub.wellorder.net")
Exception in thread wss://nostr-pub.wellorder.net-thread:
Traceback (most recent call last):
File "/usr/lib/python3.10/threading.py", line 1016, in _bootstrap_inner
self.run()
File "/usr/lib/python3.10/threading.py", line 953, in run
self._target(*self._args, **self._kwargs)
File "/root/python-nostr/nostr/relay.py", line 55, in connect
http_proxy_host=self.proxy_config.host,
AttributeError: 'NoneType' object has no attribute 'host'
>>> relay_manager.add_relay("wss://relay.damus.io")
Exception in thread wss://relay.damus.io-thread:
Traceback (most recent call last):
File "/usr/lib/python3.10/threading.py", line 1016, in _bootstrap_inner
self.run()
File "/usr/lib/python3.10/threading.py", line 953, in run
self._target(*self._args, **self._kwargs)
File "/root/python-nostr/nostr/relay.py", line 55, in connect
http_proxy_host=self.proxy_config.host,
AttributeError: 'NoneType' object has no attribute 'host'
>>> relay_manager.open_connections({"cert_reqs": ssl.CERT_NONE}) # NOTE: This disables ssl certificate verification
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'RelayManager' object has no attribute 'open_connections'
Trying the current "Publish to relays" example I get
event = Event("Hello Nostr")
^^^^^^^^^^^^^^^^^^^^
TypeError: Event.__init__() missing 1 required positional argument: 'content'
Not sure what's missing.
Using
0.0.2
The old example with version 0.0.1
and Pyhton 3.10.9
still works. Rolling back for now.
Would it be possible to support key derivation from a seed phrase? Then from that support HD key derivation?
https://github.com/nostr-protocol/nips/blob/master/06.md
I realize this could potentially help spammers go nuts. The scenario I'm trying to accommodate though is seed and key management for things like truck fleets, sensors, and physical locations. One seed for many keys is the logical approach for that.
Error output as follows:
C:\WINDOWS\system32>pip install nostr
Collecting nostr
Using cached nostr-0.0.2-py3-none-any.whl (15 kB)
Collecting cffi>=1.15.0
Using cached cffi-1.15.1.tar.gz (508 kB)
Preparing metadata (setup.py) ... error
error: subprocess-exited-with-error
× python setup.py egg_info did not run successfully.
│ exit code: 1
╰─> [24 lines of output]
Traceback (most recent call last):
File "<string>", line 2, in <module>
File "<pip-setuptools-caller>", line 34, in <module>
File "C:\Users\Human\AppData\Local\Temp\pip-install-6ix_c9ru\cffi_4296967108f5410cb42a1e996713bfb2\setup.py", line 126, in <module>
if sys.platform == "win32" and uses_msvc():
^^^^^^^^^^^
File "C:\Users\Human\AppData\Local\Temp\pip-install-6ix_c9ru\cffi_4296967108f5410cb42a1e996713bfb2\setup.py", line 105, in uses_msvc
return config.try_compile('#ifndef _MSC_VER\n#error "not MSVC"\n#endif')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Python312\Lib\site-packages\setuptools\_distutils\command\config.py", line 224, in try_compile
self._compile(body, headers, include_dirs, lang)
File "C:\Python312\Lib\site-packages\setuptools\_distutils\command\config.py", line 129, in _compile
self.compiler.compile([src], include_dirs=include_dirs)
File "C:\Python312\Lib\site-packages\setuptools\_distutils\_msvccompiler.py", line 344, in compile
self.initialize()
File "C:\Python312\Lib\site-packages\setuptools\_distutils\_msvccompiler.py", line 253, in initialize
vc_env = _get_vc_env(plat_spec)
^^^^^^^^^^^^^^^^^^^^^^
File "C:\Python312\Lib\site-packages\setuptools\msvc.py", line 214, in msvc14_get_vc_env
return _msvc14_get_vc_env(plat_spec)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Python312\Lib\site-packages\setuptools\msvc.py", line 168, in _msvc14_get_vc_env
raise distutils.errors.DistutilsPlatformError(
distutils.errors.DistutilsPlatformError: Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/
[end of output]
note: This error originates from a subprocess, and is likely not a problem with pip.
error: metadata-generation-failed
× Encountered error while generating package metadata.
╰─> See above for output.
note: This is an issue with the package mentioned above, not pip.
hint: See above for details.
C:\WINDOWS\system32>
Thanks for any assistance!
When posting to multiple relays, sometimes there are failures like the below:
2023-02-09 11:09:12 Start posting to 16 relays
2023-02-09 11:09:12 Websocket connected
2023-02-09 11:09:12 Websocket connected
2023-02-09 11:09:12 Websocket connected
2023-02-09 11:09:12 Websocket connected
2023-02-09 11:09:12 Websocket connected
2023-02-09 11:09:12 Websocket connected
2023-02-09 11:09:12 Websocket connected
2023-02-09 11:09:12 Websocket connected
2023-02-09 11:09:12 Websocket connected
2023-02-09 11:09:12 Handshake status 500 Internal Server Error - goodbye
2023-02-09 11:09:12 Websocket connected
2023-02-09 11:09:12 Websocket connected
2023-02-09 11:09:12 Websocket connected
2023-02-09 11:09:12 Websocket connected
2023-02-09 11:09:12 Websocket connected
2023-02-09 11:09:13 Websocket connected
2023-02-09 11:09:17 Error posting to nostr
Traceback (most recent call last):
File "/home/zz/ooo/util_nostr.py", line 71, in _post
relay_manager.publish_event(event)
File "/home/zz/.local/share/virtualenvs/ooo-gj3JA2ic/lib/python3.10/site-packages/nostr/relay_manager.py", line 63, in publish_event
self.publish_message(event.to_message())
File "/home/zz/.local/share/virtualenvs/ooo-gj3JA2ic/lib/python3.10/site-packages/nostr/relay_manager.py", line 53, in publish_message
relay.publish(message)
File "/home/zz/.local/share/virtualenvs/ooo-gj3JA2ic/lib/python3.10/site-packages/nostr/relay.py", line 47, in publish
self.ws.send(message)
File "/home/zz/.local/share/virtualenvs/ooo-gj3JA2ic/lib/python3.10/site-packages/websocket/_app.py", line 240, in send
raise WebSocketConnectionClosedException(
websocket._exceptions.WebSocketConnectionClosedException: Connection is already closed.
Thanks
Hi,
I've been observing this repo for a while.. how do i, for example, get a post from a set of relays?
Thanks.
Orb
Publishing content as dictionary instead of string returns event id but no event is found when checking relay events.
Use wss://relay.nostr.info
relay with this snippet to publish this json in the README example to reproduce:
data = {}
data['txid'] = "2cd2821390126c5407f29be8669c612a4092d0bc11224811a0752ff7fa31d43a"
data['vout'] = '1'
data['descriptor'] = "wpkh([ed9062ee/84'/1'/0'/0/0]0261dffbc33896fa21168d72fb74c80ca6af133c638b86e5e8a08645dbd752dca4)#gqkw68za"
data['type'] = 'input'
event = Event(public_key, data, kind=90)
It will return an event id but there would be no event with kind=90 for that relay.
Sending string instead of dict would fix this:
-event = Event(public_key, data, kind=90)
+event = Event(public_key, str(data), kind=90)
I understand content is str
in Event class however sending other type should have either resulted in an error or converted to string or at least does not return event id.
the relay manager doesn't let you reconnect to relays when the socket gets closed. It means everything stops working after a little while.
I try to use python-nostr to send a direct message to my Damus account and it works well. I am wondering how we can receive DMs using this tool?
I am having a hard time figuring out how the examples work, since i can't get any output. Thi is what i am working with:
import json
import ssl
import time
from nostr.relay_manager import RelayManager
from nostr.filter import Filter, Filters
from nostr.key import PrivateKey
from nostr.event import Event, EventKind
from nostr.message_type import ClientMessageType
private_key = PrivateKey()
public_key = private_key.public_key
print(f"Private key: {private_key.bech32()}")
print(f"Public key: {public_key.bech32()}")
relay_manager = RelayManager()
relay_manager.add_relay("wss://nostr-pub.wellorder.net")
relay_manager.add_relay("wss://relay.damus.io")
relay_manager.open_connections({"cert_reqs": ssl.CERT_NONE}) # NOTE: This disables ssl certificate verification
time.sleep(1.25) # allow the connections to open
while relay_manager.message_pool.has_notices():
notice_msg = relay_manager.message_pool.get_notice()
print(notice_msg.content)
# publish message
event = Event(public_key.hex(), "Hello Nostr")
private_key.sign_event(event)
relay_manager.publish_event(event)
time.sleep(1) # allow the messages to send
# read message
filters = Filters([Filter(authors=public_key.hex(), kinds=[EventKind.TEXT_NOTE])])
subscription_id = "test"
request = [ClientMessageType.REQUEST, subscription_id]
request.extend(filters.to_json_array())
message = json.dumps(request)
relay_manager.publish_message(message)
time.sleep(1)
while relay_manager.message_pool.has_events():
event_msg = relay_manager.message_pool.get_event()
print(event_msg.event.content)
relay_manager.close_connections()
It doesn't want to return the published message, and i can't figure out why
The pip install, nostr, worked well on my Linux system but halted on my Windows machine. For more info on that, see; https://gist.github.com/VictorieeMan/cc73f3d62e07927ac15afd3331fb08e4
My solution was to redo the bindings in this repo to call the "secp256k1" bindings in
pip install coincurve
instead. The coincurve repo is maintained to support cross-platform compatibility, see their website for reference: https://ofek.dev/coincurve/
I have a pub key generated with sk.public_key, I'm trying to use PrivateKey.encrypt_message but when I run it, I'm getting: ValueError: non-hexadecimal number found in fromhex() arg at position 2
message = PrivateKey.encrypt_message(sharedSecretPrivate, "Secret message!", sharedSecretPublic)
`import json
import ssl
import time
from nostr.key import PrivateKey
from nostr.filter import Filter, Filters
from nostr.event import Event, EventKind, EncryptedDirectMessage
from nostr.relay_manager import RelayManager
from nostr.message_type import ClientMessageType
sharedSecretPrivate = PrivateKey()
sharedSecretPublic = sharedSecretPrivate.public_key
print(f"Private key: {sharedSecretPrivate.bech32()}")
print(f"Public key: {sharedSecretPublic.bech32()}")
relay_manager = RelayManager()
relay_manager.add_relay("wss://nostr-pub.wellorder.net")
relay_manager.add_relay("wss://relay.damus.io")
relay_manager.open_connections({"cert_reqs": ssl.CERT_NONE}) # NOTE: This disables ssl certificate verification
time.sleep(1.25) # allow the connections to open
private_key = PrivateKey()
dm = EncryptedDirectMessage(
recipient_pubkey=sharedSecretPublic,
cleartext_content="Secret message!"
)
private_key.sign_event(dm)
relay_manager.publish_event(dm)
time.sleep(1) # allow the messages to send
relay_manager.close_connections()`
When running the above python script, I'm getting this error:
"Traceback (most recent call last):
File "/Users/august/Documents/Nostr/nostrtest.py", line 6, in
from nostr.event import Event, EventKind, EncryptedDirectMessage
ImportError: cannot import name 'EncryptedDirectMessage' from 'nostr.event' (/Users/august/Documents/Nostr/nostrVenv/lib/python3.11/site-packages/nostr/event.py)"
Any ideas?
If I have an event id, and I want to get the entire event data, how can I query the relays to get it?
Hi, is there any way to retrieve every public key of users that a specific public key is following with python-nostr ?
When running the bot I wrote with python-nostr it always crashes with some kind of threading error after around 5h. I use python 3.9.5 with the correct dependencie versions. Connecting to around 5 reliable relais (also tried less).
Crash log:
424 in _callback
File "/home/satdress/.local/lib/python3.9/site-packages/websocket/_app.py", line 386 in run_forever ...
Thread 0x00007f9522112700 (most recent call first): File "/usr/local/lib/python3.9/threading.py", line 312 in wait
File "/usr/local/lib/python3.9/queue.py", line 171 in get File "/home/satdress/lightningpicturebot/nostr/relay.py", line 88 in queue_worker File "/usr/local/lib/python3.9/threading.py", line 892 in run
File "/usr/local/lib/python3.9/threading.py", line 954 in _bootstrap_inner
File "/usr/local/lib/python3.9/threading.py", line 912 in _bootstrap
Thread 0x00007f9522913700 (most recent call first):
File "/usr/local/lib/python3.9/selectors.py", line 469 in select
File "/home/satdress/.local/lib/python3.9/site-packages/websocket/_app.py", line 78 in select
File "/home/satdress/.local/lib/python3.9/site-packages/websocket/_app.py", line 64 in read
File "/home/satdress/.local/lib/python3.9/site-packages/websocket/_app.py", line 383 in run_forever
File "/home/satdress/lightningpicturebot/nostr/relay.py", line 60 in connect
File "/home/satdress/lightningpicturebot/nostr/relay.py", line 80 in check_reconnect
File "/home/satdress/lightningpicturebot/nostr/relay.py", line 135 in _on_error File "/home/satdress/.local/lib/python3.9/site-packages/websocket/_app.py", line 424 in _callback File "/home/satdress/.local/lib/python3.9/site-packages/websocket/_app.py", line 386 in run_forever File "/home/satdress/lightningpicturebot/nostr/relay.py", line 60 in connect
File "/home/satdress/lightningpicturebot/nostr/relay.py", line 80 in check_reconnect
File "/home/satdress/lightningpicturebot/nostr/relay.py", line 135 in _on_error
File "/home/satdress/.local/lib/python3.9/site-packages/websocket/_app.py", line 424 in _callback
File "/home/satdress/.local/lib/python3.9/site-packages/websocket/_app.py", line 386 in run_forever
File "/home/satdress/lightningpicturebot/nostr/relay.py", line 60 in connect
File "/usr/local/lib/python3.9/threading.py", line 892 in run File "/usr/local/lib/python3.9/threading.py", line 954 in _bootstrap_inner
File "/usr/local/lib/python3.9/threading.py", line 912 in _bootstrap
Thread 0x00007f9523114700 (most recent call first):
File "/usr/local/lib/python3.9/threading.py", line 312 in wait
File "/usr/local/lib/python3.9/queue.py", line 171 in get
File "/home/satdress/lightningpicturebot/nostr/relay.py", line 88 in queue_worker File "/usr/local/lib/python3.9/threading.py", line 892 in run
File "/usr/local/lib/python3.9/threading.py", line 954 in _bootstrap_inner
File "/usr/local/lib/python3.9/threading.py", line 912 in _bootstrap
Thread 0x00007f9523955700 (most recent call first):
File "/usr/local/lib/python3.9/selectors.py", line 469 in select
File "/home/satdress/.local/lib/python3.9/site-packages/websocket/_app.py", line 78 in select
File "/home/satdress/.local/lib/python3.9/site-packages/websocket/_app.py", line 64 in read
File "/home/satdress/.local/lib/python3.9/site-packages/websocket/_app.py", line 383 in run_forever
File "/home/satdress/lightningpicturebot/nostr/relay.py", line 60 in connect
File "/usr/local/lib/python3.9/threading.py", line 892 in run
File "/usr/local/lib/python3.9/threading.py", line 954 in _bootstrap_inner
File "/usr/local/lib/python3.9/threading.py", line 912 in _bootstrap
Thread 0x00007f95267a8280 (most recent call first):
File "/usr/local/lib/python3.9/threading.py", line 312 in wait
File "/usr/local/lib/python3.9/queue.py", line 171 in get
File "/home/satdress/lightningpicturebot/nostr/message_pool.py", line 35 in get_event
File "/home/satdress/lightningpicturebot/nostr1.py", line 102 in nostr_bot
File "/home/satdress/lightningpicturebot/nostr1.py", line 551 in run
File "/home/satdress/lightningpicturebot/nostr1.py", line 559 in
Abgebrochen
Is this a bug in python-nostr or more likely related to my code?
In class Relay init:
class Relay:
def __init__(
self,
url: str,
policy: RelayPolicy,
message_pool: MessagePool,
subscriptions: dict[str, Subscription]={}) -> None:
You are initializing subscriptions to a dict '{}' is this correct?
"the default value for a function argument is only evaluated once, at the time that the function is defined. "
All self.subscriptions
will "share" a common dictionary right?
Since there seems to be no convention yet on how to format the code, I would suggest using black
(see here).
I wanted to make a PR with that but I don't know how to deal with the pyproject.toml
file in this repo. This is the error I get:
$ poetry add black --dev
[tool.poetry] section not found in /Users/cc/git/python-nostr/pyproject.toml
What should I do?
When posting messages quickly one after another the order gets wrong and messages appear earlier than others even though they got sent later
In the screenshot you can see type 4 messages i sent with the module displayed in anigma.io, the 2nd message is actually the newest one but somehow the time is wrong
Hi,
Would it be possible to add support for Nostr Zaps? Seems very useful.
When trying to decode a received Type 4 DM from Amethyst or Astral i get a Value Error "Invalid padding bytes."
(using Nostr 0.0.2 from pip)
Code i used:
if event_msg.event.kind == 4:
user_pk = event_msg.event.public_key
content = PrivateKey().decrypt_message(event_msg.event.content, user_pk)
print(content)
after receiving a type 4 dm it returns the following error:
Traceback (most recent call last):
File "/home/benutzer/PycharmProjects/X/testing.py", line 66, in
nostr_dalle()
File "/home/benutzer/PycharmProjects/X/testing.py", line 58, in nostr_dalle
content = PrivateKey().decrypt_message(event_msg.event.content, user_pk)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/benutzer/PycharmProjects/X/venv/lib/python3.11/site-packages/nostr/key.py", line 93, in decrypt_message
unpadded_data = unpadder.update(decrypted_message) + unpadder.finalize()
^^^^^^^^^^^^^^^^^^^
File "/home/benutzer/PycharmProjects/X/venv/lib64/python3.11/site-packages/cryptography/hazmat/primitives/padding.py", line 159, in finalize
result = _byte_unpadding_check(
^^^^^^^^^^^^^^^^^^^^^^
File "/home/benutzer/PycharmProjects/X/venv/lib64/python3.11/site-packages/cryptography/hazmat/primitives/padding.py", line 101, in _byte_unpadding_check
raise ValueError("Invalid padding bytes.")
ValueError: Invalid padding bytes.
Am i doing this wrong or could this be a bug?
Hi, I was having a look at this repo and when I was testing the Private_Key Class I could not really understand why this class has the public key as parameter?
If I have an object that has a given private_key the only pub_key that would work for that function is private_key.public_key.hex() so I can't really understand why do we need to manually add the public key there? is there any other use case that I'm missing?
Thanks and congrats for this repo
If I have a pubkey, how can I query to find out about their profile information like bio and lightning address?
Thank you
When a relay sends an event that contains a tag that wasn't requested in the subscription it doesn't get added to the message pool as it fails validation. Some clients send custom tags, for example I had an issue receiving events containing a "client" tag that nostr_console was sending.
Thank you for the nostr python packages. I was able to quickly publish notes to my own nostr relay with your package.
Next steps is to pull notes from my relay. For this In would like to use your published code for receiving events. Here I didn't find any information in the web about the "subscription_id = ". What am I supposed to use as an subscription id, for example if I would like to pull the last 10 events from my relay?
Best regards
Hello,
by doing
python -m venv .venv
source .venv/bin/activate
echo nostr > requirements.txt
pip install -r requirements.txt
I have the following error :
Collecting secp256k1>=0.14.0
Using cached secp256k1-0.14.0.tar.gz (2.4 MB)
Preparing metadata (setup.py) ... error
error: subprocess-exited-with-error
× python setup.py egg_info did not run successfully.
│ exit code: 1
╰─> [61 lines of output]
0.29.2
/Users/xxx/.venv/lib/python3.11/site-packages/setuptools/installer.py:27: SetuptoolsDeprecationWarning: setuptools.installer is deprecated. Requirements should be satisfied by a PEP 517 installer.
warnings.warn(
WARNING: The wheel package is not available.
error: subprocess-exited-with-error
× python setup.py bdist_wheel did not run successfully.
│ exit code: 1
╰─> [11 lines of output]
/Users/xxx/.venv/lib/python3.11/site-packages/setuptools/installer.py:27: SetuptoolsDeprecationWarning: setuptools.installer is deprecated. Requirements should be satisfied by a PEP 517 installer.
warnings.warn(
WARNING: The wheel package is not available.
WARNING: The wheel package is not available.
WARNING: The wheel package is not available.
usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
or: setup.py --help [cmd1 cmd2 ...]
or: setup.py --help-commands
or: setup.py cmd --help
error: invalid command 'bdist_wheel'
[end of output]
python --version
: 3.11.2
mac osx 10.14.6
I'd like to see a release for this repo and i'm happy to contribute for that. The "nostr" project-name is already taken but the owner is happy to pass it over. I've volunteered to coordinate the first release and i'm happy to pass the ownership over as soon as you would like to have it (or @labteral / @/brunneis is passing it over directly).
Traceback (most recent call last):
File "/home/test/Downloads/python-nostr/str1.py", line 19, in <module>
relay_manager.publish_message(message)
File "/home/test/Downloads/python-nostr/nostr/relay_manager.py", line 42, in publish_message
relay.publish(message)
File "/home/test/Downloads/python-nostr/nostr/relay.py", line 47, in publish
self.ws.send(message)
File "/home/test/.local/lib/python3.10/site-packages/websocket/_app.py", line 203, in send
if not self.sock or self.sock.send(data, opcode) == 0:
File "/home/test/.local/lib/python3.10/site-packages/websocket/_core.py", line 278, in send
return self.send_frame(frame)
File "/home/test/.local/lib/python3.10/site-packages/websocket/_core.py", line 306, in send_frame
l = self._send(data)
File "/home/test/.local/lib/python3.10/site-packages/websocket/_core.py", line 520, in _send
return send(self.sock, data)
File "/home/test/.local/lib/python3.10/site-packages/websocket/_socket.py", line 143, in send
raise WebSocketConnectionClosedException("socket is already closed.")
websocket._exceptions.WebSocketConnectionClosedException: socket is already closed.
I'd love to use this but I'm already working in Python 3.11. I can't even import the library properly.
BTW I added it to my project with poetry add git+https://github.com/jeffthibault/python-nostr.git
instead of PyPi.
First error trying to use the connect to relays example is this:
ValueError: mutable default <class 'nostr.relay.RelayPolicy'> for field policy is not allowed: use default_factory
A quick look at the code and I can't understand how this:
relay_manager.open_connections(
{"cert_reqs": ssl.CERT_NONE}
) # NOTE: This disables ssl certificate verification
Will work as I can't see a open_connections
method on that class, is the doc out of date?
I would like to provide NIP-57 support to the people all using my non-custodial NIP-05 system but I really don't have the capacity to dig into this library and fix it at this time.
I tried to install for Dev but had a bunch of problems which I can expand on if it helps anyone, suffice to say I can't get a dev environment working properly.
Not the same error as #88.
There doesn't seem to be anything in the readme addressing this.
Publish to relays
from nostr.event import Event
from nostr.relay_manager import RelayManager
from nostr.message_type import ClientMessageType
from nostr.key import generate_private_key, get_public_key
relay_manager = RelayManager()
relay_manager.add_relay("wss://nostr-pub.wellorder.net")
relay_manager.add_relay("wss://relay.damus.io")
relay_manager.open_connections()
private_key = generate_private_key()
public_key = get_public_key(private_key)
event = Event(public_key, "Hello Nostr")
event.sign(private_key)
message = json.dumps([ClientMessageType.EVENT, event.to_json_object()])
relay_manager.publish_message(message)
I am assuming event type/kind will be 1 using this example. Is it possible to specify a number for event kind using this library?
I'm hobbling together a script to post events and am running into this error. The script also includes the watchdog
module for monitoring a directory for new files. Is there some sort of "events" name collision somewhere maybe? I used pprint
to dump the PrivateKey
object's attributes. The event looks like it's created successfully but I'm unable to actually sign it. This is with python 3.9.5.
{'content': 'Doc Hodlday sends his regards ',
'created_at': 1674353522,
'id': '818a24313b54cc98234cbc11edbf9ae11631405083251341631c54351d80810a',
'kind': <EventKind.TEXT_NOTE: 1>,
'public_key': '0000000025a7ccbf6bd0c0a5a1856d78f2e9f08c778b779d35e81b5ea3f77edf',
'signature': None,
'tags': []}
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python3.9/threading.py", line 954, in _bootstrap_inner
self.run()
File "/home/user/.local/lib/python3.9/site-packages/watchdog/observers/api.py", line 205, in run
self.dispatch_events(self.event_queue)
File "/home/user/.local/lib/python3.9/site-packages/watchdog/observers/api.py", line 381, in dispatch_events
handler.dispatch(event)
File "/home/user/.local/lib/python3.9/site-packages/watchdog/events.py", line 271, in dispatch
self.on_any_event(event)
File "/home/user/satbot/telegram.py", line 80, in on_any_event
private_key.sign_event(nostr_event)
AttributeError: 'PrivateKey' object has no attribute 'sign_event'
Opend a PR to push the "Installation section to the top"
PR request : #92
NIP 38 is not merged yet although encrypted channels could be useful for many use cases. It is already supported in nostr_console, please add it in python-nostr so that I can use it in joinstr to improve privacy and security.
When you try to run the delegation example as in the README file, I always got this error:
TypeError: Object of type bytes is not JSON serializable
Apparently, it is on event.py serialize() method when trying to json.dump the data.
Any help regarding this issue?
python-nostr/nostr/relay_manager.py
Line 22 in 69ff17b
Problem:
"subscriptions" argument is a dict, which is mutable in python. This leads to the problem of handling all relay's subscriptions as the same object.
If I add a subscription only to 1 relay, it will be added to all relays. This is seemingly not an issue, but it is the same for deleting a subscription from 1 relay, deletes from all other. So the for cycle in RelayManager
will fail to close the second relay's subscription, because it is closed when we close the first relay's subscription.
I am not sure if NIP 9 is supported by python-nostr however it will be really helpful to delete events if required.
All the examples use "run_sync" which reconnects to the relays on every request
Should be able to keep the connection open and simply make more requests until the connection closes, right?
That seems more in-line with the protocol, imo. But maybe i'm reading it wrong.
I suspect using websockets directly, rather than tornado, would actually simplify this lib.
@jeffthibault Would you be willing to accept a PR in which secp256k1 is replaced by coincurve (https://github.com/ofek/coincurve) ?
The advantage is that coincurve is a cross-plattform binding for libsecp256k1.
Before I make everything ready, I just want a confirmation.
The default value for created_at in the Event
class seems to hold the time.time()
value from the time of import.
Example of a failing test below:
from nostr.event import Event
from nostr.key import PrivateKey
import time
time.sleep(2)
event = Event(public_key=PrivateKey().public_key.hex(), content='this is a test')
assert event.created_at == int(time.time())
import json
import ssl
import time
from nostr.relay_manager import RelayManager
private_key = PrivateKey()
public_key = private_key.public_key
senderPrivateKey = PrivateKey()
senderPublicKey = senderPrivateKey.public_key
receiverPrivateKey = PrivateKey()
receiverPublicKey = receiverPrivateKey.public_key
sharedSecretPrivate = PrivateKey()
sharedSecretPublic = sharedSecretPrivate.public_key
print(f"Private key: {sharedSecretPrivate.bech32()}")
print(f"Public key: {sharedSecretPublic.bech32()}")
relay_manager = RelayManager()
relay_manager.add_relay("wss://nostr-pub.wellorder.net")
relay_manager.add_relay("wss://relay.damus.io")
relay_manager.open_connections({"cert_reqs": ssl.CERT_NONE}) # NOTE: This disables ssl certificate verification
time.sleep(1.25) # allow the connections to open
while relay_manager.message_pool.has_notices():
notice_msg = relay_manager.message_pool.get_notice()
print(notice_msg.content)
relay_manager.close_connections()```
When I run this, I'm getting the following error:
Traceback (most recent call last):
File "/Users/august/Documents/Nostr/python-nostr/nostr.py", line 5, in <module>
from nostr.relay_manager import RelayManager
File "/Users/august/Documents/Nostr/python-nostr/nostr/relay_manager.py", line 11, in <module>
from .relay import Relay, RelayPolicy, RelayProxyConnectionConfig
File "/Users/august/Documents/Nostr/python-nostr/nostr/relay.py", line 33, in <module>
@dataclass
^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/dataclasses.py", line 1221, in dataclass
return wrap(cls)
^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/dataclasses.py", line 1211, in wrap
return _process_class(cls, init, repr, eq, order, unsafe_hash,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/dataclasses.py", line 959, in _process_class
cls_fields.append(_get_field(cls, name, type, kw_only))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/dataclasses.py", line 816, in _get_field
raise ValueError(f'mutable default {type(f.default)} for field '
ValueError: mutable default <class 'nostr.relay.RelayPolicy'> for field policy is not allowed: use default_factory
Any ideas?
Please list all NIPs supported by python-nostr in README
I want to run a client bot on the server. When a client chats with it, it will return what the client says. The code runs well in the first few minutes, but it cannot receive messages and send messages after that. The process is stuck at while relay_manager.message_pool.has_events():
(because when I stop the process, the exception location is in this line)
The code is below
# keys
bob_keys = ("XXX",
"XXX")
bob_private = PrivateKey.from_nsec(bob_keys[0])
bob_public = bob_private.public_key.hex()
# event filter
filters = Filters([Filter(
# authors=[alice_public],
kinds=[EventKind.ENCRYPTED_DIRECT_MESSAGE],
pubkey_refs=[bob_public],
since=int(time.time()) # the create time should after current time
)])
subscription_id = "sub"
request = [ClientMessageType.REQUEST, subscription_id]
request.extend(filters.to_json_array())
# nostr config
relay_manager = RelayManager()
relay_manager.add_relay("wss://nostr.yaohaizhou.com")
relay_manager.add_subscription_on_all_relays(subscription_id, filters)
# time.sleep(1.25) # allow the connections to open
conversation_id = {}
parent_id = {}
# DMs
while(1):
# print("loop")
while relay_manager.message_pool.has_events():
# pdb.set_trace()
# print("New event!")
event_msg = relay_manager.message_pool.get_event()
alice_public = event_msg.event.public_key
alice_name = event_msg.event.public_key[:6]
try:
decrypted_contents = bob_private.decrypt_message(
event_msg.event.content, # the encrypted message, sent by Alice
alice_public # we now use Alice's public key to decrypt it again
)
print(alice_name+f" said: {decrypted_contents}")
except:
pass
print("Chatbot: ")
dm = EncryptedDirectMessage(
recipient_pubkey=alice_public,
cleartext_content=decrypted_contents
)
bob_private.sign_event(dm)
relay_manager.publish_event(dm)
It seems like the version on PyPy (the one you install with pip install
) is pretty outdated. It misses a lot of code that exists on the github repo but not the pypi version.
May i ask when the next update to pypi is being pushed?
Hey Guys, I just saw that update_subscription is implemented in the relay, but not in the manager.
def update_subscription(self, id: str, filters: Filters):
for relay in self.relays.values():
relay.update_subscription(id, filters)
If I create a branch locally and push it, I get permission denied. How can I contribute? Would like to add this and future PR. Would be happy for some advice!
I am getting this error:
Using this code:
import time
import threading
from nostr.relay_manager import RelayManager
import logging
logging.basicConfig(level=logging.INFO)
def main():
relay_manager = RelayManager()
relay_manager.add_relay("wss://nostr.zebedee.cloud")
relay_manager.add_relay("wss://nostr.bitcoiner.social")
logging.info(f"Connections opened: ") # add more logging info
time.sleep(1.25) # allow the connections to open
threading.Thread(target=run, args=(relay_manager,)).start()
def run(relay_manager):
with relay_manager.lock:
relay_manager.close_all_relay_connections()
logging.info(f"Connections closed ...")
I saw a similar error already reported. I can't figure out how to fix it, it could easily be my own error as I am not very experienced using threading or locks.
Thanks!
from nostr.key import PrivateKey
private_key = PrivateKey.from_nsec("nsec180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsgyumg0")
public_key = private_key.public_key.from_npub("npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6")
print(f"Private key -> hex: {private_key.hex()} bech32: {private_key.bech32()}")
print(f"Public key -> hex: {public_key.hex()} bech32: {public_key.bech32()}")
Running this snippet produces this:
Private key -> hex: 3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d bech32: nsec180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsgyumg0
Public key -> hex: 3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d bech32: npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6
This snippet seems to produce the exact same hex value for both the public AND private key.
If we try with a different keypair, the hex values are not the same:
Private key -> hex: aebb7f8958d51b018bba4c6a0a704e52b456e2ddcab77810ad93ab1761e04797 bech32: nsec146ahlz2c65dsrza6f34q5uzw2269dckae2mhsy9djw43wc0qg7tsuzgg3p
Public key -> hex: 1397de906b7702ccfb71804d6d1ab12c6b094a05709e20a834a5426ee08e554d bech32: npub1zwtaayrtwupve7m3spxk6x43934sjjs9wz0zp2p554pxacyw24xstl4shy
Correct me if i'm wrong, but isn't this a collision?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.