diff --git a/.agentbridge/conversation.db b/.agentbridge/conversation.db new file mode 100644 index 00000000..4d0f4d75 Binary files /dev/null and b/.agentbridge/conversation.db differ diff --git a/.agentbridge/conversation.db-shm b/.agentbridge/conversation.db-shm new file mode 100644 index 00000000..63921544 Binary files /dev/null and b/.agentbridge/conversation.db-shm differ diff --git a/.agentbridge/conversation.db-wal b/.agentbridge/conversation.db-wal new file mode 100644 index 00000000..b205380c Binary files /dev/null and b/.agentbridge/conversation.db-wal differ diff --git a/SERVER.md b/SERVER.md new file mode 100644 index 00000000..dfe9bd1a --- /dev/null +++ b/SERVER.md @@ -0,0 +1,132 @@ +# Provisioning server + +Baresip Studio can provision accounts from a server-encrypted bundle using a +per-device RSA key pair generated in Android Keystore. + +Endpoint contract +- Base URL: whatever you pass as `endpoint=` in the `baresip:` URI +- Path used by the app: `/bundle` +- Method: POST +- Request Content-Type: application/json +- Response Content-Type: application/json + +Enrollment request body +{ + "extension": "101", + "public_key": "" +} + +Provisioning bundle response body +{ + "encrypted_key": "", + "iv": "", + "ciphertext": "", + "tag": "" +} + +The plaintext AES-GCM payload after decryption should be a JSON object like: +{ + "connect_string": "sip:101@pbx.example.com", + "transport": "tls", + "sip_verify_server": "yes", + "username": "101", + "password": "secret", + "display_name": "Extension 101", + "account_name": "Desk Phone", + "outbound1": "sip:pbx.example.com", + "outbound2": "", + "register": true, + "reg_int": 900, + "check_origin": true, + "media_enc": "", + "media_nat": "", + "stun_server": "", + "stun_user": "", + "stun_pass": "", + "rtcp_mux": false, + "rel100": false, + "dtmf_mode": 2, + "answer_mode": 0, + "auto_redirect": false, + "vm_uri": "", + "country_code": "", + "tel_provider": "", + "numeric_keypad": false, + "default_account": true, + "custom_params": "", + "client_cert": "", + "client_key": "", + "ca_certs": "" +} + +Python server example +- Requirements: python >= 3.10 +- pip install fastapi uvicorn pydantic + +from fastapi import FastAPI, HTTPException +from pydantic import BaseModel +from cryptography.hazmat.primitives.asymmetric import padding +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.ciphers.aead import AESGCM +import base64 +import json + +app = FastAPI() + +class EnrollRequest(BaseModel): + extension: str + public_key: str + +class BundleResponse(BaseModel): + encrypted_key: str + iv: str + ciphertext: str + tag: str + +SERVER_RSA_PRIVATE_KEY_PEM = """-----BEGIN RSA PRIVATE KEY----- +... +-----END RSA PRIVATE KEY-----""" + +def server_private_key(): + return serialization.load_pem_private_key( + SERVER_RSA_PRIVATE_KEY_PEM.encode(), password=None + ) + +@app.post("/bundle", response_model=BundleResponse) +def bundle(req: EnrollRequest): + pub = serialization.load_der_public_key(base64.b64decode(req.public_key)) + aes_key = AESGCM.generate_key(bit_length=256) + aesgcm = AESGCM(aes_key) + iv = b"012345678901" # replace with os.urandom(12) in production + payload = { + "connect_string": f"sip:{req.extension}@pbx.example.com", + "transport": "tls", + "sip_verify_server": "yes", + "username": req.extension, + "password": "secret", + "client_cert": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----", + "client_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----", + "ca_certs": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----", + } + plaintext = json.dumps(payload).encode("utf-8") + encrypted = aesgcm.encrypt(iv, plaintext, None) + encrypted_key = server_private_key().encrypt( + aes_key, + padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None), + ) + ciphertext = encrypted[:-16] + tag = encrypted[-16:] + return BundleResponse( + encrypted_key=base64.b64encode(encrypted_key).decode(), + iv=base64.b64encode(iv).decode(), + ciphertext=base64.b64encode(ciphertext).decode(), + tag=base64.b64encode(tag).decode(), + ) + +Example baresip URI +baresip://provision?endpoint=https://pbx.example.com&extension=101 + +Security notes +- Always serve over HTTPS. +- Keep SERVER_RSA_PRIVATE_KEY_PEM secret and offline from the app. +- Treat the bundle URL as a secret; short expiry and single-use are recommended.