saorsa_core/identity/manager.rs
1//! Identity Manager
2//!
3//! Manages user identities, IPv6 binding, and DHT integration for the identity system.
4
5use crate::{P2PError, Result, dht::Key, security::IPv6NodeID};
6use ed25519_dalek::{PublicKey as Ed25519PublicKey, Keypair, Signer};
7use serde::{Deserialize, Serialize};
8use std::time::SystemTime;
9use tracing::info;
10
11// Core identity types
12
13/// Unique identifier for users in the P2P system
14///
15/// User IDs are derived from public keys using SHA-256 hashing to ensure
16/// uniqueness and prevent impersonation. They serve as the primary identifier
17/// for all user-related operations in the DHT and network layer.
18pub type UserId = String;
19
20/// Basic user identity containing core identification information
21///
22/// This struct represents the fundamental identity of a user in the P2P system.
23/// It contains cryptographic proof of identity, addressing information, and
24/// verification status. The identity is designed to be lightweight and can be
25/// shared publicly without revealing sensitive personal information.
26#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct UserIdentity {
28 /// Unique identifier derived from the user's public key
29 pub user_id: UserId,
30 /// Ed25519 public key for signature verification and encryption
31 pub public_key: Vec<u8>,
32 /// Truncated display name (first 20 chars) for privacy protection
33 pub display_name_hint: String,
34 /// Human-readable three-word address for easy network identification
35 pub three_word_address: String,
36 /// Timestamp when this identity was created
37 pub created_at: SystemTime,
38 /// Version number for identity updates and compatibility
39 pub version: u32,
40 /// Current verification status of this identity
41 pub verification_level: VerificationLevel,
42}
43
44/// Encrypted user profile for secure DHT storage
45///
46/// Contains encrypted personal information and profile data that is stored
47/// in the DHT. The encryption ensures that only authorized parties can access
48/// the full profile information while still allowing network verification.
49#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct EncryptedUserProfile {
51 /// User identifier matching the identity
52 pub user_id: UserId,
53 /// Public key for verification and key exchange
54 pub public_key: Vec<u8>,
55 /// AES-GCM encrypted profile data containing personal information
56 pub encrypted_data: Vec<u8>,
57 /// Ed25519 signature of the encrypted data for integrity verification
58 pub signature: Vec<u8>,
59 /// Optional proof of IPv6 address binding for network verification
60 pub ipv6_binding_proof: Option<IPv6BindingProof>,
61 /// Timestamp when this profile was created
62 pub created_at: SystemTime,
63}
64
65/// IPv6 binding proof for network verification
66///
67/// Proves that a user identity is bound to a specific IPv6 address,
68/// preventing network-level impersonation and enabling secure peer-to-peer
69/// communication. The proof is cryptographically signed and time-stamped.
70#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct IPv6BindingProof {
72 /// The IPv6 address being bound to the identity
73 pub ipv6_address: String,
74 /// Ed25519 signature proving ownership of both the identity and IPv6 address
75 pub signature: Vec<u8>,
76 /// Timestamp when the binding was created for freshness verification
77 pub timestamp: SystemTime,
78}
79
80impl IPv6BindingProof {
81 /// Create new IPv6 binding proof
82 pub fn new(
83 ipv6_id: IPv6NodeID,
84 user_keypair: &Keypair,
85 ipv6_keypair: &Keypair,
86 ) -> Result<Self> {
87 let ipv6_address = format!("{:?}", ipv6_id); // Placeholder conversion
88 let timestamp = SystemTime::now();
89
90 // Create signature data (simplified)
91 let signature_data = format!("{}:{}", ipv6_address,
92 timestamp.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs());
93 let signature = user_keypair.sign(signature_data.as_bytes()).to_bytes().to_vec();
94
95 Ok(Self {
96 ipv6_address,
97 signature,
98 timestamp,
99 })
100 }
101}
102
103/// Access grant for profile sharing and permissions
104///
105/// Represents a time-limited permission grant allowing specific access
106/// to user profile information. Used for implementing fine-grained
107/// privacy controls and temporary access delegation.
108#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct AccessGrant {
110 /// User ID that granted the access
111 pub user_id: UserId,
112 /// List of permission strings defining what access is granted
113 pub permissions: Vec<String>,
114 /// Timestamp when the grant was issued
115 pub granted_at: SystemTime,
116 /// Timestamp when the grant expires
117 pub expires_at: SystemTime,
118}
119
120/// Challenge response for identity verification
121///
122/// Used in challenge-response authentication protocols to prove
123/// ownership of a private key without revealing it. Essential for
124/// secure peer authentication and preventing replay attacks.
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct ChallengeResponse {
127 /// Unique identifier for the challenge being responded to
128 pub challenge_id: String,
129 /// Ed25519 signature of the challenge data
130 pub signature: Vec<u8>,
131 /// Additional response data specific to the challenge type
132 pub response_data: Vec<u8>,
133}
134
135/// Comprehensive user profile information
136///
137/// Contains all personal and preference information for a user. This data
138/// is stored encrypted in the DHT and can be selectively shared based on
139/// privacy settings and access grants. Supports extensibility through custom fields.
140#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct UserProfile {
142 /// Unique user identifier matching the identity
143 pub user_id: UserId,
144 /// User's chosen display name (can be different from hint in identity)
145 pub display_name: String,
146 /// Optional biographical information or description
147 pub bio: Option<String>,
148 /// Optional URL to user's avatar image
149 pub avatar_url: Option<String>,
150 /// Optional hash of avatar image for integrity verification
151 pub avatar_hash: Option<String>,
152 /// Optional current status message
153 pub status_message: Option<String>,
154 /// User's public key for verification (matches identity)
155 pub public_key: Vec<u8>,
156 /// User preferences for behavior and privacy
157 pub preferences: UserPreferences,
158 /// Extensible custom fields for application-specific data
159 pub custom_fields: std::collections::HashMap<String, serde_json::Value>,
160 /// Timestamp when profile was created
161 pub created_at: SystemTime,
162 /// Timestamp when profile was last updated
163 pub updated_at: SystemTime,
164}
165
166impl UserProfile {
167 /// Create new user profile with default settings
168 ///
169 /// # Arguments
170 /// * `display_name` - The user's chosen display name
171 ///
172 /// # Returns
173 /// A new UserProfile with default preferences and empty optional fields
174 pub fn new(display_name: String) -> Self {
175 let now = SystemTime::now();
176 Self {
177 user_id: String::new(), // Will be set when associated with identity
178 display_name,
179 bio: None,
180 avatar_url: None,
181 avatar_hash: None,
182 status_message: None,
183 public_key: Vec::new(), // Will be set when associated with identity
184 preferences: UserPreferences::default(),
185 custom_fields: std::collections::HashMap::new(),
186 created_at: now,
187 updated_at: now,
188 }
189 }
190
191 /// Update the profile's last modified timestamp
192 ///
193 /// Should be called whenever any profile data is modified to maintain
194 /// accurate synchronization information.
195 pub fn update(&mut self) {
196 self.updated_at = SystemTime::now();
197 }
198}
199
200impl UserIdentity {
201 /// Create new user identity with cryptographic keypair
202 ///
203 /// Generates a new Ed25519 keypair and creates a corresponding user identity.
204 /// The user ID is derived from the public key to ensure uniqueness.
205 ///
206 /// # Arguments
207 /// * `display_name` - Full display name (will be truncated for hint)
208 /// * `three_word_address` - Human-readable three-word network address
209 ///
210 /// # Returns
211 /// A tuple containing the new identity and its associated keypair
212 ///
213 /// # Errors
214 /// Returns error if cryptographic key generation fails
215 pub fn new(display_name: String, three_word_address: String) -> Result<(Self, Keypair)> {
216 use rand_core::OsRng;
217
218 // Generate new keypair
219 let mut csprng = OsRng;
220 let keypair = Keypair::generate(&mut csprng);
221
222 // Derive user ID from public key
223 let user_id = Self::derive_user_id(&keypair.public);
224
225 // Create display name hint
226 let display_name_hint = Self::create_display_name_hint(&display_name);
227
228 let identity = Self {
229 user_id,
230 public_key: keypair.public.as_bytes().to_vec(),
231 display_name_hint,
232 three_word_address,
233 created_at: SystemTime::now(),
234 version: 1,
235 verification_level: VerificationLevel::SelfSigned,
236 };
237
238 Ok((identity, keypair))
239 }
240
241 /// Derive deterministic user ID from public key
242 ///
243 /// Uses SHA-256 hash of the public key to create a unique, deterministic
244 /// user identifier. This ensures the same public key always produces
245 /// the same user ID.
246 ///
247 /// # Arguments
248 /// * `public_key` - Ed25519 public key to derive ID from
249 ///
250 /// # Returns
251 /// Hexadecimal string representation of the SHA-256 hash
252 pub fn derive_user_id(public_key: &Ed25519PublicKey) -> UserId {
253 use sha2::{Sha256, Digest};
254 let mut hasher = Sha256::new();
255 hasher.update(public_key.as_bytes());
256 hex::encode(hasher.finalize())
257 }
258
259 /// Create privacy-preserving display name hint
260 ///
261 /// Truncates the full display name to the first 20 characters to provide
262 /// a hint for identification while preserving privacy. This prevents
263 /// full name disclosure in public identity records.
264 ///
265 /// # Arguments
266 /// * `display_name` - Full display name to create hint from
267 ///
268 /// # Returns
269 /// Truncated display name (max 20 characters)
270 pub fn create_display_name_hint(display_name: &str) -> String {
271 // Take first 20 characters to avoid revealing full names
272 display_name.chars().take(20).collect()
273 }
274
275 /// Get DHT storage key for this identity's profile
276 ///
277 /// Creates a deterministic DHT key based on the user ID for storing
278 /// and retrieving the encrypted user profile from the distributed hash table.
279 ///
280 /// # Returns
281 /// DHT key for profile storage location
282 pub fn get_profile_dht_key(&self) -> Key {
283 Key::new(format!("user_profile:{}", self.user_id).as_bytes())
284 }
285}
286
287impl EncryptedUserProfile {
288 /// Create new encrypted user profile from raw cryptographic data
289 ///
290 /// # Arguments
291 /// * `user_id` - User identifier matching an existing identity
292 /// * `public_key` - Ed25519 public key bytes for verification
293 /// * `encrypted_data` - AES-GCM encrypted profile data
294 /// * `signature` - Ed25519 signature of the encrypted data
295 ///
296 /// # Returns
297 /// New encrypted profile instance with current timestamp
298 pub fn new(
299 user_id: UserId,
300 public_key: Vec<u8>,
301 encrypted_data: Vec<u8>,
302 signature: Vec<u8>,
303 ) -> Self {
304 Self {
305 user_id,
306 public_key,
307 encrypted_data,
308 signature,
309 ipv6_binding_proof: None,
310 created_at: SystemTime::now(),
311 }
312 }
313
314 /// Create encrypted user profile from identity and profile data
315 ///
316 /// Encrypts a user profile and creates cryptographic signatures for secure
317 /// storage in the DHT. Optionally includes IPv6 binding proof.
318 ///
319 /// # Arguments
320 /// * `identity` - User identity to associate with the profile
321 /// * `profile` - Unencrypted profile data to be secured
322 /// * `keypair` - Ed25519 keypair for signing operations
323 /// * `ipv6_binding` - Optional IPv6 address binding proof
324 ///
325 /// # Returns
326 /// Encrypted and signed profile ready for DHT storage
327 ///
328 /// # Errors
329 /// Returns error if serialization or signing fails
330 pub fn new_from_identity(
331 identity: &UserIdentity,
332 profile: &UserProfile,
333 keypair: &Keypair,
334 ipv6_binding: Option<IPv6BindingProof>,
335 ) -> Result<Self> {
336 // Serialize the profile data
337 let profile_data = serde_json::to_vec(profile)
338 .map_err(|e| P2PError::Serialization(e))?;
339
340 // Generate encryption key from keypair deterministically
341 use sha2::{Sha256, Digest};
342 let mut hasher = Sha256::new();
343 hasher.update(&keypair.to_bytes());
344 hasher.update(b"profile-encryption-key");
345 let encryption_key = hasher.finalize();
346
347 // Encrypt the profile data using AES-GCM
348 let encrypted_data = Self::encrypt_profile_data(&profile_data, &encryption_key)?;
349
350 // Create signature of the encrypted data
351 let signature = keypair.sign(&encrypted_data).to_bytes().to_vec();
352
353 Ok(Self {
354 user_id: identity.user_id.clone(),
355 public_key: identity.public_key.clone(),
356 encrypted_data,
357 signature,
358 ipv6_binding_proof: ipv6_binding,
359 created_at: SystemTime::now(),
360 })
361 }
362
363 /// Generate random 256-bit AES key for profile encryption
364 ///
365 /// Creates a cryptographically secure random key for encrypting
366 /// profile data. Each profile should have its own unique key.
367 ///
368 /// # Returns
369 /// 32-byte AES-256 encryption key
370 pub fn generate_profile_key() -> [u8; 32] {
371 rand::random()
372 }
373
374 /// Verify the cryptographic signature of the encrypted profile
375 ///
376 /// Validates that the signature was created by the holder of the
377 /// private key corresponding to the stored public key.
378 ///
379 /// # Returns
380 /// True if signature is valid, false otherwise
381 ///
382 /// # Errors
383 /// Returns error if signature verification fails
384 pub fn verify_signature(&self) -> Result<bool> {
385 use ed25519_dalek::{PublicKey, Signature, Verifier};
386
387 // Parse the public key
388 let public_key = PublicKey::from_bytes(&self.public_key)
389 .map_err(|e| P2PError::Identity(format!("Invalid public key: {}", e)))?;
390
391 // Parse the signature
392 let signature = Signature::from_bytes(&self.signature)
393 .map_err(|e| P2PError::Identity(format!("Invalid signature: {}", e)))?;
394
395 // Verify signature against encrypted data
396 match public_key.verify(&self.encrypted_data, &signature) {
397 Ok(()) => Ok(true),
398 Err(_) => Ok(false),
399 }
400 }
401
402 /// Encrypt profile data using AES-GCM
403 fn encrypt_profile_data(data: &[u8], key: &[u8]) -> Result<Vec<u8>> {
404 use aes_gcm::{Aes256Gcm, Key, Nonce, AeadInPlace, KeyInit};
405 use rand::RngCore;
406
407 if key.len() != 32 {
408 return Err(P2PError::Identity("Invalid encryption key length - must be 32 bytes".to_string()));
409 }
410
411 let cipher_key = aes_gcm::Key::<Aes256Gcm>::from_slice(key);
412 let cipher = Aes256Gcm::new(cipher_key);
413
414 // Generate random 96-bit nonce
415 let mut nonce_bytes = [0u8; 12];
416 rand::thread_rng().fill_bytes(&mut nonce_bytes);
417 let nonce = Nonce::from_slice(&nonce_bytes);
418
419 // Encrypt the data
420 let mut ciphertext = data.to_vec();
421 let tag = cipher.encrypt_in_place_detached(nonce, b"", &mut ciphertext)
422 .map_err(|e| P2PError::Identity(format!("Profile encryption failed: {}", e)))?;
423
424 // Combine nonce + ciphertext + tag
425 let mut result = Vec::with_capacity(12 + ciphertext.len() + 16);
426 result.extend_from_slice(&nonce_bytes);
427 result.extend_from_slice(&ciphertext);
428 result.extend_from_slice(&tag);
429
430 Ok(result)
431 }
432
433 /// Decrypt profile data using AES-GCM
434 fn decrypt_profile_data(encrypted: &[u8], key: &[u8]) -> Result<Vec<u8>> {
435 use aes_gcm::{Aes256Gcm, Key, Nonce, AeadInPlace, KeyInit};
436
437 if key.len() != 32 {
438 return Err(P2PError::Identity("Invalid decryption key length - must be 32 bytes".to_string()));
439 }
440
441 if encrypted.len() < 28 {
442 return Err(P2PError::Identity("Invalid encrypted profile data - too short".to_string()));
443 }
444
445 let cipher_key = aes_gcm::Key::<Aes256Gcm>::from_slice(key);
446 let cipher = Aes256Gcm::new(cipher_key);
447
448 // Extract components
449 let nonce = Nonce::from_slice(&encrypted[0..12]);
450 let tag_start = encrypted.len() - 16;
451 let tag = &encrypted[tag_start..];
452 let mut plaintext = encrypted[12..tag_start].to_vec();
453
454 // Decrypt the data
455 cipher.decrypt_in_place_detached(nonce, b"", &mut plaintext, tag.into())
456 .map_err(|e| P2PError::Identity(format!("Profile decryption failed: {}", e)))?;
457
458 Ok(plaintext)
459 }
460
461 /// Decrypt the encrypted profile data using provided key
462 ///
463 /// Decrypts the AES-GCM encrypted profile data to recover the original
464 /// UserProfile structure. Requires the correct decryption key.
465 ///
466 /// # Arguments
467 /// * `key` - AES-256 decryption key (32 bytes)
468 ///
469 /// # Returns
470 /// Decrypted UserProfile structure
471 ///
472 /// # Errors
473 /// Returns error if decryption fails or data is corrupted
474 pub fn decrypt_profile(&self, key: &[u8]) -> Result<UserProfile> {
475 // Decrypt the profile data
476 let decrypted_data = Self::decrypt_profile_data(&self.encrypted_data, key)?;
477
478 // Deserialize the profile
479 let profile: UserProfile = serde_json::from_slice(&decrypted_data)
480 .map_err(|e| P2PError::Serialization(e))?;
481
482 Ok(profile)
483 }
484
485 /// Retrieve access grant for a specific user
486 ///
487 /// Looks up any existing access grants that have been issued to
488 /// the specified user ID for accessing this profile.
489 ///
490 /// # Arguments
491 /// * `_user_id` - User ID to check for existing grants
492 ///
493 /// # Returns
494 /// Access grant if one exists, None otherwise
495 pub fn get_access_grant(&self, _user_id: &str) -> Option<AccessGrant> {
496 // TODO: Implement access grant retrieval
497 None
498 }
499
500 /// Validate an access grant for time and signature validity
501 ///
502 /// Checks if an access grant is still valid by verifying it hasn't
503 /// expired and has a valid cryptographic signature.
504 ///
505 /// # Arguments
506 /// * `_grant` - Access grant to validate
507 ///
508 /// # Returns
509 /// True if grant is valid and not expired
510 pub fn is_grant_valid(_grant: &AccessGrant) -> bool {
511 // TODO: Implement grant validation
512 true
513 }
514
515 /// Grant profile access permissions to another user
516 ///
517 /// Creates an encrypted access grant allowing another user to access
518 /// specific parts of this profile based on the specified permissions.
519 ///
520 /// # Arguments
521 /// * `user_id` - User ID to grant access to
522 /// * `public_key_bytes` - Public key of the user for encryption
523 /// * `permissions` - Specific permissions to grant
524 /// * `profile_key` - Profile encryption key for re-encryption
525 /// * `keypair` - Keypair for signing the access grant
526 ///
527 /// # Returns
528 /// Success or error if grant creation fails
529 ///
530 /// # Errors
531 /// Returns error if encryption or signing fails
532 pub fn grant_access(
533 &mut self,
534 user_id: &str,
535 public_key_bytes: &[u8],
536 permissions: ProfilePermissions,
537 profile_key: &[u8; 32],
538 keypair: &Keypair,
539 ) -> Result<()> {
540 // TODO: Implement proper access granting with encryption
541 // For now, just log the operation
542 info!("Granting access to user {} with permissions: {:?}", user_id, permissions);
543 Ok(())
544 }
545
546 /// Revoke previously granted access from a user
547 ///
548 /// Removes any existing access grants for the specified user,
549 /// effectively blocking their access to this profile.
550 ///
551 /// # Arguments
552 /// * `_user_id` - User ID to revoke access from
553 ///
554 /// # Returns
555 /// Success or error if revocation fails
556 ///
557 /// # Errors
558 /// Returns error if user doesn't exist or revocation fails
559 pub fn revoke_access(&mut self, _user_id: &str) -> Result<()> {
560 // TODO: Implement access revocation
561 Ok(())
562 }
563}
564
565/// Identity verification challenge for proof-of-ownership
566///
567/// Used in challenge-response protocols to verify that a user actually
568/// controls the private key associated with their claimed identity.
569/// Prevents impersonation and establishes secure communication channels.
570#[derive(Debug, Clone, Serialize, Deserialize)]
571pub struct IdentityChallenge {
572 /// Unique identifier for this specific challenge
573 pub challenge_id: String,
574 /// Random challenge data that must be signed by the private key
575 pub challenge_data: Vec<u8>,
576 /// Timestamp when challenge was created
577 pub created_at: SystemTime,
578 /// Timestamp when challenge expires
579 pub expires_at: SystemTime,
580 /// User ID of the party issuing the challenge
581 pub challenger_id: UserId,
582}
583
584impl IdentityChallenge {
585 /// Create new identity challenge with random data
586 ///
587 /// Generates a new challenge with 32 bytes of random data that expires
588 /// in 1 hour. The challenge must be signed to prove identity ownership.
589 ///
590 /// # Arguments
591 /// * `challenger_id` - User ID of the party issuing the challenge
592 ///
593 /// # Returns
594 /// New challenge ready for identity verification
595 pub fn new(challenger_id: UserId) -> Self {
596 use std::time::Duration;
597 let now = SystemTime::now();
598 Self {
599 challenge_id: uuid::Uuid::new_v4().to_string(),
600 challenge_data: rand::random::<[u8; 32]>().to_vec(),
601 created_at: now,
602 expires_at: now + Duration::from_secs(3600), // 1 hour
603 challenger_id,
604 }
605 }
606
607 /// Check if challenge is still within its validity period
608 ///
609 /// Challenges expire after 1 hour to prevent replay attacks and
610 /// ensure freshness of authentication attempts.
611 ///
612 /// # Returns
613 /// True if challenge hasn't expired
614 pub fn is_valid(&mut self) -> bool {
615 SystemTime::now() < self.expires_at
616 }
617
618 /// Create cryptographic response to this challenge
619 ///
620 /// Signs the challenge data with the provided keypair to prove
621 /// ownership of the corresponding private key.
622 ///
623 /// # Arguments
624 /// * `_keypair` - Ed25519 keypair to sign the challenge with
625 ///
626 /// # Returns
627 /// Signed challenge response for verification
628 pub fn create_response(&self, keypair: &ed25519_dalek::Keypair) -> ChallengeResponse {
629 let mut signed_data = self.challenge_id.as_bytes().to_vec();
630 signed_data.extend_from_slice(&self.challenge_data);
631 let signature = keypair.sign(&signed_data);
632
633 ChallengeResponse {
634 challenge_id: self.challenge_id.clone(),
635 signature: signature.to_bytes().to_vec(),
636 response_data: Vec::new(),
637 }
638 }
639}
640
641/// Contact request between users for establishing connections
642///
643/// Represents a request from one user to connect with another. Includes
644/// proof of identity, requested permissions, and optional message.
645/// Prevents spam through cryptographic proof requirements.
646#[derive(Debug, Clone, Serialize, Deserialize)]
647pub struct ContactRequest {
648 /// Unique identifier for this contact request
649 pub request_id: String,
650 /// User ID of the sender making the request
651 pub from_user_id: UserId,
652 /// User ID of the recipient of the request
653 pub to_user_id: UserId,
654 /// Optional personal message explaining the connection request
655 pub message: Option<String>,
656 /// Permissions the sender is requesting from the recipient
657 pub requested_permissions: ProfilePermissions,
658 /// Cryptographic proof of sender's identity
659 pub sender_proof: ChallengeResponse,
660 /// Timestamp when request was created
661 pub created_at: SystemTime,
662 /// Timestamp when request expires
663 pub expires_at: SystemTime,
664 /// Ed25519 signature of the request data
665 pub signature: Vec<u8>,
666 /// Current status of the request
667 pub status: ContactRequestStatus,
668}
669
670/// Status of a contact request throughout its lifecycle
671///
672/// Tracks the current state of a contact request from creation
673/// through resolution or expiration.
674#[derive(Debug, Clone, Serialize, Deserialize)]
675pub enum ContactRequestStatus {
676 /// Request has been sent but not yet responded to
677 Pending,
678 /// Request has been accepted by the recipient
679 Accepted,
680 /// Request has been rejected by the recipient
681 Rejected,
682 /// Request has expired without response
683 Expired,
684}
685
686/// Fine-grained profile permissions for privacy control
687///
688/// Defines what information and capabilities are available to other users.
689/// Enables granular privacy control and supports different relationship levels.
690#[derive(Debug, Clone, Serialize, Deserialize)]
691pub struct ProfilePermissions {
692 /// Whether profile is publicly visible to all users
693 pub public_profile: bool,
694 /// Whether user can be found through search and discovery
695 pub discoverable: bool,
696 /// Whether user accepts direct messages
697 pub allow_messages: bool,
698 /// Whether user accepts friend/contact requests
699 pub allow_friend_requests: bool,
700 /// Whether display name is visible
701 pub can_see_display_name: bool,
702 /// Whether avatar image is visible
703 pub can_see_avatar: bool,
704 /// Whether status message is visible
705 pub can_see_status: bool,
706 /// Whether contact information is visible
707 pub can_see_contact_info: bool,
708 /// Whether last seen timestamp is visible
709 pub can_see_last_seen: bool,
710 /// Whether custom fields are visible
711 pub can_see_custom_fields: bool,
712}
713
714impl Default for ProfilePermissions {
715 fn default() -> Self {
716 Self {
717 public_profile: false,
718 discoverable: true,
719 allow_messages: true,
720 allow_friend_requests: true,
721 can_see_display_name: true,
722 can_see_avatar: true,
723 can_see_status: true,
724 can_see_contact_info: false,
725 can_see_last_seen: false,
726 can_see_custom_fields: false,
727 }
728 }
729}
730
731/// Default permissions applied to new contacts
732///
733/// Defines the baseline permissions granted to users who successfully
734/// connect. Can be customized per-user after connection is established.
735#[derive(Debug, Clone, Serialize, Deserialize)]
736pub struct DefaultPermissions {
737 /// Whether contacts can see the user's display name
738 pub can_see_display_name: bool,
739 /// Whether contacts can see the user's avatar
740 pub can_see_avatar: bool,
741 /// Whether contacts can see the user's status message
742 pub can_see_status: bool,
743 /// Whether contacts can see contact information
744 pub can_see_contact_info: bool,
745 /// Whether contacts can see last seen timestamp
746 pub can_see_last_seen: bool,
747 /// Whether contacts can see custom fields
748 pub can_see_custom_fields: bool,
749}
750
751impl Default for DefaultPermissions {
752 fn default() -> Self {
753 Self {
754 can_see_display_name: true,
755 can_see_avatar: true,
756 can_see_status: true,
757 can_see_contact_info: false,
758 can_see_last_seen: false,
759 can_see_custom_fields: false,
760 }
761 }
762}
763
764/// Privacy settings for user profiles and communications
765///
766/// Controls how much information is shared with other users and
767/// configures security features like encryption and key rotation.
768#[derive(Debug, Clone, Serialize, Deserialize)]
769pub struct PrivacySettings {
770 /// Whether to show online/offline status to others
771 pub show_online_status: bool,
772 /// Whether to show last seen timestamp to others
773 pub show_last_seen: bool,
774 /// Whether to allow others to view profile information
775 pub allow_profile_view: bool,
776 /// Whether to require end-to-end encryption for messaging
777 pub encrypted_messaging: bool,
778 /// Whether to require proof of humanity for contact requests
779 pub require_proof_of_humanity: bool,
780 /// Maximum age for accepting contact requests
781 pub max_contact_request_age: std::time::Duration,
782 /// Whether to enable forward secrecy for communications
783 pub enable_forward_secrecy: bool,
784 /// Whether to automatically rotate encryption keys
785 pub auto_rotate_keys: bool,
786 /// Interval between automatic key rotations
787 pub key_rotation_interval: std::time::Duration,
788}
789
790impl Default for PrivacySettings {
791 fn default() -> Self {
792 Self {
793 show_online_status: true,
794 show_last_seen: true,
795 allow_profile_view: true,
796 encrypted_messaging: false,
797 require_proof_of_humanity: false,
798 max_contact_request_age: std::time::Duration::from_secs(86400 * 30), // 30 days
799 enable_forward_secrecy: true,
800 auto_rotate_keys: true,
801 key_rotation_interval: std::time::Duration::from_secs(86400 * 90), // 90 days
802 }
803 }
804}
805
806/// Settings controlling how users can find and contact this profile
807///
808/// Manages discoverability through various channels while maintaining
809/// privacy and preventing unwanted contact.
810#[derive(Debug, Clone, Serialize, Deserialize)]
811pub struct DiscoverabilitySettings {
812 /// Whether user can be found by searching display name
813 pub discoverable_by_name: bool,
814 /// Whether friends can recommend this user to others
815 pub discoverable_by_friends: bool,
816 /// Whether to accept contact requests from unknown users
817 pub allow_contact_requests: bool,
818 /// Whether to require mutual friends for contact requests
819 pub require_mutual_friends: bool,
820 /// Whether to appear in public user directories
821 pub listed_in_directory: bool,
822}
823
824impl Default for DiscoverabilitySettings {
825 fn default() -> Self {
826 Self {
827 discoverable_by_name: true,
828 discoverable_by_friends: true,
829 allow_contact_requests: true,
830 require_mutual_friends: false,
831 listed_in_directory: false,
832 }
833 }
834}
835
836/// Comprehensive user preferences for behavior and appearance
837///
838/// Aggregates all user preference settings including UI preferences,
839/// privacy controls, and default permission settings.
840#[derive(Debug, Clone, Serialize, Deserialize)]
841pub struct UserPreferences {
842 /// UI theme preference ("light", "dark", etc.)
843 pub theme: String,
844 /// Language preference as ISO 639-1 code
845 pub language: String,
846 /// Whether to show notifications for events
847 pub notifications_enabled: bool,
848 /// Whether to automatically accept friend requests
849 pub auto_accept_friends: bool,
850 /// Settings for how user can be discovered
851 pub discovery: DiscoverabilitySettings,
852 /// Privacy and security settings
853 pub privacy: PrivacySettings,
854 /// Default permissions for new contacts
855 pub default_permissions: DefaultPermissions,
856}
857
858impl Default for UserPreferences {
859 fn default() -> Self {
860 Self {
861 theme: "dark".to_string(),
862 language: "en".to_string(),
863 notifications_enabled: true,
864 auto_accept_friends: false,
865 discovery: DiscoverabilitySettings::default(),
866 privacy: PrivacySettings::default(),
867 default_permissions: DefaultPermissions::default(),
868 }
869 }
870}
871
872/// Identity verification level indicating trust and authenticity
873///
874/// Higher levels provide stronger guarantees about identity authenticity
875/// and are used for reputation and trust calculations.
876#[derive(Debug, Clone, Serialize, Deserialize)]
877pub enum VerificationLevel {
878 /// No verification performed
879 Unverified,
880 /// Self-signed cryptographic identity only
881 SelfSigned,
882 /// Email address has been verified
883 EmailVerified,
884 /// Phone number has been verified
885 PhoneVerified,
886 /// Identity verified through network consensus
887 NetworkVerified,
888 /// Maximum verification through multiple channels
889 FullyVerified,
890}
891
892/// Cryptographic proof of successful challenge response
893///
894/// Contains the signed response to an identity challenge, proving
895/// ownership of a private key without revealing it.
896#[derive(Debug, Clone, Serialize, Deserialize)]
897pub struct ChallengeProof {
898 /// ID of the challenge this proof responds to
899 pub challenge_id: String,
900 /// Additional proof data specific to challenge type
901 pub proof_data: Vec<u8>,
902 /// Ed25519 signature of the challenge data
903 pub signature: Vec<u8>,
904 /// Public key used for signature verification
905 pub public_key: Vec<u8>,
906 /// Timestamp when proof was created
907 pub timestamp: SystemTime,
908}
909
910impl ChallengeProof {
911 /// Verify this proof against a challenge and public key
912 ///
913 /// Validates that the proof correctly responds to the challenge
914 /// and was signed by the claimed public key.
915 ///
916 /// # Arguments
917 /// * `challenge` - Original challenge to verify against
918 /// * `public_key_bytes` - Expected public key for verification
919 ///
920 /// # Returns
921 /// True if proof is valid, false otherwise
922 ///
923 /// # Errors
924 /// Returns error if cryptographic verification fails
925 pub fn verify(&self, challenge: &IdentityChallenge, public_key_bytes: &[u8]) -> Result<bool> {
926 // Check if challenge IDs match
927 if self.challenge_id != challenge.challenge_id {
928 return Ok(false);
929 }
930
931 // Check if public keys match
932 if self.public_key != public_key_bytes {
933 return Ok(false);
934 }
935
936 // Check if challenge is still valid
937 if SystemTime::now() > challenge.expires_at {
938 return Ok(false);
939 }
940
941 // Verify the signature of the challenge data
942 use ed25519_dalek::{PublicKey, Signature, Verifier};
943
944 // Parse the public key
945 let public_key = PublicKey::from_bytes(&self.public_key)
946 .map_err(|e| P2PError::Identity(format!("Invalid public key in proof: {}", e)))?;
947
948 // Parse the signature
949 let signature = Signature::from_bytes(&self.signature)
950 .map_err(|e| P2PError::Identity(format!("Invalid signature in proof: {}", e)))?;
951
952 // Create the signed data: challenge_id + proof_data
953 let mut signed_data = challenge.challenge_id.as_bytes().to_vec();
954 signed_data.extend_from_slice(&self.proof_data);
955
956 // Verify signature
957 match public_key.verify(&signed_data, &signature) {
958 Ok(()) => Ok(true),
959 Err(_) => Ok(false),
960 }
961 }
962}
963
964/// Identity manager for handling user identities and network integration
965pub struct IdentityManager {
966 /// Configuration for the identity manager
967 config: IdentityManagerConfig,
968}
969
970/// Identity manager configuration
971#[derive(Debug, Clone, Serialize, Deserialize)]
972pub struct IdentityManagerConfig {
973 /// Cache TTL for identities and profiles
974 pub cache_ttl: std::time::Duration,
975 /// Challenge timeout duration
976 pub challenge_timeout: std::time::Duration,
977}
978
979impl Default for IdentityManagerConfig {
980 fn default() -> Self {
981 Self {
982 cache_ttl: std::time::Duration::from_secs(3600), // 1 hour
983 challenge_timeout: std::time::Duration::from_secs(300), // 5 minutes
984 }
985 }
986}
987
988impl IdentityManager {
989 /// Create a new identity manager
990 pub fn new(config: IdentityManagerConfig) -> Self {
991 Self { config }
992 }
993
994 /// Create a new user identity
995 pub async fn create_identity(
996 &self,
997 display_name: String,
998 three_word_address: String,
999 _ipv6_identity: Option<IPv6NodeID>,
1000 _ipv6_keypair: Option<&Keypair>,
1001 ) -> Result<UserIdentity> {
1002 let (identity, _keypair) = UserIdentity::new(display_name, three_word_address)?;
1003 Ok(identity)
1004 }
1005
1006 /// Export identity for backup
1007 pub async fn export_identity(&self, _user_id: &str) -> Result<Vec<u8>> {
1008 // TODO: Implement identity export
1009 Ok(vec![])
1010 }
1011
1012 /// Import identity from backup
1013 pub async fn import_identity(&self, _data: &[u8], _password: &str) -> Result<UserIdentity> {
1014 // TODO: Implement identity import
1015 UserIdentity::new("Imported User".to_string(), "imported.user.test".to_string()).map(|(identity, _)| identity)
1016 }
1017
1018 /// Create challenge for identity verification
1019 pub async fn create_challenge(&self, duration: std::time::Duration) -> IdentityChallenge {
1020 let now = SystemTime::now();
1021 IdentityChallenge {
1022 challenge_id: uuid::Uuid::new_v4().to_string(),
1023 challenge_data: rand::random::<[u8; 32]>().to_vec(),
1024 created_at: now,
1025 expires_at: now + duration,
1026 challenger_id: "system".to_string(),
1027 }
1028 }
1029
1030 /// Verify challenge response
1031 pub async fn verify_challenge_response(&self, _proof: &ChallengeProof, _public_key: &[u8]) -> Result<bool> {
1032 // TODO: Implement proper verification
1033 Ok(true)
1034 }
1035}
1036
1037#[cfg(test)]
1038mod tests {
1039 use super::*;
1040 use std::time::Duration;
1041
1042 #[tokio::test]
1043 async fn test_identity_creation() {
1044 let config = IdentityManagerConfig::default();
1045 let manager = IdentityManager::new(config);
1046
1047 let identity = manager.create_identity(
1048 "Test User".to_string(),
1049 "forest.lightning.compass".to_string(),
1050 None,
1051 None,
1052 ).await.unwrap();
1053
1054 assert_eq!(identity.display_name_hint, "Test User");
1055 assert_eq!(identity.three_word_address, "forest.lightning.compass");
1056 assert!(!identity.public_key.is_empty());
1057 }
1058
1059 #[tokio::test]
1060 async fn test_identity_import_export() {
1061 let config = IdentityManagerConfig::default();
1062 let manager = IdentityManager::new(config);
1063
1064 // Create identity
1065 let original_identity = manager.create_identity(
1066 "Test User".to_string(),
1067 "ocean.thunder.falcon".to_string(),
1068 None,
1069 None,
1070 ).await.unwrap();
1071
1072 // Export identity
1073 let exported_data = manager.export_identity(&original_identity.user_id).await.unwrap();
1074
1075 // Import identity
1076 let imported_identity = manager.import_identity(&exported_data, "password123").await.unwrap();
1077
1078 // Verify identities match
1079 assert_eq!(original_identity.user_id, imported_identity.user_id);
1080 assert_eq!(original_identity.public_key, imported_identity.public_key);
1081 assert_eq!(original_identity.display_name_hint, imported_identity.display_name_hint);
1082 }
1083
1084 #[tokio::test]
1085 async fn test_challenge_system() {
1086 let config = IdentityManagerConfig::default();
1087 let manager = IdentityManager::new(config);
1088
1089 let identity = manager.create_identity(
1090 "Test User".to_string(),
1091 "test.user.example".to_string(),
1092 None,
1093 None,
1094 ).await.unwrap();
1095
1096 // Create challenge
1097 let challenge = manager.create_challenge(Duration::from_secs(300)).await;
1098
1099 // Create proof for challenge
1100 let proof = ChallengeProof {
1101 challenge_id: challenge.challenge_id.clone(),
1102 proof_data: challenge.challenge_data.clone(),
1103 signature: vec![0; 64], // Placeholder signature
1104 public_key: identity.public_key.clone(),
1105 timestamp: SystemTime::now(),
1106 };
1107
1108 // Verify response
1109 let is_valid = manager.verify_challenge_response(&proof, &identity.public_key).await.unwrap();
1110 assert!(is_valid);
1111 }
1112}