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