# UCM6301 Authenticated REC Transport

## Proven protocol

The local recording transport uses JSON `POST <base_url>/api`. Authentication follows the existing challenge/login flow, and the returned cookie remains inside the JSON request object. The REC request action is `recapi`.

A listing request supplies only a documented recording category such as `monitor`. Firmware 1.0.33.30 returned an attachment with `Content-Type: text/csv` and separate `Directory` and `Filename` columns. A WAV request supplies the exact validated category and basename from that authenticated listing. The proven response was HTTP 200, `audio/x-wav`, an attachment, and a body with valid `RIFF` and `WAVE` markers.

CDR `recordfiles` metadata can refer to recordings absent from the current authenticated listing. Catalog correlation therefore requires one exact listing basename in the selected category. It never guesses a `YYYY-MM` conversion, strips or adds a directory, or tries alternate basenames.

## Components

- `ami/lib/UcmHttpsApiClient.php` owns the private cookie, authentication, one documented `-6` reauthentication, and bounded authenticated response streaming.
- `ami/lib/UcmRecApiTransport.php` parses validated CSV listings and streams exact listing-derived WAV responses.
- `ami/lib/UcmRecordingCatalog.php` maps a safe resolver path basename to exactly one listing entry without path transformations.
- `tools/ucm_rec_transport_probe.php` provides a database-free listing summary and an explicit physical-row WAV test.

The JSON API method remains strict: it still requires `application/json`, buffers only bounded JSON, and does not accept binary responses. The separate streaming path prevents JSON error bodies and unsupported MIME types from being written to an accepted destination. WAV validation buffers only the first 12 bytes until `RIFF` and `WAVE` are confirmed; the remaining response streams directly to the supplied resource.

The destination owner must delete or truncate partial output if a later transport or size failure occurs. The diagnostic CLI always uses a mode-600 temporary file and deletes it in `finally`. No audio is persistently stored.

## Security boundaries

Directories use an explicit local allowlist. A recording filename must be a basename, contain no slash, backslash, parent traversal, null/control byte, URL scheme, query, or fragment, and end in `.wav` case-insensitively. CSV and audio sizes, connection time, and total request time are bounded. Redirects are not followed. Exceptions report only operation and status classes; they do not include cookies, credentials, paths, filenames, response error text, or Content-Disposition values.

The UCM ignored `Range: bytes=0-1023`: it returned HTTP 200 without `Accept-Ranges` or `Content-Range`. This implementation sends no Range header, claims no seeking support, emits no range headers, and performs no local caching. A future browser proxy must deliberately reject or ignore browser Range requests and return a full HTTP 200 stream.

No UCM credentials or direct UCM URL belong in a browser. This phase creates no browser endpoint, performs no database access or `recordingurl` update, and does not modify the AMI listener.

## Diagnostic usage

Listing summary only:

```bash
php tools/ucm_rec_transport_probe.php --list --filedir=monitor
```

Explicit physical CSV row test:

```bash
php tools/ucm_rec_transport_probe.php --row=2094 --filedir=monitor
```

Rows are revalidated on every run. The row test stops if the requested physical row is no longer a valid unique WAV listing entry. Output contains only counts, a masked filename pattern, sanitized response metadata, a short hash prefix, and temporary-file deletion status.
