saorsa_core/identity/
manager.rs

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