### Django Translation Example Source: https://github.com/psono/psono-server/blob/master/psono/templates/email/emergency_code_armed.html Demonstrates how to use Django's translation tags within an HTML template. The `{% trans %}` tag is used to mark a string for translation, ensuring it can be localized. ```django {% load i18n %} {% trans "Emergency code armed" %} ``` -------------------------------- ### PSONO Server Configuration Example (settings.yaml) Source: https://context7.com/psono/psono-server/llms.txt This YAML file outlines the essential configuration parameters for a self-hosted PSONO server. It includes settings for security keys, database connection, email integration, and optional features like Yubikey support and Redis caching. Ensure all secret keys are generated securely and kept confidential. ```yaml # Generate keys with: ./psono/manage.py generateserverkeys SECRET_KEY: 'your_super_secret_random_key_32_chars_or_more' ACTIVATION_LINK_SECRET: 'your_activation_link_secret_32_chars_or_more' DB_SECRET: 'your_db_secret_32_chars_or_more' EMAIL_SECRET_SALT: '$2b$12$XUG.sKxC2jmkUvWQjg53.e' PRIVATE_KEY: '302650c3c82f7111c2e8ceb660d32173cdc8c3d7717f1d4f982aad5234648fcb' PUBLIC_KEY: '02da2ad857321d701d754a7e60d0a147cdbc400ff4465e1f57bc2d9fbfeddf0b' # Client URL for activation links WEB_CLIENT_URL: 'https://client.your-domain.com' # Production settings DEBUG: False ALLOWED_HOSTS: ['api.your-domain.com'] ALLOWED_DOMAINS: ['your-domain.com'] HOST_URL: 'https://api.your-domain.com' # Email configuration EMAIL_FROM: 'noreply@your-domain.com' EMAIL_HOST: 'smtp.your-domain.com' EMAIL_PORT: 587 EMAIL_USE_TLS: True EMAIL_HOST_USER: 'smtp_user' EMAIL_HOST_PASSWORD: 'smtp_password' # Optional: Yubikey OTP support YUBIKEY_CLIENT_ID: '12345' YUBIKEY_SECRET_KEY: 'your_yubico_secret_key' # PostgreSQL database DATABASES: default: ENGINE: 'django.db.backends.postgresql' NAME: 'psono' USER: 'psono_user' PASSWORD: 'db_password' HOST: 'localhost' PORT: '5432' # Optional: Redis cache CACHE_ENABLE: True CACHE_REDIS: True CACHE_REDIS_LOCATION: 'redis://localhost:6379/0' # Enable admin API MANAGEMENT_ENABLED: True ``` -------------------------------- ### Pre-Login (Get Hashing Parameters) Source: https://context7.com/psono/psono-server/llms.txt Retrieves the password hashing algorithm and parameters for a given username. This is used to prevent username enumeration by returning fake parameters for non-existent users. ```APIDOC ## POST /authentication/prelogin/ ### Description Retrieves the password hashing algorithm and parameters for a user before login. This endpoint helps prevent username enumeration by returning fake parameters for non-existent users. ### Method POST ### Endpoint /authentication/prelogin/ ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **username** (string) - Required - The username for which to retrieve hashing parameters. ### Request Example ```json { "username": "user@example.com" } ``` ### Response #### Success Response (200) - **hashing_algorithm** (string) - The hashing algorithm used (e.g., 'scrypt'). - **hashing_parameters** (object) - An object containing the parameters for the hashing algorithm (e.g., 'n', 'r', 'p' for scrypt). #### Response Example ```json { "hashing_algorithm": "scrypt", "hashing_parameters": { "n": 16384, "r": 8, "p": 1 } } ``` ``` -------------------------------- ### Get Server Info - Bash Source: https://context7.com/psono/psono-server/llms.txt Retrieves the PSONO server's public information, including its version, public key, supported authentication methods, and capabilities. This API call does not require authentication. ```bash # Get server information (no authentication required) curl -X GET https://your-psono-server.com/info/ # Response: { "info": "{\"version\":\"7.0.3\",\"api\":1,\"public_key\":\"02da2ad857...\",\"authentication_methods\":[\"AUTHKEY\"],\"web_client\":\"https://client.psono.com\",\"management\":true,\"files\":true}", "signature": "a1b2c3d4e5...", "verify_key": "4ce9e761..." } ``` -------------------------------- ### Get Server Info Source: https://context7.com/psono/psono-server/llms.txt Retrieves the server's public information, including its version, API version, public key, supported authentication methods, and client details. This endpoint does not require authentication. ```APIDOC ## GET /info/ ### Description Returns the server's signed public information including public key, supported authentication methods, and capabilities. ### Method GET ### Endpoint /info/ ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```bash curl -X GET https://your-psono-server.com/info/ ``` ### Response #### Success Response (200) - **info** (string) - A JSON string containing server details like version, public_key, authentication_methods, etc. - **signature** (string) - The signature of the info field. - **verify_key** (string) - The public key used for signature verification. #### Response Example ```json { "info": "{\"version\":\"7.0.3\",\"api\":1,\"public_key\":\"02da2ad857...\",\"authentication_methods\":[\"AUTHKEY\"],\"web_client\":\"https://client.psono.com\",\"management\":true,\"files\":true}", "signature": "a1b2c3d4e5...", "verify_key": "4ce9e761..." } ``` ``` -------------------------------- ### Get User Hashing Parameters - Bash Source: https://context7.com/psono/psono-server/llms.txt Fetches the password hashing algorithm and parameters for a given user before the login process. This is used to prevent username enumeration by returning fake parameters for non-existent users. ```bash # Get user's hashing parameters (prevents username enumeration by returning fake params for non-existent users) curl -X POST https://your-psono-server.com/authentication/prelogin/ \ -H "Content-Type: application/json" \ -d '{ "username": "user@example.com" }' # Response: { "hashing_algorithm": "scrypt", "hashing_parameters": { "n": 16384, "r": 8, "p": 1 } } ``` -------------------------------- ### Export PSONO Datastore to JSON (Python) Source: https://context7.com/psono/psono-server/llms.txt This Python script utilizes the psono-client library to export all password datastore contents to a JSON file named 'export.json'. It handles user login, fetching datastores, recursively reading secrets within folders and shared folders, and finally logging out. Ensure the psono-client library is installed. ```python """Export all passwords from PSONO to JSON file""" import json from psono_client import ( generate_client_login_info, api_login, verify_signature, decrypt_server_login_info, decrypt_with_api_secret_key, api_read_datastores, api_read_datastore, api_read_secret, api_read_share, decrypt_symmetric, api_logout ) def export_datastore(): # 1. Login session_private_key, client_login_info = generate_client_login_info() json_response = api_login(client_login_info) verify_signature(json_response['login_info'], json_response['login_info_signature']) login_info = decrypt_server_login_info( json_response['login_info'], json_response['login_info_nonce'], json_response['server_session_public_key'], session_private_key ) token = login_info['token'] session_secret_key = login_info['session_secret_key'] user_secret_key = decrypt_with_api_secret_key( login_info['user']['secret_key'], login_info['user']['secret_key_nonce'] ) # 2. Read datastores datastores = api_read_datastores(token, session_secret_key) export_data = {'datastores': []} for ds in datastores['datastores']: if ds['type'] != 'password': continue # 3. Read datastore content ds_result = api_read_datastore(token, session_secret_key, ds['id']) ds_secret = decrypt_symmetric(ds_result['secret_key'], ds_result['secret_key_nonce'], user_secret_key) ds_content = json.loads(decrypt_symmetric(ds_result['data'], ds_result['data_nonce'], ds_secret)) # 4. Recursively read all secrets def read_items(container): if 'items' in container: for item in container['items']: if 'secret_id' in item and 'secret_key' in item: secret = api_read_secret(token, session_secret_key, item['secret_id']) content = json.loads(decrypt_symmetric( secret['data'], secret['data_nonce'], item['secret_key'] )) item.update(content) if 'folders' in container: for folder in container['folders']: # Handle shared folders if 'share_id' in folder: share = api_read_share(token, session_secret_key, folder['share_id']) share_content = json.loads(decrypt_symmetric( share['data'], share['data_nonce'], folder['share_secret_key'] )) folder.update(share_content) read_items(folder) read_items(ds_content) export_data['datastores'].append(ds_content) # 5. Logout and save api_logout(token, session_secret_key) with open('export.json', 'w') as f: json.dump(export_data, f, indent=2) print(f"Exported to export.json") if __name__ == '__main__': export_datastore() ``` -------------------------------- ### Get Server Statistics (Bash) Source: https://context7.com/psono/psono-server/llms.txt Retrieves various server statistics using cURL. Requires administrator privileges and an authorization token. Endpoints exist for browser, device, OS, and two-factor authentication statistics. ```bash # Browser statistics curl -X GET https://your-psono-server.com/admin/stats/browser/ \ -H "Authorization: Token your_admin_token" # Device statistics curl -X GET https://your-psono-server.com/admin/stats/device/ \ -H "Authorization: Token your_admin_token" # OS statistics curl -X GET https://your-psono-server.com/admin/stats/os/ \ -H "Authorization: Token your_admin_token" # Two-factor authentication statistics curl -X GET https://your-psono-server.com/admin/stats/two-factor/ \ -H "Authorization: Token your_admin_token" ``` -------------------------------- ### User Registration - Bash Source: https://context7.com/psono/psono-server/llms.txt Creates a new user account on the PSONO server. This process involves providing user credentials, public and private keys (encrypted), secret keys, and hashing parameters. ```bash curl -X POST https://your-psono-server.com/authentication/register/ \ -H "Content-Type: application/json" \ -d '{ "username": "newuser@example.com", "email": "newuser@example.com", "authkey": "hex_encoded_authkey", "public_key": "hex_encoded_public_key", "private_key": "hex_encoded_encrypted_private_key", "private_key_nonce": "hex_encoded_nonce", "secret_key": "hex_encoded_encrypted_secret_key", "secret_key_nonce": "hex_encoded_nonce", "user_sauce": "random_hex_string", "hashing_algorithm": "scrypt", "hashing_parameters": {"n": 16384, "r": 8, "p": 1} }' # Response on success: {"success": "REGISTRATION_SUCCESSFUL"} ``` -------------------------------- ### Datastore APIs Source: https://context7.com/psono/psono-server/llms.txt APIs for managing and retrieving datastore information, including listing all datastores and reading the content of a specific datastore. ```APIDOC ## GET /datastore/ ### Description Retrieves a list of all datastores accessible by the authenticated user. ### Method GET ### Endpoint /datastore/ ### Parameters #### Headers - **Authorization** (string) - Required - Authentication token in the format 'Token '. ### Response #### Success Response (200) - **datastores** (array) - A list of datastore objects, each containing 'id', 'type', and 'description'. ### Response Example ```json { "datastores": [ {"id": "uuid", "type": "password", "description": "..."}, {"id": "uuid", "type": "user", "description": "..."} ] } ``` ## GET /datastore/{datastore_id}/ ### Description Retrieves the encrypted content of a specific datastore. The response needs to be decrypted using the session secret key and then the datastore's encryption key. ### Method GET ### Endpoint /datastore/{datastore_id}/ ### Parameters #### Path Parameters - **datastore_id** (string) - Required - The unique identifier of the datastore to retrieve. #### Headers - **Authorization** (string) - Required - Authentication token in the format 'Token '. ### Response #### Success Response (200) - **text** (string) - The encrypted datastore content. - **nonce** (string) - The nonce used for encrypting the datastore content. ### Response Example ```json { "text": "encrypted-datastore-content-base64", "nonce": "nonce-base64" } ``` ### Decryption Process 1. Decrypt the response using the `session_secret_key`. 2. Decrypt the `secret_key` within the datastore data using the `user_secret_key`. 3. Decrypt the actual datastore content using the decrypted `secret_key`. ### Example Decryption (Python - assuming `decrypt_symmetric` function exists) ```python import requests import json def decrypt_symmetric(encrypted_data, nonce, key): # Placeholder for actual decryption logic pass server_url = 'https://your-psono-server.com' token = 'your-auth-token' session_secret_key = 'your-session-secret-key-hex' datastore_id = 'datastore-uuid-to-read' user_secret_key = 'your-user-secret-key-hex' # This is the key derived from user's password headers = {'Content-Type': 'application/json', 'Authorization': f'Token {token}'} response = requests.get(f'{server_url}/datastore/{datastore_id}/', headers=headers) encrypted_response = response.json() # Decrypt transport layer datastore_result = json.loads(decrypt_symmetric( encrypted_response['text'], encrypted_response['nonce'], session_secret_key )) # Decrypt datastore encryption key datastore_secret = decrypt_symmetric( datastore_result['secret_key'], datastore_result['secret_key_nonce'], user_secret_key ) # Decrypt datastore content datastore_content = json.loads(decrypt_symmetric( datastore_result['data'], datastore_result['data_nonce'], datastore_secret )) # Returns structure like: # { # "datastore_id": "uuid", # "folders": [ # { # "id": "uuid", # "name": "Work", # "folders": [...], # "items": [ # {"id": "uuid", "type": "website_password", "name": "GitHub", "secret_id": "uuid", "secret_key": "hex"} # ] # } # ], # "items": [...] # } ``` ``` -------------------------------- ### User Registration Source: https://context7.com/psono/psono-server/llms.txt Creates a new user account on the PSONO server. This involves providing user details, cryptographic keys, and hashing parameters. ```APIDOC ## POST /authentication/register/ ### Description Creates a new user account with encrypted keys. ### Method POST ### Endpoint /authentication/register/ ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **username** (string) - Required - The desired username. - **email** (string) - Required - The user's email address. - **authkey** (string) - Required - The hex-encoded authentication key. - **public_key** (string) - Required - The hex-encoded public key of the user. - **private_key** (string) - Required - The hex-encoded encrypted private key. - **private_key_nonce** (string) - Required - The nonce used for encrypting the private key. - **secret_key** (string) - Required - The hex-encoded encrypted secret key. - **secret_key_nonce** (string) - Required - The nonce used for encrypting the secret key. - **user_sauce** (string) - Required - A random hex string used in key derivation. - **hashing_algorithm** (string) - Required - The hashing algorithm to use (e.g., 'scrypt'). - **hashing_parameters** (object) - Required - The parameters for the hashing algorithm. ### Request Example ```bash curl -X POST https://your-psono-server.com/authentication/register/ \ -H "Content-Type: application/json" \ -d '{ "username": "newuser@example.com", "email": "newuser@example.com", "authkey": "hex_encoded_authkey", "public_key": "hex_encoded_public_key", "private_key": "hex_encoded_encrypted_private_key", "private_key_nonce": "hex_encoded_nonce", "secret_key": "hex_encoded_encrypted_secret_key", "secret_key_nonce": "hex_encoded_nonce", "user_sauce": "random_hex_string", "hashing_algorithm": "scrypt", "hashing_parameters": {"n": 16384, "r": 8, "p": 1} }' ``` ### Response #### Success Response (200) - **success** (string) - Indicates successful registration (e.g., 'REGISTRATION_SUCCESSFUL'). #### Response Example ```json {"success": "REGISTRATION_SUCCESSFUL"} ``` ``` -------------------------------- ### Create Share (Python) Source: https://context7.com/psono/psono-server/llms.txt Creates a new shared folder. It generates an encryption key for the share, encrypts the share content and key, and sends it to the server. Requires a session secret key for transport layer encryption and a user secret key for encrypting the share key. ```python import uuid import nacl.utils import nacl.secret import json import requests def create_share(token, session_secret_key, share_content, datastore_id, user_secret_key): """Create a new shared folder""" # Generate encryption key for the share share_secret_key = nacl.encoding.HexEncoder.encode( nacl.utils.random(nacl.secret.SecretBox.KEY_SIZE) ).decode() # Encrypt share content encrypted_share = encrypt_symmetric(json.dumps(share_content), share_secret_key) # Encrypt share key with user's secret key (for storage in datastore) encrypted_share_key = encrypt_symmetric(share_secret_key, user_secret_key) link_id = str(uuid.uuid4()) payload = json.dumps({ 'data': encrypted_share['text'], 'data_nonce': encrypted_share['nonce'], 'key': encrypted_share_key['text'], 'key_nonce': encrypted_share_key['nonce'], 'key_type': 'symmetric', 'parent_datastore_id': datastore_id, 'link_id': link_id, }) encrypted_payload = encrypt_symmetric(payload, session_secret_key) headers = {'Content-Type': 'application/json', 'Authorization': f'Token {token}'} response = requests.post( f'{server_url}/share/', json={'text': encrypted_payload['text'], 'nonce': encrypted_payload['nonce']}, headers=headers ) result = json.loads(decrypt_symmetric(response.json()['text'], response.json()['nonce'], session_secret_key)) return { 'share_id': result['share_id'], 'share_secret_key': share_secret_key } ``` -------------------------------- ### API Key Login Source: https://context7.com/psono/psono-server/llms.txt Logs in using an API key to obtain a token and session secret key for further API interactions. ```APIDOC ## POST /api-key/login/ ### Description This endpoint is used to authenticate with the Psono server using an API key. It returns a token and a session secret key required for subsequent authenticated requests. ### Method POST ### Endpoint /api-key/login/ ### Parameters #### Request Body - **api_key_id** (string) - Required - The unique identifier for the API key. - **session_public_key** (string) - Required - The public key for the session. - **device_description** (string) - Optional - A description of the device or client making the request. - **signature** (string) - Required - The signature generated from the 'info' payload using the API key's private key. ### Request Example ```json { "info": "{\"api_key_id\": \"your-api-key-uuid\", \"session_public_key\": \"your-session-public-key\", \"device_description\": \"Automation Script\"}", "signature": "generated-signature-hex" } ``` ### Response #### Success Response (200) - **token** (string) - The authentication token. - **session_secret_key** (string) - The secret key for encrypting/decrypting session data. #### Response Example ```json { "token": "your-auth-token", "session_secret_key": "your-session-secret-key-hex" } ``` ``` -------------------------------- ### User Management (Bash) Source: https://context7.com/psono/psono-server/llms.txt Provides administrative user management operations via cURL. Includes endpoints for listing, retrieving, creating, and deleting users. Requires administrator privileges and an authorization token. User creation requires a JSON payload with username, email, and password. ```bash # List all users curl -X GET https://your-psono-server.com/admin/user/ \ -H "Authorization: Token your_admin_token" # Get specific user curl -X GET https://your-psono-server.com/admin/user/{user_id}/ \ -H "Authorization: Token your_admin_token" # Create user curl -X PUT https://your-psono-server.com/admin/user/ \ -H "Authorization: Token your_admin_token" \ -H "Content-Type: application/json" \ -d '{ "username": "newuser@example.com", "email": "newuser@example.com", "password": "initial_password" }' # Delete user curl -X DELETE https://your-psono-server.com/admin/user/{user_id}/ \ -H "Authorization: Token your_admin_token" ``` -------------------------------- ### Create Share Source: https://context7.com/psono/psono-server/llms.txt Creates a new shared folder that can be shared with other users. This endpoint handles the encryption of share content and keys before sending them to the server. ```APIDOC ## POST /share/ ### Description Creates a new shared folder that can be shared with other users. ### Method POST ### Endpoint /share/ ### Parameters #### Request Body - **text** (string) - Required - The encrypted share content. - **nonce** (string) - Required - The nonce used for encrypting the share content. ### Request Example ```json { "text": "encrypted_share_content", "nonce": "encrypted_share_nonce" } ``` ### Response #### Success Response (200) - **share_id** (string) - The ID of the newly created share. - **share_secret_key** (string) - The secret key for the newly created share. #### Response Example ```json { "share_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef", "share_secret_key": "generated_share_secret_key" } ``` ``` -------------------------------- ### Backup PSONO Server Data Source: https://github.com/psono/psono-server/blob/master/README.md This script facilitates the backup of PSONO Server data. It requires copying the 'var/backup' directory, updating the '.env' file within the copied directory, and then executing the 'backup' script. Backups can be scheduled using cron for automated execution. ```shell sudo cp -R var/backup /opt/psono-backup # Update .env file in /opt/psono-backup /opt/psono-backup/backup # Example cron entry for daily backup at 2:30 AM 30 2 * * * /opt/psono-backup/backup ``` -------------------------------- ### Restore PSONO Server Data Source: https://github.com/psono/psono-server/blob/master/README.md This script enables the restoration of PSONO Server from a backup. Similar to the backup process, it involves copying the 'var/backup' directory, updating the '.env' file, and then executing the 'restore' script with the path to the desired backup. ```shell sudo cp -R var/backup /opt/psono-backup # Update .env file in /opt/psono-backup /opt/psono-backup/restore --backup=path/to/the/backup/backup_12345.../ ``` -------------------------------- ### User Login - Python Source: https://context7.com/psono/psono-server/llms.txt Authenticates a user with the PSONO server and establishes a secure session. It utilizes ephemeral session keys for Perfect Forward Secrecy (PFS) and requires the user's derived authentication key and session public key. ```python import requests import json import nacl.encoding import nacl.signing from nacl.public import PrivateKey, PublicKey, Box server_url = 'https://your-psono-server.com' # Generate ephemeral session keys for PFS box = PrivateKey.generate() session_private_key = box.encode(encoder=nacl.encoding.HexEncoder).decode() session_public_key = box.public_key.encode(encoder=nacl.encoding.HexEncoder).decode() # Login request login_data = { 'username': 'user@example.com', 'authkey': 'your_derived_authkey_hex', # Derived from password using hashing params 'session_public_key': session_public_key, 'device_fingerprint': 'device_fingerprint_here', 'device_description': 'My Script', 'session_duration': 86400 # 24 hours } response = requests.post(f'{server_url}/authentication/login/', json=login_data) result = response.json() # Decrypt the login info using session keys # result contains: login_info (encrypted), login_info_nonce # After decryption, you get: token, session_secret_key, user info ``` -------------------------------- ### Create Signed Login Info for Psono Server Source: https://context7.com/psono/psono-server/llms.txt Generates signed login information using an API key and private key to authenticate with the Psono server. It then sends a POST request to the '/api-key/login/' endpoint and retrieves the server response, which includes a token and session secret key for subsequent encrypted communication. ```python import requests import json import nacl.encoding import nacl.signing import binascii # Assuming api_key_id, session_public_key, api_key_private_key, and server_url are defined info = json.dumps({ 'api_key_id': api_key_id, 'session_public_key': session_public_key, 'device_description': 'Automation Script', }) signing_box = nacl.signing.SigningKey(api_key_private_key, encoder=nacl.encoding.HexEncoder) signed = signing_box.sign(info.encode()) signature = binascii.hexlify(signed.signature).decode() login_data = {'info': info, 'signature': signature} response = requests.post(f'{server_url}/api-key/login/', json=login_data) result = response.json() # The result contains a token and session_secret_key for further encrypted API calls. ``` -------------------------------- ### Header, Footer, and Main Section Styles Source: https://github.com/psono/psono-server/blob/master/psono/templates/email/new_share_created.html Styles for the main sections of an email template, including '.main', '.wrapper', and '.footer'. This snippet defines background colors, borders, padding, and text alignment for these key areas. ```css /* ------------------------------------- HEADER, FOOTER, MAIN ------------------------------------- */ .main { background: #151f2b; border-radius: 4px; width: 100%; } .wrapper { box-sizing: border-box; padding: 20px; } .footer { clear: both; padding-top: 10px; text-align: center; width: 100%; } .footer td, .footer p, .footer span, .footer a { color: #999999; font-size: 12px; text-align: center; } ``` -------------------------------- ### API Key Login (Session-Based) Source: https://context7.com/psono/psono-server/llms.txt Authenticates a user session using an API key. This method establishes a secure session with transport encryption. ```APIDOC ## POST /authentication/login/apikey/ ### Description Authenticates using an API key and creates a session with transport encryption. ### Method POST ### Endpoint /authentication/login/apikey/ ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **api_key_id** (string) - Required - The ID of the API key. - **api_key_signature** (string) - Required - The signature generated using the API key's private key. - **session_public_key** (string) - Required - The public key of the ephemeral session. - **device_fingerprint** (string) - Required - A fingerprint identifying the device. - **device_description** (string) - Optional - A description for the device. - **session_duration** (integer) - Optional - The desired duration of the session in seconds. ### Request Example ```python import requests import json import nacl.encoding import nacl.signing import nacl.secret from nacl.public import PrivateKey, PublicKey, Box import binascii api_key_id = 'your-api-key-uuid' api_key_private_key = 'your_api_key_private_key_hex' api_key_secret_key = 'your_api_key_secret_key_hex' server_url = 'https://your-psono-server.com' # Generate session keys box = PrivateKey.generate() session_private_key = box.encode(encoder=nacl.encoding.HexEncoder).decode() session_public_key = box.public_key.encode(encoder=nacl.encoding.HexEncoder).decode() # Prepare data for signing data_to_sign = f'{session_public_key}{device_fingerprint}{device_description}{session_duration}'.encode('utf-8') # Sign the data with the API key's private key signer = nacl.signing.SigningKey(binascii.unhexlify(api_key_private_key)) api_key_signature = binascii.hexlify(signer.sign(data_to_sign)).decode() login_data = { 'api_key_id': api_key_id, 'api_key_signature': api_key_signature, 'session_public_key': session_public_key, 'device_fingerprint': 'device_fingerprint_here', 'device_description': 'My Script', 'session_duration': 86400 } response = requests.post(f'{server_url}/authentication/login/apikey/', json=login_data) result = response.json() # The response will contain encrypted session information similar to user login. ``` ### Response #### Success Response (200) - **login_info** (string) - Encrypted login information including the session token. - **login_info_nonce** (string) - The nonce used to encrypt the login information. #### Response Example (Response is encrypted and requires decryption using session keys) ``` -------------------------------- ### API Key Access (No Session - Restricted) Source: https://context7.com/psono/psono-server/llms.txt Allows direct access to specific secrets using an API key without establishing a full user session. Useful for automated scripts with limited permissions. ```APIDOC ## POST /api-key-access/inspect/ ### Description Inspects an API key to determine its access permissions and the secrets it can access. ### Method POST ### Endpoint /api-key-access/inspect/ ### Parameters #### Request Body - **api_key_id** (string) - Required - The unique identifier for the API key. ### Response #### Success Response (200) - **api_key_secrets** (array) - A list of secrets accessible by the API key. - **read** (boolean) - Indicates if the API key has read permissions. - **write** (boolean) - Indicates if the API key has write permissions. - **restrict_to_secrets** (boolean) - Indicates if access is restricted to specific secrets. ### Request Example ```json { "api_key_id": "your-api-key-uuid" } ``` ## POST /api-key-access/secret/ ### Description Reads a specific secret directly using an API key. The secret is returned encrypted and requires decryption using the API key's secret key. ### Method POST ### Endpoint /api-key-access/secret/ ### Parameters #### Request Body - **api_key_id** (string) - Required - The unique identifier for the API key. - **secret_id** (string) - Required - The unique identifier of the secret to read. ### Response #### Success Response (200) - **secret_key** (string) - The encrypted secret key for the specific secret. - **secret_key_nonce** (string) - The nonce used for encrypting the secret key. - **data** (string) - The encrypted secret data. - **data_nonce** (string) - The nonce used for encrypting the secret data. ### Request Example ```json { "api_key_id": "your-api-key-uuid", "secret_id": "secret-uuid-to-read" } ``` ### Decryption Process 1. Decrypt `secret_key` using the API key's secret key and `secret_key_nonce`. 2. Use the decrypted secret key to decrypt the `data` using `data_nonce`. ### Example Decryption (Python) ```python import requests import json import nacl.encoding import nacl.secret api_key_id = 'your-api-key-uuid' api_key_secret_key = 'your_api_key_secret_key_hex' server_url = 'https://your-psono-server.com' secret_id = 'secret-uuid-to-read' # Read a secret directly read_response = requests.post( f'{server_url}/api-key-access/secret/', json={'api_key_id': api_key_id, 'secret_id': secret_id} ) encrypted_secret = read_response.json() # Decrypt the secret key first crypto_box = nacl.secret.SecretBox(api_key_secret_key, encoder=nacl.encoding.HexEncoder) encryption_key = crypto_box.decrypt( nacl.encoding.HexEncoder.decode(encrypted_secret['secret_key']), nacl.encoding.HexEncoder.decode(encrypted_secret['secret_key_nonce']) ) # Then decrypt the secret data crypto_box = nacl.secret.SecretBox(encryption_key, encoder=nacl.encoding.HexEncoder) decrypted = crypto_box.decrypt( nacl.encoding.HexEncoder.decode(encrypted_secret['data']), nacl.encoding.HexEncoder.decode(encrypted_secret['data_nonce']) ) secret_content = json.loads(decrypted) # Example: {'website_password_url': 'https://...', 'website_password_username': '...', 'website_password_password': '...'} ``` ``` -------------------------------- ### API Key Login - Python Source: https://context7.com/psono/psono-server/llms.txt Authenticates a client using an API key, establishing a session with transport encryption. This method requires the API key ID, its private key, and its secret key, along with generated session keys. ```python import requests import json import nacl.encoding import nacl.signing import nacl.secret from nacl.public import PrivateKey, PublicKey, Box import binascii api_key_id = 'your-api-key-uuid' api_key_private_key = 'your_api_key_private_key_hex' api_key_secret_key = 'your_api_key_secret_key_hex' server_url = 'https://your-psono-server.com' # Generate session keys box = PrivateKey.generate() session_private_key = box.encode(encoder=nacl.encoding.HexEncoder).decode() session_public_key = box.public_key.encode(encoder=nacl.encoding.HexEncoder).decode() ``` -------------------------------- ### Symmetric Encryption Helper (Python) Source: https://context7.com/psono/psono-server/llms.txt Provides helper functions for NaCl symmetric encryption (XSalsa20-Poly1305). Includes functions to encrypt messages with a secret key and nonce, and to decrypt messages given the ciphertext, nonce, and secret key. Both functions handle hex encoding/decoding. ```python import nacl.encoding import nacl.secret import nacl.utils def encrypt_symmetric(message, secret_key_hex): """Encrypt a message with NaCl SecretBox (XSalsa20-Poly1305)""" nonce = nacl.utils.random(nacl.secret.SecretBox.NONCE_SIZE) secret_box = nacl.secret.SecretBox(secret_key_hex, encoder=nacl.encoding.HexEncoder) encrypted = secret_box.encrypt(message.encode(), nonce) # Separate ciphertext from nonce ciphertext = encrypted[len(nonce):] return { 'text': nacl.encoding.HexEncoder.encode(ciphertext).decode(), 'nonce': nacl.encoding.HexEncoder.encode(nonce).decode() } def decrypt_symmetric(ciphertext_hex, nonce_hex, secret_key_hex): """Decrypt a message encrypted with NaCl SecretBox""" ciphertext = nacl.encoding.HexEncoder.decode(ciphertext_hex) nonce = nacl.encoding.HexEncoder.decode(nonce_hex) secret_box = nacl.secret.SecretBox(secret_key_hex, encoder=nacl.encoding.HexEncoder) return secret_box.decrypt(ciphertext, nonce).decode() ``` -------------------------------- ### User Management APIs Source: https://context7.com/psono/psono-server/llms.txt Administrative endpoints for managing users on the Psono server, including listing, retrieving, creating, and deleting users. ```APIDOC ## Administration APIs - User Management ### GET /admin/user/ Lists all users on the server. ### GET /admin/user/{user_id}/ Retrieves details for a specific user. ### PUT /admin/user/ Creates a new user. ### DELETE /admin/user/{user_id}/ Deletes a specific user. ### Method GET, PUT, DELETE ### Endpoint /admin/user/ /admin/user/{user_id}/ ### Parameters #### Headers - **Authorization** (string) - Required - Bearer token for authentication (e.g., `Token your_admin_token`). - **Content-Type** (string) - Required for PUT requests (e.g., `application/json`). #### Path Parameters (for GET and DELETE) - **user_id** (string) - Required - The ID of the user. #### Request Body (for PUT) - **username** (string) - Required - The username for the new user. - **email** (string) - Required - The email address for the new user. - **password** (string) - Required - The initial password for the new user. ### Request Example (Create User) ```bash curl -X PUT https://your-psono-server.com/admin/user/ \ -H "Authorization: Token your_admin_token" \ -H "Content-Type: application/json" \ -d '{ "username": "newuser@example.com", "email": "newuser@example.com", "password": "initial_password" }' ``` ### Response #### Success Response (200) - For GET requests: JSON object containing user information. - For PUT requests: JSON object confirming user creation. - For DELETE requests: Typically an empty response or a success message. ``` -------------------------------- ### API Key Access to Secrets (No Session) Source: https://context7.com/psono/psono-server/llms.txt Demonstrates how to access specific secrets directly using an API key without establishing a full user session. This is useful for restricted API keys. It first inspects the API key's permissions and then reads a secret, decrypting it using the API key's secret key. ```python import requests import json import nacl.encoding import nacl.secret # Assuming api_key_id, api_key_secret_key, server_url, and secret_id are defined # Inspect API key to see allowed secrets inspect_response = requests.post( f'{server_url}/api-key-access/inspect/', json={'api_key_id': api_key_id} ) # Returns: {api_key_secrets: [{secret_id: "..."}], read: true, write: true, restrict_to_secrets: true} # Read a secret directly read_response = requests.post( f'{server_url}/api-key-access/secret/', json={'api_key_id': api_key_id, 'secret_id': secret_id} ) encrypted_secret = read_response.json() # Decrypt the secret key first crypto_box = nacl.secret.SecretBox(api_key_secret_key, encoder=nacl.encoding.HexEncoder) encryption_key = crypto_box.decrypt( nacl.encoding.HexEncoder.decode(encrypted_secret['secret_key']), nacl.encoding.HexEncoder.decode(encrypted_secret['secret_key_nonce']) ) # Then decrypt the secret data crypto_box = nacl.secret.SecretBox(encryption_key, encoder=nacl.encoding.HexEncoder) decrypted = crypto_box.decrypt( nacl.encoding.HexEncoder.decode(encrypted_secret['data']), nacl.encoding.HexEncoder.decode(encrypted_secret['data_nonce']) ) secret_content = json.loads(decrypted) # Example: {'website_password_url': 'https://...', 'website_password_username': '...', 'website_password_password': '...'} ``` -------------------------------- ### User Login Source: https://context7.com/psono/psono-server/llms.txt Authenticates a user using their credentials and returns an encrypted session token. This endpoint supports Perfect Forward Secrecy (PFS) by using ephemeral session keys. ```APIDOC ## POST /authentication/login/ ### Description Authenticates a user and returns an encrypted session token with Perfect Forward Secrecy (PFS). ### Method POST ### Endpoint /authentication/login/ ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **username** (string) - Required - The user's username. - **authkey** (string) - Required - The derived authentication key (hex-encoded). - **session_public_key** (string) - Required - The public key of the ephemeral session. - **device_fingerprint** (string) - Required - A fingerprint identifying the device. - **device_description** (string) - Optional - A description for the device. - **session_duration** (integer) - Optional - The desired duration of the session in seconds (defaults to 86400). ### Request Example ```python import requests import json import nacl.encoding import nacl.signing from nacl.public import PrivateKey, PublicKey, Box server_url = 'https://your-psono-server.com' # Generate ephemeral session keys for PFS box = PrivateKey.generate() session_private_key = box.encode(encoder=nacl.encoding.HexEncoder).decode() session_public_key = box.public_key.encode(encoder=nacl.encoding.HexEncoder).decode() # Login request login_data = { 'username': 'user@example.com', 'authkey': 'your_derived_authkey_hex', # Derived from password using hashing params 'session_public_key': session_public_key, 'device_fingerprint': 'device_fingerprint_here', 'device_description': 'My Script', 'session_duration': 86400 # 24 hours } response = requests.post(f'{server_url}/authentication/login/', json=login_data) result = response.json() # Decrypt the login info using session keys # result contains: login_info (encrypted), login_info_nonce # After decryption, you get: token, session_secret_key, user info ``` ### Response #### Success Response (200) - **login_info** (string) - Encrypted login information including the session token. - **login_info_nonce** (string) - The nonce used to encrypt the login information. #### Response Example (Response is encrypted and requires decryption using session keys) ``` -------------------------------- ### Head Styles for Email Clients Source: https://github.com/psono/psono-server/blob/master/psono/templates/email/new_group_membership_created.html Contains styles intended for the `` section of an HTML document, particularly for email clients. It includes styles to ensure proper rendering across different email clients, such as handling external classes and Apple-specific links. ```css @media all { .ExternalClass { width: 100%; } .ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div { line-height: 100%; } .apple-link a { color: inherit !important; font-family: inherit !important; font-size: inherit !important; f ``` -------------------------------- ### Secret Management API Source: https://context7.com/psono/psono-server/llms.txt APIs for managing secrets, including creation, reading, and updating. ```APIDOC ## PUT /secret/ ### Description Creates a new encrypted secret in a datastore or share. ### Method PUT ### Endpoint /secret/ ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **text** (string) - Required - The encrypted payload containing the new secret details. - **nonce** (string) - Required - The nonce used for encrypting the payload. ### Request Example ```json { "text": "encrypted_payload_text", "nonce": "encrypted_payload_nonce" } ``` ### Response #### Success Response (200) - **text** (string) - The encrypted response containing the new secret's ID, key, and link ID. - **nonce** (string) - The nonce used for encrypting the response. #### Response Example ```json { "text": "encrypted_response_text", "nonce": "encrypted_response_nonce" } ``` ``` ```APIDOC ## GET /secret/{secret_id}/ ### Description Reads and decrypts a specific secret. ### Method GET ### Endpoint /secret/{secret_id}/ ### Parameters #### Path Parameters - **secret_id** (string) - Required - The ID of the secret to retrieve. #### Query Parameters None #### Request Body None ### Request Example (No request body for GET requests) ### Response #### Success Response (200) - **text** (string) - The encrypted response containing the secret data and metadata. - **nonce** (string) - The nonce used for encrypting the response. #### Response Example ```json { "text": "encrypted_response_text", "nonce": "encrypted_response_nonce" } ``` ``` ```APIDOC ## POST /secret/ ### Description Updates an existing secret with new encrypted content. ### Method POST ### Endpoint /secret/ ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **text** (string) - Required - The encrypted payload containing the updated secret details. - **nonce** (string) - Required - The nonce used for encrypting the payload. ### Request Example ```json { "text": "encrypted_payload_text", "nonce": "encrypted_payload_nonce" } ``` ### Response #### Success Response (200) Returns `true` if the update was successful. #### Response Example ```json true ``` ```