# Keys Configuration Service Integration - Implementation Summary

## Overview

Implemented comprehensive keys configuration management system with RKI (Retail Key Injection) integration for automatic key generation and distribution to devices. The system manages keys.json file creation with comprehensive KCV (Key Check Value) tracking for easy maintenance and key change management.

---

## Architecture Flow

```
AutoPushService (Scenario 1: Missing Versions)
    ↓
push_device_setup_configs("keys_config")
    ↓
KeysConfigService.generate_and_store_keys_file(serial_number, model)
    ├─ Step 1: Call RKI Endpoint
    │  └─ HTTP POST to getRki with device parameters
    │     Request: {serialNumber, model, kekKcv, slotNumber}
    │     Response: {rkiKey, rkiKcv, slotNumber}
    │
    ├─ Step 2: Create keys.json with full configuration
    │  └─ {
    │       "rki_key": "XA9A9A23CD841F63D20D1B17F24BED2CF",
    │       "rki_kcv": "CB9DEA",
    │       "kek_kcv": "112233",
    │       "slot_number": 1,
    │       "serial_number": "1234567890",
    │       "model": "MF919",
    │       "vendor": "MoreFun",
    │       "created_at": "2025-01-31T15:00:00Z",
    │       "expires_at": "2026-01-31T15:00:00Z"
    │     }
    │
    ├─ Step 3: Store file at priv/ota/{serial_number}/keys.json
    │
    └─ Step 4: Return download URL
         └─ http://demo.ctrmv.com/ota/{serial_number}/keys.json
             ↓
AutoPushService sends to MQTTCommandBuilder
    ↓
MQTTCommandBuilder.build_mf919_command({
  "command_type": "LOAD_KEYS",
  "request_id": "req-1237",
  "url_path_from_download": "http://demo.ctrmv.com/ota/1234567890/keys.json"
})
    ↓
MQTT Payload (Consistent Format):
{
  "type": "tms_command",
  "command": "LOAD_KEYS",
  "requestId": "req-1237",
  "downloadUrl": "http://demo.ctrmv.com/ota/1234567890/keys.json"
}
    ↓
Device downloads keys.json and applies configuration
```

---

## Database Changes

### Migration 3: Add Keys Configuration Fields to TmsTerminal

File: `priv/repo/migrations/20250131000003_add_keys_config_fields_to_tms_terminals.exs`

**New Columns:**
```sql
ALTER TABLE tms_terminals ADD COLUMN kek_kcv VARCHAR(255) DEFAULT '112233';
ALTER TABLE tms_terminals ADD COLUMN slot_number INTEGER DEFAULT 1;
ALTER TABLE tms_terminals ADD COLUMN last_keys_update DATETIME;

CREATE INDEX idx_tms_terminals_kek_kcv ON tms_terminals(kek_kcv);
CREATE INDEX idx_tms_terminals_slot_number ON tms_terminals(slot_number);
```

**Schema Updates:** [TmsTerminal Schema](../terminal_management/tms_terminal.ex)
- Added `kek_kcv` field to store Key Encryption Key Check Value
- Added `slot_number` field to store key slot information
- Added `last_keys_update` to track last keys update timestamp
- All fields included in JSON encoder

---

## New Service: KeysConfigService

File: `lib/da_product_app/terminal_management/keys_config_service.ex`

### Public API

#### `generate_and_store_keys_file(serial_number, model)`
```elixir
def generate_and_store_keys_file(serial_number, model) when is_binary(serial_number) and is_binary(model) do
  # Returns: {:ok, download_url, file_path} or {:error, reason}
end
```

**Flow:**
1. Retrieve terminal from database with kek_kcv and slot_number
2. Call getRki endpoint with device parameters
3. Create keys.json with complete configuration (rki_key, rki_kcv, kek_kcv, etc.)
4. Store file at `priv/ota/{serial_number}/keys.json`
5. Return download URL for MQTT command

**Keys.json Structure:**
```json
{
  "rki_key": "XA9A9A23CD841F63D20D1B17F24BED2CF",
  "rki_kcv": "CB9DEA",
  "kek_kcv": "112233",
  "slot_number": 1,
  "serial_number": "1234567890",
  "model": "MF919",
  "vendor": "MoreFun",
  "created_at": "2025-01-31T15:00:00Z",
  "expires_at": "2026-01-31T15:00:00Z"
}
```

