Files
digiserver-v2/old_code_documentation/player_analisis/KIWY_PLAYER_ARCHITECTURE_DIAGRAM.md

25 KiB

Kiwy-Signage HTTPS Architecture Diagram

Current Architecture (Before Patches)

┌─────────────────────────────────────────────────────────────────┐
│                    Kiwy-Signage Player                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  GUI / Settings (main.py:696-703)                        │  │
│  │  - Reads config/app_config.json                          │  │
│  │  - Builds server URL                                     │  │
│  │  - Calls PlayerAuth.authenticate()                       │  │
│  └──────────────────────────────────────────────────────────┘  │
│                            │                                    │
│                            ▼                                    │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  PlayerAuth (src/player_auth.py)                         │  │
│  │  - authenticate() [Line 95]                              │  │
│  │  - verify_auth() [Line 157]                              │  │
│  │  - get_playlist() [Line 178]                             │  │
│  │  - send_heartbeat() [Line 227]                           │  │
│  │  - send_feedback() [Line 254]                            │  │
│  │                                                           │  │
│  │  All use: requests.post/get(..., timeout=30)             │  │
│  │  ⚠️  verify parameter NOT SPECIFIED (uses default)      │  │
│  └──────────────────────────────────────────────────────────┘  │
│                            │                                    │
│                            ▼                                    │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  Playlist Manager (src/get_playlists_v2.py)              │  │
│  │  - download_media_files() [Line 159]                     │  │
│  │  - requests.get(file_url, timeout=30)                    │  │
│  │  ⚠️  verify parameter NOT SPECIFIED                     │  │
│  └──────────────────────────────────────────────────────────┘  │
│                            │                                    │
│                            ▼                                    │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  Python requests Library (v2.32.4)                       │  │
│  │  - Default: verify=True                                  │  │
│  │  - Validates against system CA certificates              │  │
│  │  - NO custom CA support in this application              │  │
│  │  - NO certificate pinning                                │  │
│  │  - NO ignore certificate verification option             │  │
│  └──────────────────────────────────────────────────────────┘  │
│                            │                                    │
└────────────────────────────┼────────────────────────────────────┘
                             │
                    ┌────────▼──────────┐
                    │  HTTPS Handshake  │
                    ├───────────────────┤
                    │ Validates cert:   │
                    │ ✓ Chain valid?    │
                    │ ✓ Hostname match? │
                    │ ✓ Not expired?    │
                    │ ✓ In CA store?    │
                    └────────┬──────────┘
                             │
        ┌────────────────────┼────────────────────┐
        │                    │                    │
    Success ❌ SELF-SIGNED   │                 Success ✅
   (Not in CA              │              (CA-signed cert)
    store)                 │
        │              ✓ Server
        │          Certificate
        │              Valid
        │
   ┌────▼─────────────────────────────────────────┐
   │  SSLError: certificate verify failed        │
   │  Application cannot connect to server        │
   │  Player goes offline                         │
   └─────────────────────────────────────────────┘


CURRENT LIMITATION:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Player ONLY works with production certificates
that are signed by a trusted Certificate Authority
and present in the system's CA certificate store.

After Patches - New Architecture

┌─────────────────────────────────────────────────────────────────┐
│                    Kiwy-Signage Player                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  GUI / Settings (main.py:696-703)                        │  │
│  │  - Reads config/app_config.json                          │  │
│  │  - Builds server URL                                     │  │
│  │  - Calls PlayerAuth.authenticate()                       │  │
│  └──────────────────────────────────────────────────────────┘  │
│                            │                                    │
│                            ▼                                    │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  SSLConfig Module (src/ssl_config.py) ✨ NEW             │  │
│  │  - get_verify_setting()                                  │  │
│  │  - get_ca_bundle()                                       │  │
│  │  - set_ca_bundle(path)                                   │  │
│  │  - disable_verification() [dev/test only]                │  │
│  │                                                           │  │
│  │  Certificate Resolution Order:                           │  │
│  │  1. Custom CA set via set_ca_bundle()                    │  │
│  │  2. REQUESTS_CA_BUNDLE env var                           │  │
│  │  3. config/ca_bundle.crt (file in app)                   │  │
│  │  4. System default (True = certifi)                      │  │
│  └──────────────────────────────────────────────────────────┘  │
│                            │                                    │
│                            ▼                                    │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  PlayerAuth (MODIFIED: src/player_auth.py)               │  │
│  │  - __init__(): self.verify_ssl = SSLConfig.get_...()    │  │
│  │  - authenticate(): verify=self.verify_ssl [Line 95]      │  │
│  │  - verify_auth(): verify=self.verify_ssl [Line 157]      │  │
│  │  - get_playlist(): verify=self.verify_ssl [Line 178]     │  │
│  │  - send_heartbeat(): verify=self.verify_ssl [Line 227]   │  │
│  │  - send_feedback(): verify=self.verify_ssl [Line 254]    │  │
│  └──────────────────────────────────────────────────────────┘  │
│                            │                                    │
│                            ▼                                    │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  Playlist Manager (MODIFIED: get_playlists_v2.py)         │  │
│  │  - download_media_files(): verify=verify_ssl [Line 159]  │  │
│  └──────────────────────────────────────────────────────────┘  │
│                            │                                    │
│                            ▼                                    │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  Python requests Library (v2.32.4)                       │  │
│  │  - Uses verify parameter from SSLConfig                  │  │
│  │  - Can use custom CA bundle (if provided)                │  │
│  │  - Validates against specified certificate               │  │
│  └──────────────────────────────────────────────────────────┘  │
│                            │                                    │
└────────────────────────────┼────────────────────────────────────┘
                             │
                    ┌────────▼──────────┐
                    │  HTTPS Handshake  │
                    ├───────────────────┤
                    │ Validates against:│
                    │ ✓ Custom CA       │
                    │ ✓ Hostname        │
                    │ ✓ Expiration      │
                    └────────┬──────────┘
                             │
        ┌────────────────────┼────────────────────┐
        │                    │                    │
    Success ✅          Success ✅           Success ✅
 (Custom CA or   (Self-signed +     (Production
  self-signed)   ca_bundle.crt)       cert)
        │                    │                    │
        └────────────────┬───┴────────────────────┘
                         │
                    ┌────▼──────┐
                    │ Connected! │
                    │ Establish  │
                    │  secure    │
                    │ connection │
                    └─────────────┘


