Contact Class
Overview
The Contact
class represents external cryptographic identities in the Keychain system. Contacts are associated with personas and are used as recipients for encryption operations and as trusted signers for verification operations.
Package: keychain.identity.contact
from keychain.identity.contact import Contact
Class Definition
class Contact(KeychainObject):
"""Represents an external cryptographic identity."""
Constructor
def __init__(self, c_pointer) -> None
Initialize a Contact object with a C library pointer. Contacts are typically created through Gateway.add_contact()
or Persona.add_contact()
methods rather than direct construction.
Parameters:
-
c_pointer
- C library pointer to the contact object
Properties
Basic Properties
name
@property
def name(self) -> str
Get the primary name of the contact.
Returns: Primary name string
Status Properties
Cryptographic Properties
encryption_algorithm
@property
def encryption_algorithm(self) -> EncryptionScheme
Get the encryption algorithm used by this contact.
Returns: EncryptionScheme
enumeration value
encryption_key_size
@property
def encryption_key_size(self) -> int
Get the encryption key size in bits.
Returns: Key size in bits
signature_algorithm
@property
def signature_algorithm(self) -> SignatureScheme
Get the signature algorithm used by this contact.
Returns: SignatureScheme
enumeration value
Keychain Access Methods
keychain(keychain_type)
def keychain(self, keychain_type: KeychainType) -> Keychain
Get a specific keychain from the contact.
Parameters:
-
keychain_type
(KeychainType
) - Type of keychain (ENCRYPT or SIGN)
Returns: Keychain
object
Lifecycle Operations
Comparison Methods
eq(other)
def __eq__(self, other: object) -> bool
Test equality with another contact.
Parameters:
-
other
(Contact
) - Contact to compare with
Returns: True
if contacts are equal
Example:
# Check if two contact references are the same
if contact1 == contact2:
print("Same contact")
else:
print("Different contacts")
Example: Working with Contacts
from keychain.gateway import Gateway
from keychain.constants import SecurityLevel, KeychainType
from keychain.exceptions import KeychainNotFoundError
# Initialize gateway
settings = Gateway.init("keychain.config")
gateway = Gateway(settings)
try:
# Get or create personas
alice = gateway.find_persona("alice", "company.com")
bob = gateway.find_persona("bob", "company.com")
# Add Bob as a contact for Alice
bob_contact = gateway.add_contact(
persona=alice,
name="bob",
subname="company.com",
did=bob.did
)
print(f"Added contact: {bob_contact.name}.{bob_contact.subname}")
print(f"Contact DID: {bob_contact.did}")
# Wait for contact to become mature if needed
if not bob_contact.is_mature():
print("Waiting for contact to mature...")
bob_contact.await_maturity()
# Check contact status
print(f"Contact status:")
print(f" Is known: {bob_contact.is_known}")
print(f" Is mature: {bob_contact.is_mature}")
print(f" Is null: {bob_contact.is_null()}")
# Display cryptographic information
print(f"Cryptographic details:")
print(f" Encryption: {bob_contact.encryption_algorithm} ({bob_contact.encryption_key_size} bits)")
print(f" Signature: {bob_contact.signature_algorithm} ({bob_contact.signature_key_size} bits)")
print(f" Cipher: {bob_contact.cipher}")
# Access keychains
enc_keychain = bob_contact.encryption_keychain()
sig_keychain = bob_contact.signature_keychain()
print(f"Contact has encryption and signature keychains")
# Use contact for encryption
message = "Confidential message for Bob"
encrypted = alice.encrypt(message, [bob_contact])
print("Message encrypted for contact")
# Refresh contact information from network
bob_contact.refresh()
print("Contact information refreshed from PKI network")
# Find contact in persona's contact list
try:
found_contact = alice.find_contact("bob", "company.com")
if found_contact == bob_contact:
print("✓ Contact found in persona's contact list")
except KeychainNotFoundError:
print("✗ Contact not found in persona's contact list")
# List all contacts for Alice
print(f"\nAlice's contacts ({len(alice.contacts)}):")
for i, contact in enumerate(alice.contacts):
print(f" {i}: {contact.name}.{contact.subname}")
print(f" Known: {contact.is_known}, Mature: {contact.is_mature}")
finally:
Gateway.close()
Example: Contact Management Workflow
from keychain.gateway import Gateway
from keychain.constants import SecurityLevel
from keychain.exceptions import KeychainNotFoundError
def manage_contacts_workflow():
"""Demonstrate comprehensive contact management."""
settings = Gateway.init("keychain.config")
gateway = Gateway(settings)
try:
# Create or get main persona
try:
alice = gateway.find_persona("alice", "company.com")
except KeychainNotFoundError:
alice = gateway.create_persona(
name="alice",
subname="company.com",
security_level=SecurityLevel.HIGH,
auto_renew=True
)
alice.await_maturity()
# Create multiple contacts
contact_info = [
("bob", "company.com"),
("charlie", "partner.org"),
("diana", "client.net"),
("eve", "vendor.biz")
]
contacts = []
for name, subname in contact_info:
# Create persona for contact (in real scenario, these would be external)
try:
contact_persona = gateway.find_persona(name, subname)
except KeychainNotFoundError:
contact_persona = gateway.create_persona(
name=name,
subname=subname,
security_level=SecurityLevel.MEDIUM,
auto_renew=True
)
contact_persona.await_maturity()
# Add as contact
contact = alice.add_contact(
name=name,
subname=subname,
did=contact_persona.did
)
contacts.append(contact)
print(f"Added contact: {contact.name}.{contact.subname}")
# Wait for all contacts to mature
print("\nWaiting for contacts to mature...")
for contact in contacts:
if not contact.is_mature():
contact.await_maturity()
# Display contact information
print(f"\nContact Information:")
print(f"Alice has {len(alice.contacts)} contacts:")
for i, contact in enumerate(alice.contacts):
print(f"\n Contact {i+1}: {contact.name}.{contact.subname}")
print(f" DID: {contact.did}")
print(f" Status: Known={contact.is_known}, Mature={contact.is_mature}")
print(f" Encryption: {contact.encryption_algorithm} ({contact.encryption_key_size} bits)")
print(f" Signature: {contact.signature_algorithm} ({contact.signature_key_size} bits)")
# Test encryption to multiple contacts
print(f"\nTesting encryption to multiple contacts...")
message = "Important announcement to all team members"
encrypted = alice.encrypt(message, contacts[:3]) # Send to first 3 contacts
print(f"Message encrypted for {len(contacts[:3])} recipients")
# Test contact lookup
print(f"\nTesting contact lookup...")
try:
bob_contact = alice.find_contact("bob", "company.com")
print(f"✓ Found Bob: {bob_contact.name}.{bob_contact.subname}")
charlie_contact = alice.find_contact("charlie", "partner.org")
print(f"✓ Found Charlie: {charlie_contact.name}.{charlie_contact.subname}")
except KeychainNotFoundError as e:
print(f"✗ Contact not found: {e}")
# Test contact refresh
print(f"\nRefreshing contact information...")
for contact in alice.contacts:
contact.refresh()
print(f" Refreshed: {contact.name}.{contact.subname}")
# Test contact equality
print(f"\nTesting contact equality...")
contact1 = alice.get_contact(0)
contact2 = alice.find_contact(contact1.name, contact1.subname)
if contact1 == contact2:
print("✓ Contact equality test passed")
else:
print("✗ Contact equality test failed")
return contacts
finally:
Gateway.close()
if __name__ == "__main__":
contacts = manage_contacts_workflow()
Error Handling
Contact methods can raise various exceptions:
-
KeychainNotFoundError
- Contact not found in searches -
KeychainSecurityError
- Cryptographic operation failures -
KeychainValidationError
- Input validation errors -
IndexError
- Contact index out of range
Example:
from keychain.exceptions import KeychainNotFoundError, KeychainSecurityError
try:
# Safe contact operations
contact = persona.find_contact("unknown", "domain.com")
contact.refresh()
if contact.is_mature():
keychain = contact.encryption_keychain()
except KeychainNotFoundError:
print("Contact not found")
except KeychainSecurityError:
print("Cryptographic operation failed")
except Exception as e:
print(f"Unexpected error: {e}")
Best Practices
-
Always check maturity: Verify
is_mature()
before using contacts for cryptographic operations -
Handle contact discovery: Use try-catch blocks when finding contacts
-
Refresh when needed: Call
refresh()
to get latest PKI information -
Check status: Verify
is_known
before trusting contact for sensitive operations -
Await maturity: Use
await_maturity()
for newly added contacts
Example:
def safe_contact_usage(persona, contact_name, contact_subname):
"""Demonstrate safe contact usage patterns."""
try:
# Find contact
contact = persona.find_contact(contact_name, contact_subname)
# Check basic status
if contact.is_null():
print("Contact is null - cannot use")
return None
# Ensure contact is known
if not contact.is_known:
print("Contact is not known - refreshing...")
contact.refresh()
# Wait for maturity if needed
if not contact.is_mature():
print("Contact is not mature - waiting...")
contact.await_maturity()
# Now safe to use
print(f"Contact {contact.name}.{contact.subname} is ready for use")
return contact
except KeychainNotFoundError:
print(f"Contact {contact_name}.{contact_subname} not found")
return None
See Also
-
Persona Class - Managing contacts
-
Gateway Class - Adding contacts
-
PersonaDID Class - Contact identifiers
-
Exception Classes - Error handling