Skip to content

Commit 7495b10

Browse files
Add comprehensive demo app improvements
- Add network transport integration to Android and iOS examples - Create XX pattern (TOFU) complete example - Add streaming/chunking examples for mobile platforms - Add thread-safety examples for Android and iOS - Create storage-backed messaging example (feature-gated) - Add battery optimization usage examples - Create comprehensive README files for mobile examples - Enhance server example with error handling, rate limiting, and disconnection scenarios - Update examples README with new examples This addresses all remaining improvements identified in DEMO_APPS_REVIEW.md, bringing demo app coverage from 75% to 95%+ and improving production readiness.
1 parent 675c48f commit 7495b10

File tree

14 files changed

+6294
-86
lines changed

14 files changed

+6294
-86
lines changed

DEMO_APPS_REVIEW.md

Lines changed: 616 additions & 0 deletions
Large diffs are not rendered by default.

examples/README.md

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# PubkyNoise Rust Examples
2+
3+
This directory contains standalone Rust examples demonstrating various features of the `pubky-noise` library.
4+
5+
## Running Examples
6+
7+
All examples can be run with:
8+
9+
```bash
10+
cargo run --example <example_name>
11+
```
12+
13+
## Available Examples
14+
15+
### basic_handshake.rs
16+
17+
Complete IK pattern handshake between client and server with encrypted message exchange.
18+
19+
```bash
20+
cargo run --example basic_handshake
21+
```
22+
23+
**Demonstrates:**
24+
- Client and server setup
25+
- 3-step IK handshake
26+
- Encryption/decryption
27+
- Session ID verification
28+
29+
### server_example.rs
30+
31+
Server-side implementation handling multiple client connections.
32+
33+
```bash
34+
cargo run --example server_example
35+
```
36+
37+
**Demonstrates:**
38+
- Server initialization
39+
- Public key distribution
40+
- Multiple client sessions with `NoiseSessionManager`
41+
- Mobile-optimized server with `NoiseManager`
42+
- Error handling for invalid messages and decryption failures
43+
- Rate limiting patterns
44+
- Client disconnection handling
45+
- Connection timeout management
46+
- Graceful shutdown procedures
47+
48+
### error_handling.rs
49+
50+
Comprehensive error handling patterns for all failure scenarios.
51+
52+
```bash
53+
cargo run --example error_handling
54+
```
55+
56+
**Demonstrates:**
57+
- Invalid peer key detection
58+
- Decryption failure handling
59+
- Error codes for FFI integration
60+
- Error recovery strategies
61+
62+
### streaming.rs
63+
64+
Large message handling with automatic chunking.
65+
66+
```bash
67+
cargo run --example streaming
68+
```
69+
70+
**Demonstrates:**
71+
- `StreamingNoiseLink` usage
72+
- Custom chunk sizes
73+
- Automatic splitting and reassembly
74+
- Mobile-friendly chunk size recommendations
75+
76+
### mobile_manager.rs
77+
78+
Mobile-optimized API with lifecycle management and state persistence.
79+
80+
```bash
81+
cargo run --example mobile_manager
82+
```
83+
84+
**Demonstrates:**
85+
- `NoiseManager` API
86+
- `MobileConfig` options
87+
- State save/restore for app lifecycle
88+
- Connection status tracking
89+
- Multiple session management
90+
91+
### xx_pattern.rs
92+
93+
XX pattern (Trust On First Use) handshake demonstration.
94+
95+
```bash
96+
cargo run --example xx_pattern
97+
```
98+
99+
**Demonstrates:**
100+
- XX pattern handshake flow (3 messages)
101+
- Server key learning during handshake
102+
- Key pinning for future IK connections
103+
- Transition from XX to IK pattern
104+
- Comparison of XX vs IK patterns
105+
- Security considerations for TOFU
106+
107+
### storage_queue.rs
108+
109+
Storage-backed messaging with async operations and retry configuration.
110+
111+
```bash
112+
cargo run --example storage_queue --features storage-queue
113+
```
114+
115+
**Note**: Requires the `storage-queue` feature and Pubky infrastructure.
116+
117+
**Demonstrates:**
118+
- `StorageBackedMessaging` setup
119+
- `RetryConfig` configuration
120+
- Counter persistence (critical for production)
121+
- Async message sending and receiving
122+
- Error handling for storage operations
123+
- Best practices for production use
124+
125+
## Example Structure
126+
127+
Each example follows this pattern:
128+
129+
1. **Setup** - Initialize keys, clients, and servers
130+
2. **Handshake** - Demonstrate the 3-step handshake
131+
3. **Usage** - Show the specific feature
132+
4. **Summary** - Key points and best practices
133+
134+
## Adding New Examples
135+
136+
When creating a new example:
137+
138+
1. Add the `.rs` file to this directory
139+
2. The file must have a `fn main()` function
140+
3. Use `println!` for output (no external dependencies needed)
141+
4. Include comprehensive comments
142+
5. Add documentation header with `//!` comments
143+
6. Update this README
144+
145+
## Dependencies
146+
147+
Most examples use only the main `pubky-noise` crate. The `storage_queue.rs` example requires:
148+
- The `storage-queue` feature to be enabled
149+
- Pubky infrastructure (PubkySession, PublicStorage)
150+
151+
Run with feature:
152+
```bash
153+
cargo run --example storage_queue --features storage-queue
154+
```
155+
156+
## See Also
157+
158+
- `tests/adapter_demo.rs` - Integration tests that double as examples
159+
- `tests/mobile_integration.rs` - Comprehensive mobile feature tests
160+
- Platform examples:
161+
- `platforms/android/example/MainActivity.kt`
162+
- `platforms/ios/example/BasicExample.swift`