NEW CAPABILITY:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Player works with:
✅ Production certificates (CA-signed)
✅ Self-signed certificates (with ca_bundle.crt)
✅ Custom CA certificates (with environment variable)
✅ Multiple certificate scenarios (dev, test, prod)

Certificate Resolution Flow

When Player Starts
        │
        ▼
┌──────────────────┐
│  PlayerAuth      │
│  __init__()      │
└────────┬─────────┘
         │
         │ Calls SSLConfig.get_verify_setting()
         │
         ▼
    ┌──────────────────────────┐
    │ Check Priority Order     │
    └──────────────┬───────────┘
                   │
           ┌───────▼────────┐
           │ Is custom CA   │──NO──┐
           │ set via code?  │      │
           └───────────────┘      │
                │ YES             │
                ▼                 ▼
           Return path     ┌──────────────────────┐
                           │ Check environment    │
                           │ REQUESTS_CA_BUNDLE? │
                           └────────┬─────────────┘
                                    │
                                NO  │  YES
                             ┌──────┘  ▼
                             │     Return env
                             │     var path
                             ▼
                    ┌──────────────────────┐
                    │ Check config dir     │
                    │ config/ca_bundle.crt?│
                    └────────┬─────────────┘
                             │
                         NO  │  YES
                      ┌──────┘  ▼
                      │     Return config
                      │     cert path
                      ▼
                ┌─────────────────┐
                │ No custom cert  │
                │ found, use      │
                │ system default  │
                │ (True)          │
                └─────────────────┘
                      │
                      ▼
                ┌──────────────────┐
                │ Pass to requests │
                │ library as       │
                │ verify=<value>   │
                └──────────────────┘
                      │
                      ▼
                ┌──────────────────────────┐
                │ HTTPS Connection Made   │
                │ With Selected Cert      │
                └──────────────────────────┘

File Structure After Patches

Kiwy-Signage/
├── config/
│   ├── app_config.json          (unchanged)
│   ├── ca_bundle.crt            ✨ NEW (optional)
│   └── resources/
│
├── src/
│   ├── main.py                  (unchanged)
│   ├── player_auth.py           ✏️  MODIFIED (7 changes)
│   ├── get_playlists_v2.py      ✏️  MODIFIED (2 changes)
│   ├── ssl_config.py            ✨ NEW FILE (~60 lines)
│   ├── network_monitor.py       (unchanged)
│   ├── edit_popup.py            (unchanged)
│   └── keyboard_widget.py       (unchanged)
│
├── working_files/               (unchanged)
├── start.sh                     (unchanged)
├── requirements.txt             (unchanged - no new packages!)
└── ...

Changes Summary:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✨ New Files:      1 (ssl_config.py + ca_bundle.crt)
✏️  Modified Files: 2 (player_auth.py, get_playlists_v2.py)
📦 New Packages:   0 (uses existing requests library)
🔄 Backward Compat: Yes (all changes are additive)
⚠️  Breaking Chgs:  None

Deployment Scenarios

Scenario 1: Production Server (Current)

