# OTAMan — SIM OTA toolkit: PWA + local card server OTAMan is an offline HTML/JS PWA for building APDU commands (SIM, USIM, GlobalPlatform RAM), assembling SCP80 secured packets per ETSI TS 102 225, and constructing Expanded Remote Application data format APDU per ETSI TS 102 226. A bundled [`pysim-otaman-server`](pysim_otaman_server/) exposes a local HTTP API over pySim for live card operations: file manager, raw APDU, SIM Toolkit menu browsing, and OTA (SCP80) delivery. **Demo:** [otaman.atroshin.ru](https://otaman.atroshin.ru) — the PWA alone, for experimenting. Install the server (below) for card-reader functions. ## Quick start **PWA only (client-side tools):** open `frontend/index.html` in any browser, or serve `frontend/` with any static server. No Python required. **Full (PWA + card server):** ```sh git clone https://github.com/anttro/otaman.git cd otaman ./setup.sh # or setup.bat on Windows — creates .venv, installs pysim + server ./start.sh # or start.bat — starts the server (it serves the PWA too) ``` Then open http://127.0.0.1:8080 — the UI and API share one origin, so no CORS or browser-permission setup is needed. ## Build Tailwind CSS is used for styling. After cloning, rebuild the CSS: ```sh cd frontend npm install npm run build ``` ## Interface Five top-level tabs: **Remote APDU**, **SCP80**, **Profiler**, **Card reader**, and **Phone simulator**. **Remote APDU** and **SCP80** use pill sub-tabs; the Card reader tab has three sub-tabs: **File manager**, **pySim command line**, and **Raw APDU**; the Profiler tab lists **Profiles**, **Card snapshots**, and **Custom files**. --- ## Remote APDU tab Builds command APDUs (C-APDUs). Seven sub-tabs cover different card generations, command sets and decoding tools: **SIM RFM**, **USIM RFM**, **Expanded Script**, **RAM/GP**, **HTTP OTA**, **C-APDU Parser**, and **Response parser**. ### SIM RFM CLA = `A0` (GSM 11.11 / ISO 7816-4). #### Commands | Command | INS | Description | |---|---|---| | SELECT | A4 | Select EF/DF by FID, path, dfname, or chain | | UPDATE RECORD | DC | Update a record in a record-oriented EF | | UPDATE BINARY | D6 | Update binary content at an offset | | READ RECORD | B2 | Read a record | | READ BINARY | B0 | Read binary content | | ERASE BINARY | 0E | Erase binary at an offset | | ACTIVATE FILE | 44 | Activate a file | | DEACTIVATE FILE | 04 | Deactivate a file | | VERIFY PIN | 20 | Verify PIN1 or PIN2 | | CHANGE PIN | 24 | Change PIN1 or PIN2 | #### SELECT methods | Method | P1 | P2 | Input | |---|---|---|---| | By FID | 00 | 00 | 2-byte FID (4 hex) | | By full path from MF | 08 | 00 | Full path hex from MF | | By DF name / AID | 04 | 00 | AID (application ID) | | ADF RFM chain | 00 | 00 | Comma-separated FIDs, each selected in turn | #### Options - **Start with SELECT** — checkbox to prepend a SELECT command before the operation. When unchecked, the operation is sent standalone with CLA. - **Selection mode (P2)** — for record commands: Absolute (04), Next (06), Previous (02). - **Record size** — pad/truncate data to the specified byte count. - **Allow P1/P2 editing** — checkbox to enable manual override of P1/P2 bytes. #### References - ISO/IEC 7816-4: Organization, security and commands for interchange - ETSI TS 102 226: Remote APDU structure for UICC based applications - GSM 11.11: SIM-ME Interface ### USIM RFM CLA = `00` (ETSI TS 102 221). Same commands as SIM, but SELECT uses P1=09, P2=0C (by FID from current directory). #### References - ETSI TS 102 221: UICC-Terminal Interface; Physical and Logical Characteristics - ETSI TS 102 226: Remote APDU structure for UICC based applications ### Expanded Script Builds Expanded Remote Application data format per ETSI TS 102 226 §5.2.1. #### Format Two encoding variants: - **Definite (AA)**: `AA` + length + Command TLVs - **Indefinite (AE)**: `AE` + `80` + Command TLVs + `00 00` #### Command TLVs | Type | Tag | Description | |---|---|---| | C-APDU | 22 | Raw APDU hex | | Immediate Action | 81 | Proactive command or action indicator | | Error Action | 82 | Proactive command on error | | Script Chaining | 83 | Chaining data for multi-packet scripts | #### Immediate Action builder When the type is set to Immediate Action, the tool provides a structured builder for: - **Action indicator**: `81` (Proactive session indication) / `82` (Early response) - **Proactive command**: REFRESH, DISPLAY TEXT, or PLAY TONE — with auto-generated COMPREHENSION-TLV data objects (command details, device identities, text string, tone, etc.) - **Custom hex**: freeform input for manual TLV construction Error Action supports the same builder (DISPLAY TEXT, PLAY TONE). #### References - ETSI TS 102 226 V13.0.0 §5.2.1: Expanded Remote Application data format - ETSI TS 102 223: Card Application Toolkit (CAT) — proactive command structure - ETSI TS 101 220: BER-TLV tag assignments ### RAM/GP CLA = `80` (GlobalPlatform Card Specification v2.3.1). Remote Application Management commands for card content management. #### GP Commands Reference | Command | INS | P1 | Description | |---|---|---|---| | INSTALL [for load] | E6 | 02 | Register a load file for loading | | INSTALL [for install] | E6 | 0C | Install an application or SD | | INSTALL [for make selectable] | E6 | 10 | Make an application selectable | | INSTALL [for registry update] | E6 | 01 | Update registry entries | | INSTALL [for extradition] | E6 | 04 | Extradition (move between SDs) | | LOAD | E8 | 00 | Load executable code blocks | | DELETE | E4 | 00/80 | Delete application or SD | | GET STATUS | F2 | 80/40/20/10 | Get card status | | GET DATA | CA | tag | Read card data objects | | STORE DATA | E2 | 00/40/80/C0 | Store data (key, certificate, etc.) | | SET STATUS | F0 | 80/40/60 | Lifecycle state management | | EXTERNAL AUTHENTICATE | 82 | 00 | SCP host authentication | | INTERNAL AUTHENTICATE | 88 | 00 | Card challenge-response | #### INSTALL [for install] — Privilege Builder Tag `C7` in the INSTALL data field. Built from 3 privilege bytes (GP spec Tables 11-7, 11-8, 11-9): **Byte 1** (bits): | Bit | Privilege | |---|---| | b8 | Security Domain | | b7 | DAP Verification | | b6 | Delegated Management | | b5 | Card Lock | | b4 | Card Terminate | | b3 | Card Reset | | b2 | CVM Management | **Byte 2** (bits): | Bit | Privilege | |---|---| | b8 | Trusted Path | | b7 | Authorized Management | | b6 | Token Verification | | b5 | Global Delete | | b4 | Global Lock | | b3 | Global Registry | | b2 | Final Application | **Byte 3** (bits): | Bit | Privilege | |---|---| | b8 | Receipt Generation | #### INSTALL [for install] — SIM/UICC Toolkit Parameters Optional TLV objects appended to the INSTALL data field: - **Tag `CA`** (SIM Toolkit): Priority, Timers, Text Length, Menu Entries, Menu Positions, Channels, MSL, TAR, Access Domain - **Tag `80`** (UICC Toolkit, inside `EA`): Same fields minus Access Domain **MSL (Minimum Security Level)** — SPI1 byte per TS 102 225: | Value | Meaning | |---|---| | 00 | No check | | 11 | RC/CC/DS | | 12 | RC/DS/CC | | 15 | RC/DS/CC + MAC | | 16 | RC/DS/CC + MAC + Cipher | | 19 | RC/DS/CC + MAC + Cipher + DS | #### GET STATUS P1 values | Value | Meaning | |---|---| | 80 | Issuer Security Domain (ISD) | | 40 | Applications and Supplementary Security Domains | | 20 | Executable Load Files | | 10 | ELF and their Executable Modules | #### GET STATUS P2 values | Value | Meaning | |---|---| | 40 | First/all occurrences, GP TLV format (default) | | 42 | Next occurrence, GP TLV format | | 00 | First/all, old format (deprecated) | | 02 | Next, old format (deprecated) | #### GET DATA tag values | Tag | Data Object | |---|---| | 42 | Issuer Identification Number (IIN) | | 45 | Card Image Number (CIN) | | 66 | Card Data / SD Management Data | | 67 | Card Capability Information | | E0 | Key Information Template | | D3 | Current Security Level | | 2F00 | List of Applications (ISO 7816-4) | | FF21 | Extended Card Resources Info | | 5F50 | SD Manager URL | | C1 | Sequence Counter (SCP02/03) | | C2 | Confirmation Counter | | 7F21 | Certificate (SD public key) | | 5031 | Certificate info (EF.OD) | #### DELETE P1 values | Value | Meaning | |---|---| | 00 | By AID | | 80 | Delete associated objects | #### STORE DATA P1 values | Value | Meaning | |---|---| | 00 | Last block, no encryption | | 40 | More blocks, no encryption | | 80 | Last block, encrypted | | C0 | More blocks, encrypted | #### SET STATUS parameters **P1 (Status Type)**: | Value | Target | |---|---| | 80 | Issuer Security Domain | | 40 | Application or Supplementary Security Domain | | 60 | Security Domain and its associated Applications | **P2 (State)**: | Value | Action | |---|---| | 00 | Unlock (return to previous state) | | 80 | Lock (LOCKED state) | #### References - GlobalPlatform Card Specification v2.3.1 (GPC_Spec_v2.3.1): Commands, Privileges, TLV structures - ETSI TS 102 226 V13.0.0 §8.2.1.3.2: SIM/UICC Toolkit parameters, MSL, TAR, Access Domain ### Conversion (SIM/USIM sidebars) Value encoding conversions embedded in the SIM RFM and USIM RFM tabs. #### IMSI → EF.IMSI Per TS 31.102 §4.2.3. Encodes a 15-digit IMSI into the 9-byte EF.IMSI format: - Byte 0: number of subsequent bytes (8) - Odd/even indicator nibble in the last byte - BCD digits, swapped nibble pairs per identity Input: 15 decimal digits. Output: 18 hex characters. #### MSISDN → BCD Strips leading `+`, pads odd length with `f`, swaps nibble pairs. #### ICCID → hex Swaps nibble pairs of the ICCID string. #### Provider Name → SPN Per 3GPP TS 31.102 §4.2.5 (EF_SPN). Three encoding paths: 1. **GSM 7-bit packed** (all chars in GSM 7-bit default alphabet): prefix `01`, DCS byte (spare bits), packed septets, 0xFF padding to 16 bytes. 2. **UCS2 non-BMP** (emoji / chars > U+FFFF): prefix `00`, DCS `80`, UTF-16BE, 0xFF padding to 16 bytes. 3. **UCS2 BMP non-GSM7** (Cyrillic, etc.): prefix `00`, DCS `81`, base byte, per-char offsets, 0xFF padding to 16 bytes. GSM 7-bit alphabet per 3GPP TS 23.038. Full extension table supported. #### PLMN → EF_PLMNsel / PLMNwAcT Per TS 31.102 §4.2.3. 3-byte BCD encoding for PLMN, plus optional 2-byte Access Technology selector. #### Nibble swap Swaps nibble pairs of an even-length hex string. #### References - 3GPP TS 31.102: Characteristics of the USIM Application - 3GPP TS 23.038: Alphabets and language information - ETSI TS 102 225: Secured packet structure for (U)SIM toolkit - pySim: enc_imsi() implementation ### C-APDU Parser Pastes raw APDU hex and renders a collapsible tree. It auto-detects the container: an **Expanded Script** (leading `AA` or `AE80`, decoded per ETSI TS 102 226 §5.2.1) or a **Compact C-APDU chain** (a sequence of ISO 7816 C-APDUs). Each node shows its label, hex, and a short description; parent nodes expand to reveal their sub-elements. ### HTTP OTA Builds the Remote Application Management over HTTP payloads defined in GlobalPlatform **GPC v2.2 Amendment B v1.1** (§4.7). Two modes: - **Trigger (Push SMS)** — administration session triggering parameters (`81 > 83 > 84/[85]/[86]/89`, Table 4-3). This is the message that asks the card's Security Domain to dial out and start an HTTP session. - **Store (SD admin params)** — writes the same parameters as card (Security Domain) data via **STORE DATA in TLV mode** (`80 E2 90 00`, P1=90 = last block + BER-TLV per GP v2.2 Amendment B v1.1.3), wrapped in tag `85` (or `A5`) per Table 4-4. | Section | Tag | Contents | |---|---|---| | Connection parameters | `84` | COMPREHENSION-TLVs needed to open the TCP connection (OPEN CHANNEL per TS 102 223): Device Identities `02`, Alpha `80`, Bearer `01`, vendor TLVs. Row editor + presets, editable hex. | | Security parameters | `85` | Table 4-6: LV PSK Identity (text), LV Key version/KID. Identifies the PSK TLS key (RFC 4279). | | Retry policy | `86` | Table 4-7: retry counter (2 bytes, e.g. `B000`), retry waiting delay as the TS 102 223 timer TLV (`25 03 HH MM SS`), optional vendor-specific report-failure TLV. | | HTTP POST | `89` | Tables 4-8/9/10: Host header (`8A`), X-Admin-From agent ID (`8B`), URI (`8C`) — text converted to octets. | The **Command Scripting template** checkbox wraps the whole `81` triggering command in the definite-length Expanded Remote Application data format (`AA`, ETSI TS 102 226 §5.2.1) for TARs that process the expanded format. **Pack into Secured packet** sends the built payload to the SCP80 tab for SPI/counter filling — insert the TAR the SD listens on (typically the OTASD TAR) there. --- ### Response parser Decodes a raw command response: pick the command that was sent, enter the SW (e.g. `9000`) and the response data hex, then press **Decode**. - **Command** — SIM/USIM group (SELECT, STATUS, READ/UPDATE, PIN ops, CAT commands like TERMINAL PROFILE/ENVELOPE/FETCH/TERMINAL RESPONSE, MANAGE CHANNEL, ...) or RAM/GP group (INSTALL, LOAD, DELETE, GET/STORE DATA, auth, SCP commands). - **SW decode** — status words resolved against generic, UICC (TS 102 221), and GlobalPlatform maps, with context auto-detected. - **Privilege decode** — GET DATA / INSTALL response payloads decode the privilege bytes into human-readable flags. - **Response data** — raw hex rendered and interpreted per command (e.g. SELECT FCP templates). --- ## SCP80 tab The **SCP80** top-level tab groups SCP80-related views, switched by three pills: **Secured Packet**, **Cards**, and **RAM**. Assembles secured packets per ETSI TS 102 225. ### Secured Packet Builds SCP80 secured packets per ETSI TS 102 225. #### Packet structure | Field | Size | Description | |---|---|---| | CPI | 1 | Command Packet Identifier (`02`) | | CPL | 1 | Command Packet Length | | CHI | 1 | Command Header Identifier (`01`) | | CHL | 1 | Command Header Length | | SPI | 2 | Security Parameter Indicator | | KIc | 1 | Key Identifier for ciphering | | KID | 1 | Key Identifier for MAC | | TAR | 3 | Toolkit Application Reference | | CNTR | 5 | Replay counter | | PCNTR | 1 | Padding counter | | RC/CC/DS | 8 | Cryptographic Checksum / MAC | | Secured Data | variable | Padded APDU (encrypted if required) | #### SPI1 (Security Level) SPI1 bit layout (TS 102 225 §5.1.1): `b8–b6` padding, `b5–b4` counter, `b3` ciphering, `b2–b1` RC/CC/DS. | Value | Security | Ciphering | Counter (b5 b4) | |---|---|---|---| | 00 | None | No | 00 none | | 01 | RC | No | 00 none | | 02 | CC/MAC | No | 00 none | | 06 | CC/MAC | Yes | 00 none | | 0A | CC/MAC | No | 01 available | | 0E | CC/MAC | Yes | 01 available | | 12 | CC/MAC | No | 10 higher | | 16 | CC/MAC | Yes | 10 higher | | 1A | CC/MAC | No | 11 +1 | | 1E | CC/MAC | Yes | 11 +1 | > **AES requires `b5 b4 = 10` (higher) or `11` (+1)** per TS 102 225 §5.1.2 and §5.1.3.1. > The 3DES values `00/01/02/06` (no counter) remain valid for 3DES only. #### SPI2 (PoR settings) | Value | Mode | Security | Cipher | |---|---|---|---| | 00 | No PoR | — | No | | 01 | PoR required | None | No | | 05 | PoR required | RC | No | | 09 | PoR required | CC | No | | 0D | PoR required | DS | No | | 11 | PoR required | None | Yes | | 02 | PoR on error | None | No | | 06 | PoR on error | RC | No | #### Crypto - **3DES-CBC** encryption (zero ICV), supporting 8, 16, and 24 byte keys — deprecated since Rel-18, still supported for backwards compatibility - **AES-CBC** encryption (zero ICV, zero-padded to 16), supporting 16, 24, and 32 byte keys (TS 102 225 §5.1.2, KIc `x2`) - **Retail MAC** (ISO 9797-1 MAC algorithm 3) for the DES/3DES cryptographic checksum - **AES-CMAC** (NIST SP 800-38B, truncated to 8 octets) for the AES cryptographic checksum (TS 102 225 §5.1.3.1, KID `x2`) - Padding byte configurable (`00` per TS 102 225 default, or `FF`) #### PoR (Proof of Reception) PoR confirms the card received and executed the secured packet. Two modes: | SPI2 (bit 5) | Mode | Description | |---|---|---| | `0x00` | Delivery PoR | PoR is returned in the ENVELOPE response SW+data | | `0x20` | Submit PoR | PoR is sent back as an SMS-SUBMIT via a proactive FETCH command | Delivery PoR (SPI2 `01`) is simpler — the card returns the PoR directly in the ENVELOPE response. Submit PoR (SPI2 `21`) is used when the card cannot respond inline (e.g. during ELF operations where the ENVELOPE response space is limited). #### References - ETSI TS 102 225 V18.1.0: Secured packet structure for UICC based applications - ETSI TS 102 226: Remote APDU structure for UICC based applications - ISO 9797-1: MAC algorithms - NIST SP 800-38B: CMAC ### Cards Stores saved card configurations (presets). Each preset stores the cryptographic keys, SPI settings, TAR, and replay counter needed for SCP80 operations. | Field | Description | |---|---| | SPI1 / SPI2 | Security level and PoR settings | | KIc / KID key | Encryption and MAC key hex | | KIc / KID index | Key version number | | TAR | Toolkit Application Reference (3 bytes) | | Counter (CNTR) | 10-digit hex replay counter, auto-incremented after each successful SCP80 send | **Add a card:** fill in the name, SPI1/SPI2, KIc/KID keys and indices, TAR, and click **Add**. The card appears in the list and becomes available in the RAM tab's **Card preset** dropdown. **Edit a card:** click a card in the list, modify fields, click **Save**. **Delete a card:** select a card, click **Delete**. Removes the preset from `localStorage`. **Counter:** the 10-digit hex counter (CNTR) is auto-incremented after each successful SCP80 send (both manual Secured Packet sends and RAM operations). The updated counter is saved back to the preset automatically. ### RAM All RAM operations are delivered as SCP80 secured packets (ETSI TS 102 225) via SMS-PP-DOWNLOAD ENVELOPE. The card must support SCP03 (AES or 3DES) for secure transport. Select a saved card configuration from the **Card preset** dropdown. If no preset is selected, the RAM tab warns and refuses to execute. The RAM subtab offers two operations selected from the **Operation** dropdown: | Operation | Description | |---|---| | **Explore Card (all GP data)** | Queries GET STATUS for ISD, Applications, ELFs, and ELF Modules, plus GET DATA FF21 for memory info. Results appear in an explorer view with per-item **Delete** buttons. | | **Install Package (.cap file)** | Sends a `.cap` file to the card via the server: INSTALL\[for load\] → LOAD ×N → INSTALL\[for install (+make selectable)\]. | #### Explorer View After "Explore Card" runs, the explorer view displays: - **ISD** — AID, lifecycle, privileges (no delete; the ISD cannot be removed) - **Applications** — AID, lifecycle, privileges, associated ELF/SD. Each has a **Delete** button (GP `DELETE` by AID). - **Executable Load Files** — AID, lifecycle, version, module AIDs. Each has **Delete** (ELF only) and **Delete All** (cascade: ELF + modules + installed Applications, P2=0x80) buttons. Delete confirms via a browser prompt before sending the GP `DELETE` command via SCP80. The explorer auto-refreshes after a successful deletion. --- ## Card Reader (pySim integration) Connects to the bundled [`pysim-otaman-server`](pysim_otaman_server/) for live card operations. > **Browser restriction:** when the PWA is served from a public HTTPS host, reaching the local server (`http://127.0.0.1:8080`) requires two things: the server must send `Access-Control-Allow-Private-Network: true` (pysim-otaman-server ≥ 1.6.1 does this automatically), and the browser must be allowed to access the local network — in Chrome/Edge/Vivaldi: Site settings → Local network access → allow the site (or accept the permission prompt). Without the browser permission, the request to `127.0.0.1` is blocked before any preflight is sent. ### File Browser Browse the UICC filesystem in a tree view. Files are shown with names, FIDs, and AIDs (for ADFs). Click to read contents. - Entries are grouped with DFs above EFs and sorted by **FID** or symbolic **Name** (pills above the tree, remembered in `localStorage`) - **Read** — reads the selected file (auto-detects transparent vs record files) - **Edit** — switch to edit mode, modify hex data, click **Save** to write back - **Raw / Decoded** — toggle between hex dump and pysim-decoded JSON view - Selecting a file shows its FID, file type, size / record layout and the decoded FCI above the contents - Missing files are shown in red (✗); a present but empty DF shows `(empty)` - **Probe all files** — walks the whole tree (incl. custom files), marks every entry present/absent with *N / total* progress, stoppable, and ends with a summary; browsing itself stays lazy ### Command Hints Type a command name in the **pySim command line** input. Usage hints appear as a tooltip after 300ms. Command autocomplete suggestions appear above the input. --- ## Profiler Verifies that a card matches a named **profile** — an ordered set of rules describing the expected file system and, optionally, file contents. Profiles are stored in `localStorage`. - **New profile** creates an empty ruleset; **Profile from card** scans the equipped card and generates one rule per existing file; **Import profile** loads a ruleset from JSON (the name is stored inside the file). - Each profile row has **Check card ▶** (run against the equipped card), **Check card snapshot** (run offline against a saved snapshot), **Edit**, **Export**, and **Delete**. A filesystem rule is defined by: - **Path** — `MF`-rooted (e.g. `MF/7F10/6F3A`) or ADF AID-rooted (e.g. `A0000000871002/6F07`). - **FCP/FCI check** — **Filetype only (FCP)**, **Filetype + size (FCP)** (adds file size, or record length/count for record files), or **Exact FCI** (byte-for-byte comparison of the raw SELECT FCP template `'62'`, catching FID/AID, life-cycle status, security-attribute, and proprietary-parameter changes). - **File attributes** — file type, size, record length and record count, taken from the FCP template (any may be left unset). - **Check contents** (optional) — **Exact** hex equality, or **Mask** where `?` is a per-nibble wildcard (a mask with no `?` is a prefix match, e.g. `0891` for the IMSI MCC/MNC). Record files store a per-record list. The check report marks each verified aspect (e.g. *filetype ✓, size ✗, contents ✓*), lists mismatches as read-only monospace expected/actual fields aligned in one column, and shows a decoded per-parameter FCI comparison for FCI mismatches. Corrupt FCI data shows whatever decoded before the faulty part plus an explicit decode-failure note; record mismatches list the *matching records*. **Only mismatches** in the results header hides all passing files and keeps failures and errors only. #### “Profile from card” scan options The scan dialog asks for a profile name and offers the FCP/FCI mode described above, an **Ignore contents of files** checklist of frequently-overwritten files (all checked by default except `EF.ARR`; the header checkbox toggles the whole list) — `EF.LOCI`, `EF.PSLOCI`, `EF.EPSLOCI`, `EF.5GS3GPPLOCI`, `EF.Keys`, `EF.KeysPS`, `EF.SMS`, `EF.Kc`, `EF.KcGPRS`, `EF.LOCIGPRS`, `EF.CBMID`, `EF.SMSS`, `EF.ACC`, `EF.EPSNSC`, `EF.START-HFN`, `EF.ARR` — and two checked-by-default mask options that capture only the first 4 bytes of `EF.IMSI` and `EF.ICCID` (uncheck for exact matching). A progress line shows *N / total files* with the current path; the options are locked while scanning. Rules are created only for files that actually exist (a FCP template is returned); custom files from the **Custom files** sub-tab are included under the same existence check. #### Card snapshots The list view has two tabs — **Profiles** and **Card snapshots**. A snapshot is an immutable capture of the card filesystem: for every existing file it stores the path, symbolic name, file type, size (or record length/count), the raw FCI from the SELECT response, and the contents whenever the file is readable (no ignore list, no masking). The ICCID is decoded from EF.ICCID and shown next to the snapshot name. The scan also measures every card command (SELECT / READ BINARY / READ RECORD) from command to response and stores min/avg/max per type plus the total scan time; the snapshot view shows these in the summary and the select/read time per file (read time per record). Timings are display-only and ignored by checks/comparisons. - **New snapshot** scans the card; **Import snapshot** loads JSON. - Each snapshot row has **Open** (all captured data read-only, raw FCI with decoded FCI and contents; only the name is editable), **Export**, and **Delete**. - **Check card snapshot** on a profile row runs the profile rules against a snapshot picked from the list, without a card reader. Files whose contents were not captured are reported as unverifiable errors. - **Compare snapshots** compares two snapshots offline exactly like a profile check: pick the *master* snapshot and the *snapshot to check*, optionally masking the first 4 bytes of EF.IMSI/EF.ICCID (on by default), and get the same report. Every file must match exactly (exact FCI, contents); files present only in the checked snapshot are reported as extra files. In the comparison report the mismatch fields and FCI comparison columns are labeled with the master/checked snapshot names instead of expected/actual. --- --- #### Custom files Files not in pysim's model can be added manually: 1. Switch to the **Custom files** tab in the Profiler list 2. Enter the file path (e.g., `3F00/6F46`) and an alias (e.g., `EF.SPN`) 3. Click **Add** — the file appears in the tree in italics (unverified) 4. Use **Edit** on a row to reload it into the form (the button becomes **Save** and a **Cancel** button appears) or **Delete** to remove it 5. Click the file to verify existence — on success, it behaves like a model file Custom files persist in `localStorage` across sessions. Export/import as JSON for sharing. ## Phone simulator The **Phone simulator** tab provides real-time CAT session interaction. It has two pills: **Phone** (STK menu, STATUS and polling, subscribed events, proactive command log) and **TR Config** (response data injected into TERMINAL RESPONSEs for proactive commands). **Subscribed Events** — the card's SET UP EVENT LIST is displayed with per-event **Send** buttons. Clicking opens a form specific to the event type: - **No-data events** (User Activity, Idle Screen, etc.) — single-click confirmation - **Location Status** — dropdown for Normal / Limited / No service - **Access Technology Change** — dropdown for all 13 RAT types - **Card Reader Status, Language, UICC Access** — appropriate inputs - **Network Rejection** — full adaptive form with registration type dropdown (LU / GPRS / EPS / 5GS), location fields (MCC, MNC, LAC, RAC, TAC), access technology selection, and 53-cause unified rejection cause code dropdown covering EMM, GMM, 5GMM, and LU causes **Proactive Command Log** — chronological list of proactive commands encountered (seconds elapsed, type code, name, byte count). Covers SET UP MENU, SET UP EVENT LIST, POLL INTERVAL, DISPLAY TEXT, SELECT ITEM, and PROVIDE LOCAL INFORMATION. **TR Config: PLI data dictionary** — editable per-qualifier hex values for all 22 PROVIDE LOCAL INFORMATION qualifiers (TS 102 223 + TS 131 111). 10 qualifiers have inline decode/encode forms (toggle): | Code | Decoded fields | |------|--------------| | 00 | MCC, MNC, LAC/TAC | | 01 | IMEI (15 digits) | | 03 | Date, Time, TZ offset | | 04 | Language (2-char code) | | 05 | ME Status, Timing Advance | | 06 | Access Technology (dropdown) | | 08 | IMEISV (16 digits) | | 09 | Search Mode (Auto/Manual) | | 0A | Battery charge (%) | | 0E | Multiple Access Technologies (comma-list) | Values persist on the server until restart. Apply → hex updates; Save → POSTs to server. The server will use these values to populate TERMINAL RESPONSE data for future PLI proactive commands. ## PWA OTAMan is a Progressive Web App and can be installed for offline use. Use the **INSTALL PWA** button in the header, or use the browser's install prompt. - Service worker pre-caches all assets on first visit - App icons at 192×192 and 512×512 ## Theme A dark theme is included. It follows the system preference and can be toggled manually with the header button (🌙/☀️); the choice is stored in `localStorage`. ## Localization The interface is in English with Russian support. The language is detected from `navigator.language`; the header toggle (EN/RU) stores the choice in `localStorage`. Switching the language also re-renders visible dynamic views (profile lists, check reports, snapshots, cards, proactive views). ## Server (pysim-otaman-server) The bundled Python server wraps [pySim](https://osmocom.org/projects/pysim/wiki) and serves both the OTAMan PWA (from `frontend/`) and a JSON API under `/api/*`. ### Prerequisites - **Python 3.8+** with `pip`, and **Git** - **Smart card reader** (PC/SC or serial/FTDI) — PC/SC is preferable (`pcsc-lite` + `ccid` on Linux) - **Windows** — use Python 3.10–3.13 (3.13 recommended): `pyscard` ships precompiled wheels for these versions. On 3.9 / 3.14 it builds from source (needs MSVC C++ Build Tools). The SMPP bridge (`smpp.twisted3`) is intentionally skipped on Windows. ### Scripts | Script | What it does | |--------|-------------| | `setup.sh` / `setup.bat` | Creates `.venv/`, installs pysim and the server. Run once after cloning. | | `start.sh` / `start.bat` | Starts the server from the venv (serves the PWA + API on `:8080`). | `start.sh` auto-detects the reader (PC/SC if `pcscd` is running, else `/dev/ttyUSB0`); `start.bat` always uses `-p 0` (PC/SC is built into Windows). If no reader is found the server still starts ("Reader: none") — initialize the card later via the **Equip** button. ### Manual installation ```sh python3 -m venv .venv source .venv/bin/activate # Linux/macOS (Windows: .venv\Scripts\activate) pip install git+https://github.com/osmocom/pysim.git pip install -e . # editable — serves frontend/ from the source tree pysim-otaman-server --http-port 8080 ``` ### CLI options | Option | Description | |--------|-------------| | `--http-host` | Bind address (default: `127.0.0.1`) | | `--http-port` | TCP port (default: `8080`) | | `--web-dir` | Directory with PWA static files (default: `/frontend`) | | `-p` / `--pcsc-device` | PC/SC reader slot number | | `-d` / `--device` | Serial device path | | `--no-card-init` | Skip card init to preserve the CAT session (no file manager) | | `--apdu-trace` | Log APDU-level traces to stderr | | `--log-requests` | Log request/response payloads to stderr | | `--sms-oa` / `--sms-sm-sc` | SMS-DELIVER originating address / SM-SC for PoR-in-submit | | `--terminal-profile` | TERMINAL PROFILE payload hex (default 10-byte GSM profile) | | `--poll-interval` | Idle interval before automatic STATUS polling (default 30s; `0` disables polling) | | `--full-pysim-init` | Use pysim's stock init/equip (redundant card resets). The default init/equip is reset-free — only explicit equip/reset reconnect the card | | `--no-auto-equip` | Do not initialize a card automatically right after it is inserted (default: auto-equip on) | | `--menu-timeout` | Auto-answer a paused STK command with a timeout TERMINAL RESPONSE (default 60s; `0` disables) | | `--timing` | Log phase durations, card resets and APDU counters with elapsed timestamps | ### Troubleshooting - **"Failed to establish context: Access denied"** — `pcscd` isn't running or the user lacks permission: `sudo systemctl enable --now pcscd && sudo usermod -a -G pcscd $USER`. - **"device file /dev/ttyUSB0 does not exist"** — no serial reader; connect a USB reader or pass `-d` explicitly. The server still starts without a reader. ### API reference See [docs/api.md](docs/api.md) for the full endpoint reference. ## Theme Dark theme is supported. The app follows the OS preference on first visit, and a manual toggle button (🌙/☀️) at the top-right corner persists the choice in `localStorage`. ## Localisation The UI is in English with Russian language support. Language is detected from the browser's `navigator.language` preference. A manual toggle button (EN/RU) in the header persists the choice in `localStorage`. ## Version compatibility | PWA (OTAMan) | Server | Status | |-------------|--------|--------| | 1.x.x | 1.x.x | ✅ Compatible | | 1.x.x | 0.x.x | ❌ Outdated — update server | | 1.x.x | 2.x.x+ | ⚠️ Server newer — update PWA | The PWA checks the server version on connect via `GET /api/version` and warns if versions are incompatible.