Giter Club home page Giter Club logo

python-nostr's People

Contributors

armstrys avatar brightonbtc avatar callebtc avatar dni avatar jamesgmorgan avatar jeffthibault avatar kdmukai avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-nostr's Issues

Additional conversion class methods for PublicKey, PrivateKey

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.

[Question] Encryption algorithm

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.

AttributeError: 'NoneType' object has no attribute 'host'

>>> 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'

NIP-06 Support

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.

Unable to install

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!

Handling bad relays in relay_manager.py

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.
  1. Is it possible to add better logging to tell which relays connected and which failed?
  2. In case of one bad relay, I would still like to be able to continue posting to the rest without an exception being thrown.

Thanks

So how do i get a post?

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

bug: publishing message as dictionary instead of string

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.

Can we receive DMs?

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?

[Question] Basic usage

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

Dependency secp256k1 0.14.0 not cross-platform compatible with Windows

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/

How to convert pubkey to hex

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)

EncryptedDirectMessage Issue

`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?

How to get user's "Following"

Hi, is there any way to retrieve every public key of users that a specific public key is following with python-nostr ?

Threading error

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?

Initializing a dict in an argument.

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?

Request: Can we use the code formatter `black`?

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?

Wrong message order/time

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

Bildschirmfoto vom 2022-10-23 15-54-39

ValueError decoding Type 4 DM: "Invalid padding bytes."

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?

[Question] decrypt_message public_key?

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

Events received with custom tags are rejected

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.

[question] what is subscription_id

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

[BUG] Failed to install via pip

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

Creating a Release

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).

WebSocketConnectionClosedException error when trying publish example

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.

Python 3.11 and are the examples up to date?

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.

using different event kinds when publishing

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?

AttributeError: 'PrivateKey' object has no attribute 'sign_event'

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'

NIP 38 support

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.

Delegation error

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?

Mutable argument

def add_relay(self, url: str, read: bool=True, write: bool=True, subscriptions={}):

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.

NIP 9 support

I am not sure if NIP 9 is supported by python-nostr however it will be really helpful to delete events if required.

Persistent connections

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.

Bug in Event default created_at time

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())

relay issue

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?

[BUG] The client is stuck after a few minutes running

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)

[Question] PyPi outdated?

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?

Add update_subscription to relay_manager.

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!

Attribute Error: 'RelayManager' object has no attribute 'lock'

I am getting this error:

image

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!

Potential public-private key collision

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?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.