DigiServer v2
(digi-signage.moto-adv.com)
    │
    │ Valid CA Certificate
    │ (e.g., Let's Encrypt)
    │
    ▼
Player (No patches needed)
    │
    ▼ requests.post/get(..., timeout=30)
         ├─ No verify= specified
         └─ Uses system default: verify=True
    │
    ▼ validates cert ✓
         │
         ▼ SSL handshake succeeds ✓
              │
              ▼ authenticated ✓


Result: ✅ Works fine (no changes needed)

Scenario 2: Self-Signed Server (After Patches)

DigiServer v2 (self.local)
(Self-signed certificate)
    │
    │ 1. Export cert
    │    openssl s_client... > server.crt
    │
    │ 2. Place in player
    │    config/ca_bundle.crt
    │
    ▼
Player (with patches)
    │
    ▼ __init__()
         │
         ▼ SSLConfig.get_verify_setting()
              ├─ Check custom CA: None
              ├─ Check env var: not set
              ├─ Check config dir: ✓ found ca_bundle.crt
              │
              └─ Return: 'config/ca_bundle.crt'
    │
    ▼ requests.post/get(..., verify='config/ca_bundle.crt')
    │
    ▼ validates cert against ca_bundle.crt ✓
         │
         ▼ SSL handshake succeeds ✓
              │
              ▼ authenticated ✓


Result: ✅ Works with self-signed cert

Scenario 3: Development (Insecure - Testing Only)

DigiServer v2 (test.local)
(Self-signed, or cert issues)
    │
    ▼
Player (with patches + SSLConfig.disable_verification())
    │
    ▼ SSLConfig.disable_verification()
         │
         └─ _verify_ssl = False
    │
    ▼ requests.post/get(..., verify=False)
    │
    ▼ ⚠️  Skips certificate validation
         │
         ▼ SSL handshake proceeds anyway ⚠️
              │
              ▼ authenticated (but insecure!)
         
         ⚠️  VULNERABLE TO MITM ATTACKS


Result: ⚠️  Works but insecure - DEV/TEST ONLY
Note: Add in code temporarily:
  from ssl_config import SSLConfig
  SSLConfig.disable_verification()  # TEMPORARY - DEV ONLY

Request Flow Sequence Diagram

Player           SSLConfig          requests          DigiServer
  │                 │                  │                  │
  │─ authenticate()─│                  │                  │
  │                 │                  │                  │
  │          get_verify_setting()      │                  │
  │                 │                  │                  │
  │        ◄────────┤ 'config/ca...   │                  │
  │                 │   bundle.crt'    │                  │
  │                 │                  │                  │
  │  ┌──────────────┐                  │                  │
  │  │ requests.post(                  │                  │
  │  │   url,                          │                  │
  │  │   verify='config/ca...         │                  │
  │  │         bundle.crt',           │                  │
  │  │   ...                          │                  │
  │  │ )                              │                  │
  │  └──────────────┘                  │                  │
  │                 │ validate cert    │                  │
  │                 │ against bundle◄──┤─ Server Cert ────┤
  │                 │                  │   (PEM format)   │
  │                 │                  │                  │
  │                 │                  │ ✓ Signature OK   │
  │                 │                  │ ✓ Chain valid    │
  │                 │                  │ ✓ Hostname match │
  │                 │                  │                  │
  │                 │ ◄────────────────┤─ 200 OK ─────────┤
  │ response ◄──────┤                  │ {auth_code}      │
  │                 │                  │                  │
  │ Save auth_code  │                  │                  │
  │ to file         │                  │                  │
  │                 │                  │                  │

Error Handling

BEFORE (Current):
───────────────

requests.post(url, ...)
    │
    ├─ success → parse response
    │
    └─ SSLError (self-signed cert)
         │
         └─ Caught by: except Exception as e
              │
              └─ error_msg = "Authentication error: ..."
                   │
                   └─ User sees generic error ❌


AFTER (With Patches):
─────────────────────

requests.post(url, ..., verify=ca_bundle)
    │
    ├─ success → parse response
    │           (with custom CA support)
    │
    └─ SSLError (cert not in bundle)
         │
         └─ Caught by: except Exception as e
              │
              └─ error_msg = "Authentication error: ..."
                   │
                   └─ Log shows actual SSL error details ✓
                      (if SSL validation fails, not player's fault)

Security Comparison

Scenario: Self-Signed Certificate

┌──────────────────┬──────────────────────┬─────────────────────┐
│   Approach       │   Security Level     │   Recommendations  │
├──────────────────┼──────────────────────┼─────────────────────┤
│ Do nothing       │ 🔴 BROKEN            │ ❌ Not viable       │
│ (current)        │ - Player offline     │ - App won't work    │
│                  │ - No connection      │                     │
├──────────────────┼──────────────────────┼─────────────────────┤
│ verify=False     │ ⚠️  INSECURE         │ ⚠️  DEV/TEST ONLY   │
│ (disable verify) │ - Vulnerable to MITM │ - Never production  │
│                  │ - No cert validation │ - Temporary measure │
├──────────────────┼──────────────────────┼─────────────────────┤
│ Custom CA bundle │ ✅ SECURE            │ ✅ RECOMMENDED      │
│ (patches)        │ - Validates cert     │ - Works with any    │
│                  │ - CA is trusted      │   self-signed cert  │
│                  │ - No MITM risk       │ - Production-ready  │
├──────────────────┼──────────────────────┼─────────────────────┤
│ Cert pinning     │ 🔒 VERY SECURE       │ ✅ IF NEEDED        │
│ (advanced)       │ - Pins specific cert │ - Extra complexity  │
│                  │ - Maximum trust      │ - For high-security │
│                  │                      │   deployments       │
└──────────────────┴──────────────────────┴─────────────────────┘