Vue d’ensemble
revolution/laravel-nostr est un package qui permet d’utiliser le protocole Nostr depuis Laravel. Il propose la génération et la conversion de clés, la récupération et la publication d’événements, la prise en charge de pools (plusieurs relays), les profils NIP-05, les messages directs privés NIP-17, ainsi que l’intégration avec Laravel Notifications.
Les spécifications de Nostr évoluent encore, ce package est donc en développement continu. La fonctionnalité de notification est déjà utilisable en pratique.
Pilotes
Ce package propose deux pilotes.
| Pilote | Description |
|---|
native | Implémentation en PHP pur. Utilise nostr-php. Suffisant à l’heure actuelle. |
node | Implémentation dépendant d’une WebAPI externe (Node.js). |
La particularité du pilote native est son implémentation WebSocketHttpMixin. Il se connecte en WebSocket via le client HTTP de Laravel, échange des données puis se déconnecte immédiatement. Il n’est pas nécessaire de faire tourner un serveur WebSocket en continu, ce qui rend cette solution accessible à tout utilisateur de Laravel.
Le pilote native ne prend pas en charge NIP-04.
Configuration du pilote par défaut
Configurez dans config/nostr.php ou .env.
// config/nostr.php
'driver' => env('NOSTR_DRIVER', 'node'),
Si aucun pilote n’est spécifié, le pilote par défaut est utilisé.
use Revolution\Nostr\Facades\Nostr;
Nostr::event()->list();
Vous pouvez également spécifier explicitement le pilote.
use Revolution\Nostr\Facades\Nostr;
Nostr::driver('node')->event()->list();
Nostr::node()->event()->list();
Nostr::driver('native')->event()->list();
Nostr::native()->event()->list();
Installation
Installer le package
composer require revolution/laravel-nostr
Publier le fichier de configuration
php artisan vendor:publish --tag=nostr-config
Gestion des clés
Générer une clé
use Revolution\Nostr\Facades\Nostr;
use Illuminate\Http\Client\Response;
/** @var Response $response */
$response = Nostr::key()->generate();
$keys = $response->json();
// [
// 'sk' => 'sk...',
// 'nsec' => 'nsec...',
// 'pk' => 'pk...',
// 'npub' => 'npub...',
// ]
Convertir une clé
Conversion depuis un nsec.
use Revolution\Nostr\Facades\Nostr;
$response = Nostr::key()->fromNsec(nsec: 'nsec');
$keys = $response->json();
// ['sk' => '...', 'nsec' => '...', 'pk' => '...', 'npub' => '...']
Conversion depuis une secret key.
$response = Nostr::key()->fromSecretKey(sk: 'sk');
Conversion depuis un npub (clé publique uniquement).
$response = Nostr::key()->fromNpub(npub: 'npub');
$keys = $response->json();
// ['pk' => '...', 'npub' => '...']
Conversion depuis une public key.
$response = Nostr::key()->fromPublicKey(pk: 'pk');
Récupération d’événements
Récupérer plusieurs événements
use Illuminate\Http\Client\Response;
use Revolution\Nostr\Facades\Nostr;
use Revolution\Nostr\Filter;
use Revolution\Nostr\Kind;
$filter = Filter::make(
authors: ['my pk'],
kinds: [Kind::Text],
limit: 10,
);
/** @var Response $response */
$response = Nostr::event()->list(filter: $filter);
$events = $response->json('events');
// [
// ['id' => '...1', 'kind' => 1, 'content' => '...'],
// ['id' => '...2', 'kind' => 1, 'content' => '...'],
// ]
Récupérer un seul événement
use Revolution\Nostr\Facades\Nostr;
use Revolution\Nostr\Filter;
use Revolution\Nostr\Kind;
$filter = Filter::make(
authors: ['my pk'],
kinds: [Kind::Metadata],
);
$response = Nostr::event()->get(filter: $filter);
$event = $response->json('event');
// ['id' => '...', 'kind' => 0, 'content' => '{name: ""}']
Publication d’événements
Publier sur un seul relay
use Revolution\Nostr\Facades\Nostr;
use Revolution\Nostr\Event;
use Revolution\Nostr\Kind;
$event = Event::make(
kind: Kind::Text,
content: 'hello',
created_at: now()->timestamp,
tags: [],
);
$sk = 'my sk';
$response = Nostr::event()->publish(event: $event, sk: $sk);
if ($response->successful()) {
$event = $response->json('event');
}
Publier sur plusieurs relays (pool)
use Revolution\Nostr\Facades\Nostr;
use Revolution\Nostr\Event;
use Revolution\Nostr\Kind;
$event = Event::make(
kind: Kind::Text,
content: 'test',
created_at: now()->timestamp,
tags: [],
);
$responses = Nostr::pool()->publish(event: $event, sk: 'my sk');
// $responses est de type array<string, Response>
// ['wss://relay1' => $response, 'wss://relay2' => $response]
foreach ($responses as $relay => $response) {
if ($response->failed()) {
dump($relay . ' : ' . $response->body());
}
}
Configuration des serveurs relay
Serveurs relay utilisés
Si vous utilisez uniquement Nostr::event(), le premier relay défini dans config/nostr.php est utilisé. Avec Nostr::pool(), tous les relays de la configuration sont ciblés.
Modifier les relays à l’exécution
use Revolution\Nostr\Facades\Nostr;
$response = Nostr::event()->withRelay('wss://')->...;
use Revolution\Nostr\Facades\Nostr;
$response = Nostr::pool()->withRelays(['wss://', 'wss://'])->...;
Profils NIP-05
use Revolution\Nostr\Facades\Nostr;
$profile = Nostr::nip05()->profile('user@localhost');
// [
// 'user' => 'user@localhost',
// 'pubkey' => 'pk',
// 'relays' => [],
// ]
Messages directs privés NIP-17
NIP-17 n’est pris en charge que par le pilote native.
Envoyer un message privé
use Revolution\Nostr\Facades\Nostr;
$response = Nostr::driver('native')
->nip17()
->sendDirectMessage(
sk: 'sender-secret-key',
pk: 'receiver-public-key',
message: 'Hello, this is a private message!'
);
Déchiffrer un message privé
use Revolution\Nostr\Facades\Nostr;
$response = Nostr::driver('native')
->nip17()
->decryptDirectMessage(
giftWrap: $receivedGiftWrap,
sk: 'receiver-secret-key'
);
$decryptedMessage = $response->json();
Laravel Notifications
Avec NostrChannel, vous pouvez envoyer des messages vers Nostr depuis Laravel Notifications.
Classe Notification
use Illuminate\Notifications\Notification;
use Revolution\Nostr\Notifications\NostrChannel;
use Revolution\Nostr\Notifications\NostrMessage;
use Revolution\Nostr\Tags\HashTag;
class TestNotification extends Notification
{
public function via(object $notifiable): array
{
return [
'mail',
NostrChannel::class,
];
}
public function toNostr(object $notifiable): NostrMessage
{
return new NostrMessage(
// Le #laravel dans le content sert à l'affichage ; le HashTag dans tags est destiné à la classification au niveau du protocole.
content: 'hello #laravel',
tags: [
HashTag::make(t: 'laravel'),
],
);
}
}
Notification à la demande
use Illuminate\Support\Facades\Notification;
use Revolution\Nostr\Notifications\NostrRoute;
Notification::route('nostr', NostrRoute::to(sk: 'sk'))
->notify(new TestNotification());
Intégration au modèle User
use Illuminate\Notifications\Notifiable;
use Revolution\Nostr\Notifications\NostrRoute;
class User
{
use Notifiable;
public function routeNotificationForNostr($notification): NostrRoute
{
return NostrRoute::to(sk: $this->sk, relays: ['wss://']);
}
}
$user->notify(new TestNotification());
Relays utilisés pour les notifications
Par défaut, tous les relays de config/nostr.php sont utilisés. Vous pouvez les modifier à l’exécution en spécifiant des relays dans NostrRoute.
use Revolution\Nostr\Notifications\NostrRoute;
return NostrRoute::to(sk: 'sk', relays: ['wss://', 'wss://']);