Skip to content

Commit

Permalink
[ Edit ] reviewed and modified the README.md for better understanding
Browse files Browse the repository at this point in the history
  • Loading branch information
anasfik committed May 19, 2023
1 parent e578646 commit 90d2e6d
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 110 deletions.
153 changes: 75 additions & 78 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,103 +16,68 @@ Some NIPs have a custom implementation in this package like the NIP-05, which yo

Some other implementations are not intended to work in the Dart environment, so they are not implemented in this package, such as NIP-07 which is based on the `window` object of a browser. that being said it can be implemented separately if there is a use of Flutter web, but for now, it is not implemented.

- NIP-01
- NIP-02
- NIP-03
- NIP-04 (TODO: make the encryption part automated by the package).
- NIP-05
- NIP-09
- NIP-10
- NIP-11
- NIP-12
- NIP-14
- NIP-16
- NIP-18
- NIP-20
- NIP-23
- NIP-25
- NIP-27
- NIP-28
- NIP-33
- NIP-36
- NIP-39
- NIP-40
- NIP-56
- NIP-65
NIP-01, NIP-02, NIP-03, NIP-04 (TODO: make the encryption part automated by the package), NIP-05, NIP-06, NIP-09, NIP-10, NIP-11, NIP-12, NIP-14, NIP-16, NIP-18, NIP-20, NIP-23, NIP-25, NIP-27, NIP-28, NIP-33, NIP-36, NIP-39, NIP-40, NIP-56, NIP-65.

## TODO (if you want to contribute, please feel free to implement any of the following NIPS and make a pull request, I will be happy to review it and merge it.)

- NIP-06
- NIP-13
- NIP-19
- NIP-26
- NIP-42
- NIP-45
- NIP-50
- NIP-51
- NIP-57
- NIP-58
NIP-13, NIP-19, NIP-26, NIP-42, NIP-45, NIP-50, NIP-51, NIP-57, NIP-58

# Usage:

The main and only instance that you need to use to access all other members in this package is:
The main and only singleton instance that you need to use to access all other services of this package is:

```dart
Nostr.instance;
```

`Nostr.instance` offers access to separated services of this package which they-self offer many other members/functions to get your things done.
`Nostr.instance` offers access to all services of this package which they-self offer many other members/functions to get your things done:

```dart
Nostr.instance.keysService; // access to the keys service, which will provide methods to handle user key pairs, private keys, public keys, etc.
Nostr.instance.relaysService; // access to the relays service, which will provide methods to interact with your own relays such as sending events, listening to events, etc.
Nostr.instance.utilsService; // access the utils service, which provides many handy utils that you will need to use in your app, such as encoding, getting random hex strings to use with requests, etc.
```

<br>

## Keys Service:

This service is responsible for handling anything that is related to the user's key pairs, private keys, public keys, signing and verifying messages, etc.
This service is responsible for handling anything that is related to the nostr keys including generating and deriving private & public keys, signing and verifying messages, etc.

#### Generate a new key pair:

In order to generate a new key pair, you will need to call the `generateKeyPair()` function, which will return a `NostrKeyPairs` object that contains the private key and the public key of the generated key pair.
In order to generate a new key pair of a private and a public keys, you will need to call the `generateKeyPair()` method, which will return a `NostrKeyPairs` object that contains them:

```dart
NostrKeyPairs keyPair = await Nostr.instance.keysService.generateKeyPair();
NostrKeyPairs keyPair = Nostr.instance.keysService.generateKeyPair();
print(keyPair.private); // ...
print(keyPair.public); // ...
// or maybe give it to your user so he owns it.
```

#### Get a key pair from an existent private key:

If you already have a private key, you can get a key pair from it by calling the `generateKeyPairFromExistingPrivateKey()` function, which will return a `NostrKeyPairs` object that contains the private key and the generated public key.
when you have an existent private key, you can get it's key pair directly by calling the `generateKeyPairFromExistingPrivateKey()` method, which will return a `NostrKeyPairs` object that contains that private key and it's associated public key.

```dart
NostrKeyPairs keyPair = await Nostr.instance.keysService.generateKeyPairFromExistingPrivateKey(privateKey);
NostrKeyPairs keyPair = Nostr.instance.keysService.generateKeyPairFromExistingPrivateKey(privateKey);
```

#### generate and get a new private key directly:

Sometimes, you will need to only generate a private key and not a key pair, in this case, you can call the `generatePrivateKey()` function, which will return a `String` that contains the generated private key directly.
Sometimes, you will need to only generate a private key and not a key pair, in this case, you can call the `generatePrivateKey()` method, which will return a `String` that contains the generated private key directly.