#### `get_keys_file(serial_number)`
```elixir
def get_keys_file(serial_number) when is_binary(serial_number) do
  # Returns: {:ok, keys_map} or {:error, reason}
end
```

Retrieves stored keys.json for a device.

### HTTP Integration

**RKI Endpoint:** `http://localhost:8300/api/v1/getRki`

**Request:**
```json
{
  "serialNumber": "1234567890",
  "model": "MF919",
  "kekKcv": "112233",
  "slotNumber": 1
}
```

**Response:**
```json
{
  "serialNumber": "1234567890",
  "rkiKey": "XA9A9A23CD841F63D20D1B17F24BED2CF",
  "rkiKcv": "CB9DEA",
  "slotNumber": 1
}
```

---

## AutoPushService Enhancements

File: `lib/da_product_app/terminal_management/auto_push_service.ex`

### Updated Functions

#### `push_device_setup_configs/4` - Refactored
```elixir
defp push_device_setup_configs(serial_number, terminal, vendor, model) do
  config_types = ["emv_config", "keys_config", "application"]
  
  Enum.each(config_types, fn config_type ->
    case config_type do
      "keys_config" ->
        # Special RKI + keys.json generation
        push_keys_config(serial_number, terminal, vendor, model)
      
      _ ->
        # Regular config push
        push_regular_config(serial_number, terminal, vendor, model, config_type)
    end
  end)
end
```

#### `push_keys_config/4` - New
Handles RKI integration and keys.json generation:
- Calls `KeysConfigService.generate_and_store_keys_file/2`
- Creates parameter_push_logs entry with file metadata
- Updates terminal's `last_keys_update` timestamp
- Sends MQTT command with keys.json download URL

#### `push_regular_config/5` - New
Handles emv_config and application pushes.

#### `send_mqtt_keys_config/4` - New
```elixir
defp send_mqtt_keys_config(serial_number, vendor, model, request_id, download_url) do
  # Use MQTTCommandBuilder for device-specific format
  command_params = %{
    "command_type" => "LOAD_KEYS",
    "request_id" => request_id,
    "url_path_from_download" => download_url
  }
  
  case MQTTCommandBuilder.build_command(model, command_params) do
    {:ok, mqtt_payload} ->
      # Publish consistent MQTT format
  end
end
```

#### `send_mqtt_parameter_push/5` - Updated
Now uses `MQTTCommandBuilder.build_command/2` for device-specific formatting.

#### `send_mqtt_config_push/5` - Updated
Now uses `MQTTCommandBuilder.build_command/2` with `command_type_for_config/1`.

#### Helper Functions - New
```elixir
defp command_type_for_config("emv_config"), do: "UPDATE_L3_CONFIG"
defp command_type_for_config("keys_config"), do: "LOAD_KEYS"
defp command_type_for_config("application"), do: "UPDATE_APPLICATION"

defp get_file_size(file_path) do
  # Returns file size for logging
end

defp calculate_checksum(file_path) do
  # SHA256 checksum for integrity verification
end
```

---

## MQTTCommandBuilder Integration

File: `lib/da_product_app/terminal_management/mqtt_command_builder.ex` (Extended)

### Device-Specific Format Support

#### MF919 LOAD_KEYS Command
```json
{
  "type": "tms_command",
  "command": "LOAD_KEYS",
  "requestId": "req-1237",
  "downloadUrl": "http://demo.ctrmv.com/ota/1234567890/keys.json"
}
```

#### MF919 UPDATE_PARAMS Command
```json
{
  "type": "tms_command",
  "command": "UPDATE_PARAMS",
  "requestId": "req-1237",
  "downloadUrl": "http://demo.ctrmv.com/ota/params.zip"
}
```

#### SR600 file_download Command (Existing)
```json
{
  "command": "file_download",
  "local_path_to_save": "/config",
  "url_path_from_download": "http://...",
  "file_size": 1024,
  "file_category": "keys",
  "file_name": "keys.json",
  "request_id": "req-1237"
}
```

---