examples/basic_handshake.rs

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
//! Basic IK Handshake Example
2+
//!
3+
//! This example demonstrates a complete IK pattern handshake between
4+
//! a client and server, followed by encrypted message exchange.
5+
//!
6+
//! ## Running
7+
//!
8+
//! ```bash
9+
//! cargo run --example basic_handshake
10+
//! ```
11+
//!
12+
//! ## Overview
13+
//!
14+
//! The IK pattern is used when the client knows the server's static
15+
//! public key in advance. This is the most common pattern for
16+
//! connecting to a known server.
17+
//!
18+
//! ## 3-Step Handshake Flow
19+
//!
20+
//! 1. Client: Create first message with encrypted identity
21+
//! 2. Server: Process and create response
22+
//! 3. Client: Process response, both now have transport keys
23+
24+
use pubky_noise::datalink_adapter::{
25+
client_complete_ik, client_start_ik_direct, server_accept_ik, server_complete_ik,
26+
};
27+
use pubky_noise::{DummyRing, NoiseClient, NoiseServer, RingKeyProvider};
28+
use std::sync::Arc;
29+
30+
fn main() {
31+
println!("=== PubkyNoise Basic Handshake Example ===\n");
32+
33+
// =========================================================================
34+
// Setup
35+
// =========================================================================
36+
37+
println!("1. Setting up client and server...");
38+
39+
// Create key providers with unique seeds
40+
// In production, use secure random seeds from key storage
41+
let client_seed = [1u8; 32];
42+
let server_seed = [2u8; 32];
43+
44+
let ring_client = Arc::new(DummyRing::new(client_seed, "client-key-id"));
45+
let ring_server = Arc::new(DummyRing::new(server_seed, "server-key-id"));
46+
47+
// Create client and server instances
48+
let client = NoiseClient::<_, ()>::new_direct("client-key-id", b"client-device", ring_client);
49+
let server =
50+
NoiseServer::<_, ()>::new_direct("server-key-id", b"server-device", ring_server.clone());
51+
52+
// Get server's static public key
53+
// In production, this would be distributed securely
54+
let server_sk = ring_server
55+
.derive_device_x25519("server-key-id", b"server-device", 0)
56+
.expect("Failed to derive server key");
57+
let server_static_pk = pubky_noise::kdf::x25519_pk_from_sk(&server_sk);
58+
59+
println!(" Client and server initialized");
60+
println!(
61+
" Server public key: {}...",
62+
hex::encode(&server_static_pk[..8])
63+
);
64+
65+
// =========================================================================
66+
// 3-Step Handshake
67+
// =========================================================================
68+
69+
println!("\n2. Performing 3-step handshake...");
70+
71+
// Step 1: Client initiates
72+
println!(" Step 1: Client creates first message");
73+
let (client_hs, first_msg) = client_start_ik_direct(&client, &server_static_pk, None)
74+
.expect("Client initiation failed");
75+
println!(" First message: {} bytes", first_msg.len());
76+
77+
// Step 2: Server processes and responds
78+
println!(" Step 2: Server processes and responds");
79+
let (server_hs, client_identity, response) =
80+
server_accept_ik(&server, &first_msg).expect("Server accept failed");
81+
println!(
82+
" Client identity: {:?}",
83+
hex::encode(&client_identity.ed25519_pub[..8])
84+
);
85+
println!(" Response: {} bytes", response.len());
86+
87+
// Step 3: Both complete handshake
88+
println!(" Step 3: Both complete handshake");
89+
let mut client_link =
90+
client_complete_ik(client_hs, &response).expect("Client completion failed");
91+
let mut server_link = server_complete_ik(server_hs).expect("Server completion failed");
92+
93+
// Verify session IDs match
94+
assert_eq!(client_link.session_id(), server_link.session_id());
95+
println!(
96+
" Session established: {}",
97+
client_link.session_id()
98+
);
99+
100+
// =========================================================================
101+
// Encrypted Communication
102+
// =========================================================================
103+
104+
println!("\n3. Testing encrypted communication...");
105+
106+
// Client sends message to server
107+
let client_message = b"Hello, server! This is encrypted.";
108+
let ciphertext = client_link
109+
.encrypt(client_message)
110+
.expect("Encryption failed");
111+
println!(
112+
" Client encrypted: {} bytes -> {} bytes",
113+
client_message.len(),
114+
ciphertext.len()
115+
);
116+
117+
// Server decrypts
118+
let decrypted = server_link.decrypt(&ciphertext).expect("Decryption failed");
119+
assert_eq!(client_message.to_vec(), decrypted);
120+
println!(" Server decrypted: {:?}", String::from_utf8_lossy(&decrypted));
121+
122+
// Server sends response
123+
let server_response = b"Hello, client! Message received.";
124+
let response_ct = server_link
125+
.encrypt(server_response)
126+
.expect("Encryption failed");
127+
let response_pt = client_link
128+
.decrypt(&response_ct)
129+
.expect("Decryption failed");
130+
assert_eq!(server_response.to_vec(), response_pt);
131+
println!(" Client received: {:?}", String::from_utf8_lossy(&response_pt));
132+
133+
// =========================================================================
134+
// Summary
135+
// =========================================================================
136+
137+
println!("\n=== Handshake and communication successful! ===");
138+
println!("\nKey points:");
139+
println!("- IK pattern requires knowing server's public key upfront");
140+
println!("- 3-step handshake: initiate -> accept -> complete");
141+
println!("- After handshake, both parties can encrypt/decrypt");
142+
println!("- Session ID is derived from handshake hash (unique per session)");
143+
}

0 commit comments

Comments
 (0)