| Crates.io | pubky-messenger |
| lib.rs | pubky-messenger |
| version | 0.3.0 |
| created_at | 2025-06-18 01:15:08.211544+00 |
| updated_at | 2025-11-09 23:25:23.003018+00 |
| description | A Rust library for private messaging using Pubky |
| homepage | |
| repository | https://github.com/coreyphillips/pubky-messenger |
| max_upload_size | |
| id | 1716443 |
| size | 175,108 |
A Rust library for secure private messaging using the Pubky protocol. This library provides end-to-end encrypted messaging capabilities with authentication via pkarr recovery files.
Add this to your Cargo.toml:
[dependencies]
pubky-messenger = "0.2.1"
use pubky_messenger::{PrivateMessengerClient, PublicKey};
use anyhow::Result;
#[tokio::main]
async fn main() -> Result<()> {
// Load recovery file
let recovery_file = std::fs::read("recovery.pkarr")?;
// Create client with passphrase
let client = PrivateMessengerClient::from_recovery_file(&recovery_file, Some("your_passphrase"))?;
// Or without passphrase (defaults to empty string)
// let client = PrivateMessengerClient::from_recovery_file(&recovery_file, None)?;
// Sign in
client.sign_in().await?;
// Send a message
let recipient = PublicKey::try_from("recipient_public_key_here")?;
let message_id = client.send_message(&recipient, "Hello, world!").await?;
println!("Message sent with ID: {}", message_id);
// Get messages
let messages = client.get_messages(&recipient).await?;
for msg in messages {
println!("{}: {}", msg.sender, msg.content);
}
Ok(())
}
If you already have a keypair, you can create the client directly:
use pkarr::Keypair;
use pubky_messenger::PrivateMessengerClient;
let keypair = Keypair::random();
let client = PrivateMessengerClient::new(keypair)?;
You can also create a client using a 12-word mnemonic recovery phrase with optional passphrase and language:
use pubky_messenger::PrivateMessengerClient;
// Basic usage - defaults to English, no passphrase
let mnemonic = "your twelve word recovery phrase goes here with spaces between words";
let client = PrivateMessengerClient::from_recovery_phrase(mnemonic, None, None)?;
// Sign in and use as normal
client.sign_in().await?;
With optional passphrase for additional security:
// Add a passphrase for extra security
let client_with_passphrase = PrivateMessengerClient::from_recovery_phrase(
mnemonic,
Some("my_secure_passphrase"), // Optional passphrase
None, // Use default English
)?;
With different language:
use pubky_messenger::{Language, PrivateMessengerClient};
// Use a different language
let client = PrivateMessengerClient::from_recovery_phrase(
mnemonic,
None, // No passphrase
Some(Language::English), // Explicit language
)?;
With both passphrase and language:
let client = PrivateMessengerClient::from_recovery_phrase(
mnemonic,
Some("my_passphrase"), // Optional passphrase
Some(Language::English), // Optional language
)?;
The recovery phrase must be:
Parameters:
mnemonic_phrase: The 12-word BIP39 mnemonic (required)passphrase: Optional passphrase for additional security (defaults to empty string)language: Optional language for mnemonic validation (defaults to English)This method provides a deterministic way to recover your keypair from a mnemonic phrase. The same mnemonic with the same passphrase and language will always produce the same keypair.
// Get your own profile
if let Some(profile) = client.get_own_profile().await? {
println!("Name: {}", profile.name);
println!("Bio: {:?}", profile.bio);
}
// Get followed users
let followed = client.get_followed_users().await?;
for user in followed {
println!("{}: {}", user.pubky, user.name.unwrap_or_default());
}
The library provides methods to delete messages from your conversations:
// Delete a single message
let message_id = "550e8400-e29b-41d4-a716-446655440000";
client.delete_message(message_id, &recipient).await?;
// Delete multiple messages at once
let message_ids = vec![
"id1".to_string(),
"id2".to_string(),
"id3".to_string(),
];
client.delete_messages(message_ids, &recipient).await?;
// Clear all your sent messages in a conversation
client.clear_messages(&recipient).await?;
Note: These delete operations only remove messages from your own storage on the Pubky network. Messages stored by the recipient remain unchanged.
PrivateMessengerClientThe main client for interacting with the Pubky messaging system.
new(keypair: Keypair) -> Result<Self> - Create a new client from a keypairfrom_recovery_file(bytes: &[u8], passphrase: Option<&str>) -> Result<Self> - Create from recovery file with optional passphrasefrom_recovery_phrase(mnemonic: &str, passphrase: Option<&str>, language: Option<Language>) -> Result<Self> - Create from 12-word BIP39 mnemonic with optional passphrase and languagesign_in(&self) -> Result<Session> - Sign in to the homeserversend_message(&self, recipient: &PublicKey, content: &str) -> Result<String> - Send encrypted messageget_messages(&self, other: &PublicKey) -> Result<Vec<DecryptedMessage>> - Get conversation messagesdelete_message(&self, message_id: &str, other: &PublicKey) -> Result<()> - Delete a single messagedelete_messages(&self, message_ids: Vec<String>, other: &PublicKey) -> Result<()> - Delete multiple messagesclear_messages(&self, other: &PublicKey) -> Result<()> - Clear all sent messages in a conversationget_own_profile(&self) -> Result<Option<PubkyProfile>> - Get user's profileget_followed_users(&self) -> Result<Vec<FollowedUser>> - Get followed userspublic_key(&self) -> PublicKey - Get the client's public keypublic_key_string(&self) -> String - Get public key as stringDecryptedMessage - A decrypted message with sender, content, timestamp, and verification statusPubkyProfile - User profile information (name, bio, image, status)FollowedUser - Information about a followed userAll methods return Result<T> where the error type is anyhow::Error. This provides flexible error handling with context. Common error scenarios include:
Example error handling:
match client.send_message(&recipient, "Hello").await {
Ok(message_id) => println!("Message sent: {}", message_id),
Err(e) => eprintln!("Failed to send message: {}", e),
}
Check the examples/ directory for more detailed examples:
# Run the basic usage example
cargo run --example basic_usage -- path/to/recovery.pkarr [optional_recipient_pubky]
This example demonstrates:
# Send a message to a specific pubky
cargo run --example send_message -- path/to/recovery.pkarr recipient_pubky "Your message here"
# Example:
cargo run --example send_message -- recovery.pkarr pk:q9x5sfjbpajdebk45b9jashgb86iem7rnwpmu16px3ens63xzwro "Hello there!"
This example:
# Read all messages from a conversation with a specific pubky
cargo run --example read_messages -- path/to/recovery.pkarr peer_pubky
# Example:
cargo run --example read_messages -- recovery.pkarr pk:q9x5sfjbpajdebk45b9jashgb86iem7rnwpmu16px3ens63xzwro
This example:
# Start an interactive chat session with a specific pubky
cargo run --example conversation -- path/to/recovery.pkarr peer_pubky
# Example:
cargo run --example conversation -- recovery.pkarr pk:q9x5sfjbpajdebk45b9jashgb86iem7rnwpmu16px3ens63xzwro
This example provides a real-time chat experience:
Features:
The library includes comprehensive unit and integration tests. Due to API rate limiting, it's recommended to run tests sequentially:
# Run all tests sequentially (recommended)
cargo test -- --test-threads=1
# Run specific test file
cargo test --test test_delete_methods -- --test-threads=1
# Run with output for debugging
cargo test -- --test-threads=1 --nocapture
The repository includes test recovery files (p1.pkarr and p2.pkarr) in the root directory for integration testing. Both use "password" as the passphrase.
Important: These test files are for development only and should never be used in production.
When writing tests that interact with the Pubky network:
tokio::time::sleep)This library implements end-to-end encryption using:
Messages are encrypted with a shared secret derived from the sender and recipient's keypairs.
MIT