## Configuration

File: `config/config.exs`

```elixir
config :da_product_app,
  rki_endpoint: "http://localhost:8300/api/v1/getRki",
  ota_base_url: "http://demo.ctrmv.com/ota",
  ota_storage_path: "priv/ota",
  rki_timeout: 10_000,
  mqtt_product_key: "pFppbioOCKlo5c8E"
```

**Environment-specific overrides in `dev.exs` or `prod.exs`:**
```elixir
config :da_product_app,
  rki_endpoint: System.get_env("RKI_ENDPOINT", "http://localhost:8300/api/v1/getRki"),
  ota_base_url: System.get_env("OTA_BASE_URL", "http://demo.ctrmv.com/ota")
```

---

## File Storage Structure

```
priv/ota/
├── 1234567890/
│   └── keys.json                 (Generated keys configuration)
├── 61250904380091/
│   └── keys.json
└── ...
```

**Directory Permissions:** Auto-created with File.mkdir_p/1

---

## ParameterPushLog Tracking

Each keys push creates a log entry with:
- `config_type`: "keys_config"
- `file_path`: Full path to generated keys.json
- `file_size`: Size of keys.json file
- `checksum`: SHA256 hash for integrity verification
- `device_vendor`, `device_model`: Device identifiers
- `trigger_reason`: "missing_version"
- `status`: "pending" (updated on device ACK)

---

## Error Handling

### RKI Endpoint Failures
- HTTP timeout (10 seconds)
- Non-200 status codes
- Invalid JSON response
- Network errors

**Recovery:**
- Log error with full context
- Skip keys push, continue with other configs
- Operator can retry via UI

### File Operations
- Directory creation failures
- File write failures
- Checksum calculation errors

**Recovery:**
- Log error
- Return error status
- Mark push log as failed

---

## Testing Scenarios

### Scenario 1: Happy Path
1. Device reports missing keys_config version
2. AutoPushService triggers
3. KeysConfigService calls getRki endpoint
4. keys.json generated and stored
5. MQTT command sent with download URL
6. Device downloads and applies config

### Scenario 2: RKI Endpoint Unavailable
1. Device reports missing keys_config version
2. KeysConfigService fails to call getRki
3. Error logged
4. Other configs (EMV, Application) continue
5. Operator can retry keys push later

### Scenario 3: Device-Specific Format
1. MF919 device: Receives tms_command format with LOAD_KEYS
2. SR600 device: Receives file_download format
3. Each device gets format it understands

---

## Advantages of This Approach

✅ **Centralized MQTT Format Management** - MQTTCommandBuilder is single source of truth
✅ **KCV Retention** - Both rki_kcv and kek_kcv stored for audit trail
✅ **File-Based Configuration** - keys.json can be versioned and managed
✅ **Device-Specific** - Supports MF919, SR600, Kozen with different formats
✅ **Audit Trail** - All push operations tracked with file metadata
✅ **Easy Key Rotation** - Change kek_kcv on terminal, next auto-push generates new RKI
✅ **Checksum Verification** - SHA256 for integrity checking
✅ **Configuration Expiry** - 1-year validity tracking

---

## Next Steps

### Phase 2: Version Mismatch Detection
- Compare current device versions with latest available
- Auto-push outdated versions
- Scheduled version management

### Phase 3: Push Acknowledgment
- Monitor device ACK messages
- Update push log status
- Retry failed pushes

### Future: Key Rotation Management
- Track key expiry dates
- Schedule proactive key refresh
- Support key revocation

---

## Files Modified/Created

**New Files:**
- `lib/da_product_app/terminal_management/keys_config_service.ex` (121 lines)
- `priv/repo/migrations/20250131000003_add_keys_config_fields_to_tms_terminals.exs`

**Modified Files:**
- `lib/da_product_app/terminal_management/auto_push_service.ex` - Refactored for MQTTCommandBuilder integration
- `lib/da_product_app/terminal_management/tms_terminal.ex` - Added kek_kcv, slot_number, last_keys_update
- `config/config.exs` - Added RKI and OTA configuration

---

**Implementation Version:** 1.0  
**Date:** 2025-01-31  
**Status:** Ready for Phase 1 Deployment