```dart
String privateKey = await Nostr.instance.keysService.generatePrivateKey();
```

#### Derive a public key from a private key directly:

Or, if you already have a private key, you can derive the public key from it by calling the `derivePublicKey()` function, which will return a `String` that contains the derived public key directly.

```dart
String publicKey = await Nostr.instance.keysService.derivePublicKey(privateKey);
```

#### Sign and verify a message:

To sign a message, you will need to call the `sign()` function, which will return a `String` that contains the signature of the message.
To sign a message, you will need to call the `sign()` method, which will return a `String` that contains the signature of the message, then if you want to verify that message, you can call the `verify()` method, which will return a `bool` that indicates if the message is verified or not.

```dart
String message = ...;
Expand All @@ -134,9 +99,11 @@ print(isMessageVerified); // ...

## Relays Service:

The relays service is responsible for anything related to the actual interaction with relays such connecting to them, sending events to them, listening to events from them, etc.

#### Creating and signing Nostr events:

You can get the final events that you will send to your relays by either creating a raw `NostrEvent` object and then you will need to generate and set it's `id` and `sign` by yourself using the Nostr protocol speceifications which you can check manually from it's official documentation.
You can get the final events that you will send to your relays by either creating a raw `NostrEvent` object and then you will need to generate and set literally all its properties by yourself using the Nostr protocol specifications which you will need to have a basic [understanding of it](https://github.com/nostr-protocol/nips/blob/master/01.md) :

```dart
Expand All @@ -151,14 +118,16 @@ You can get the final events that you will send to your relays by either creatin
);
```

As it is explained, this will require you to set every single value of the event manually, including the `id` and `sig` values.
As it is explained, this will require you to set every single value of the event properties manually, including the `id` and `sig` values.

This package covers you in thus part and offers a `NostrEvent.fromPartialData(...)` which requires only the direct fields to be set and the rest will be handled automatically so you don't need to worry about it.
Well, we al lve easy things right? This package offers the option to handle all this internally and covers you in this part with the `NostrEvent.fromPartialData(...)` which requires you to only set the direct necessary fields and the rest will be handled internally so you don't need to worry about it:

```dart
final pair = Nostr.instance.keysService.generateKeyPair();
final event = NostrEvent.fromPartialData(
kind: 0,
keyPairs: "<THE-KEYPAIRS-OF-THE-EVENT-CREATOR>",
keyPairs: pair,
content: 'This is a test event content',
tags: [],
createdAt: DateTime.parse('...'),,
Expand All @@ -167,78 +136,105 @@ This package covers you in thus part and offers a `NostrEvent.fromPartialData(..

The only required fields here are `kind`, `keyPairs` and `content`.

- if `tags` is ignored, it will be set to `[]`.
- if `createdAt` is ignored, it will be set to `DateTime.now()` automatically.
- other fields like `id` and `sign` will be generated automatically.
- if `tags` is ignored, it will be set to an empty list `[]`.

- if `createdAt` is ignored, it will be set to the current date `DateTime.now()` .

- other fields like `id`, `sign` and pubkey is what you don't need to worry about, they will be generated and set internally.


`NostrEvent.fromPartialData` requires the `keyPairs` because it needs to get the private key to sign the event and assign to the `sign` field, and it needs to get the public key to use it as the `pubkey` of the event.

To get a `NostrKeyPairs` of your event creator, refer please to the [Keys Service](#keys-service) section.


#### Connecting to relay(s):

as I already said, this package exposes only one main instance, which is `Nostr.instance`, you will need to initialize/connect to your relay(s) only one time in your Dart/Flutter app with:
As I already said, this package exposes only one main instance, which is `Nostr.instance`, you will need to initialize/connect to your relay(s) only one time in your Dart/Flutter app with:

```dart
Nostr.instance.relaysService.init(
relaysUrl: ['wss://relay.damus.io'],
onRelayListening: (String relayUrl, receivedData) {}, // will be called once a relay is connected and listening to events.
onRelayError: (String relayUrl, Object? error) {}, // will be called once a relay is disconnected or an error occurred.
onRelayDone: (String relayUrl) {}, // will be called once a relay is disconnected, finished.
lazyListeningToRelays: false, // if true, the relays will not start listening to events until you call `Nostr.instance.relaysService.startListeningToRelays()`, if false, the relays will start listening to events as soon as they are connected.
onRelayListening: (String relayUrl, receivedData) {}, // will be called once a relay is connected and listening to events.
onRelayError: (String relayUrl, Object? error) {}, // will be called once a relay is disconnected or an error occurred.
onRelayDone: (String relayUrl) {}, // will be called once a relay is disconnected, finished.
lazyListeningToRelays: false, // if true, the relays will not start listening to events until you call `Nostr.instance.relaysService.startListeningToRelays()`, if false, the relays will start listening to events as soon as they are connected.
retryOnError: false, // Weither to ro retry connecting to relay(s) if an error occurred to them .
retryOnClose: false, // Weither to ro retry connecting to relay(s) if they are closed.
bool ensureToClearRegistriesBeforeStarting = true, // Weither to clear the registries of the relays before starting to listen to them, this is useful if you want to implmenta reconnecting feature, so that you will totally clear previous connections and start a new one.
bool ignoreConnectionException: true, // Weither to ignore any exception that occurs while connecting to relay(s) or not (if false, the exception will be thrown and you will have to catch it).
bool shouldReconnectToRelayOnNotice = false, // Weither to reconnect to relay(s) if they sent a [NOTICE, ...] message.
Duration connectionTimeout = const Duration(seconds: 5), // The timeout of the connection to relay(s).
);
```

the only required field here is `relaysUrl`, which accepts a `List<String>` that contains the URLs of your relays web sockets, you can pass as many relays as you want.
The only required field here is `relaysUrl`, which accepts a `List<String>` that contains the URLs of your relays web sockets, you can pass as many relays as you want.

I personally recommend initializing the relays service in the `main()` function of your app, so that it will be initialized as soon as the app starts, and will be available to be used anywhere else in your app.
I personally recommend initializing the relays service in the `main()` function of your app, so that it will be initialized as soon as the app starts, and then it will be available to be used anywhere and anytime in your app.

```dart
void main() {
Nostr.instance.relaysService.init(...);
// if it is a flutter app: runApp(MyApp());
//...
}
```

#### Listening to events from relay(s):

For listening to events from relay(s), you will need to create a `NostrRequest` request with the target filters:
For listening to events from relay(s), you will need to create a `NostrRequest` first with the specify your request type and filters = that you wanna apply as example:

```dart
// creating the request.
NostrRequest req = NostrRequest(
final req = NostrRequest(
filters: [
NostrFilter(
kind: 1,
tags: ["p", "..."],
authors: ["..."],
),
),
],
);
// creating a stream of events.
Stream<NostrEvent> stream = Nostr.instance.relaysService.startEventsSubscription(req);
NostrEventsStream nostrEventsStream = Nostr.instance.relaysService.startEventsSubscription(req);
// listening to the stream.
stream.listen((event) {
nostrEventsStream.stream.listen((event) {
print(event);
});
```
you can set manually the `subscriptionId` of the request, or you can let the package generate it for you automatically.
// closing the nostr nostr events stream after 10 seconds (and yes this will close it for all relays that you're listening to)
Future.delayed(Duration(seconds: 10)).then((value) {
nostrEventsStream.close();
});
```

#### Sending events to relay(s):

When you have an event that is ready to be sent to your relay(s), you can call the `sendEventToRelays()` function with the event as the only parameter:
When you have an event that is ready to be sent to your relay(s) as exmaple the [previous event](#creating-and-signing-nostr-events) that we did created, you can call the `sendEventToRelays()` method with it and send it to relays:

```dart
Nostr.instance.relaysService.sendEventToRelays(event);
```

The event will be sent to all the connected relays now, and if you're already subscribing with a `NostrRequest` to the relays, you will start receiving the event in your stream.
The event will be sent now to all the connected relays now, and if you're already openeing a subsciption to your relays, you will start receiving it in your stream.

<br>

#### nip-05 verification:
#### nip-05 identifier verification:

in order to verify a user pubkey with his internet identifier, you will need to call the `verifyNip05()` function with the user's pubkey and internet identifier as the only parameters:

Expand All @@ -247,14 +243,15 @@ bool isVerified = await Nostr.instance.relaysService.verifyNip05(
internetIdentifier: '<THE-INTERNET-IDENTIFIER-OF-THE-USER>',
pubkey: '<THE-PUBKEY-OF-THE-USER>',
);
print(isVerified); // ...
```

if the user is verified, the function will return `true`, otherwise, it will return `false`.
if the user is verified, the function will return `true`.

#### nip-11 relay Information Document:
#### Relay Information Document:

You can get the relay information document by calling the `getRelayInformationDocument()` function with the relay's URL as the only parameter:
You can get the relay information document (NIP 11) by calling the `getRelayInformationDocument()` function with the relay's URL as the only parameter:

```dart
Expand Down
32 changes: 0 additions & 32 deletions lib/nostr/core/nip06.dart

This file was deleted.

0 comments on commit 90d2e6d

Please sign in to comment.