diff --git a/docs/api.md b/docs/api.md index ab417a5..528a6a0 100644 --- a/docs/api.md +++ b/docs/api.md @@ -252,7 +252,7 @@ import also accepts presets exported by the older localStorage-based builds. Sync a preset's SCP80 counter with the card. The card accepts only a counter *above* its own (TS 102 225 §5.1.1, SPI1 b5b4 = `10`) and updates it only when the packet is accepted, so rejected attempts change nothing; the probe walks a -doubling ladder (`start+1`, `+2`, `+4`, …) with a read-only command until one +doubling ladder (`start+1`, `+2`, `+4`, …) with a fixed read-only command until one is accepted, then persists `accepted+1` (monotonic) into the keyset. The search stops at a ceiling and after a bounded number of packets, so it can never run towards the 40-bit maximum, where the card blocks the counter. The @@ -261,15 +261,15 @@ the packet's, TS 102 225 §5.2 Table 3), which is why this probe exists. ```json {"preset_id": "…", "kvn": 2, "tar": "000000", "spi1": "16", "spi2": "21", - "cntr": "0001000000", "ceiling": "FFFFFFFF", "max_attempts": 40, - "apdu": "00A40000023F00"} + "cntr": "0001000000", "ceiling": "FFFFFFFF", "max_attempts": 40} ``` All fields except `preset_id` are optional: `kvn` picks a keyset (the first otherwise), `tar`/`spi1`/`spi2` default to the preset's values, `cntr` to the -keyset's counter, `ceiling` to `FFFFFFFF` (must stay below `FFFFFFFFFF`), -`max_attempts` to 40 (clamped to 1–64), and `apdu` to a read-only `SELECT MF` -(the probe command should never modify anything). A SPI1 without a counter +keyset's counter, `ceiling` to `FFFFFFFF` (must stay below `FFFFFFFFFF`) and +`max_attempts` to 40 (clamped to 1–64). The probe always sends the read-only +`SELECT MF` - the counter advances on the packet's security acceptance whatever +the applet answers (`6A86`/`6D00` are normal there). A SPI1 without a counter check is refused (400). **Response:** `{"success": true, "accepted_cntr": "0001000000", diff --git a/frontend/index.html b/frontend/index.html index 9a5ecac..8b9432e 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1801,7 +1801,7 @@ // ===== Version ===== // Single source of truth for the PWA version: shown in the header and used // by the server version check in pysimConnect(). -const SIMPLE_VERSION = '3.9.0'; +const SIMPLE_VERSION = '3.9.1'; document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION; // ===== Tab switching ===== diff --git a/frontend/sw.js b/frontend/sw.js index a2b39ad..4fc409d 100644 --- a/frontend/sw.js +++ b/frontend/sw.js @@ -1,4 +1,4 @@ -const CACHE = 'simple-v356'; +const CACHE = 'simple-v357'; const URLS = [ 'index.html', 'help.html', diff --git a/pyproject.toml b/pyproject.toml index ac8e93f..ea5c9c3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "pysim-simple-server" -version = "3.9.0" +version = "3.9.1" description = "HTTP REST server wrapping pysim for the SIMple PWA" requires-python = ">=3.8" # pysim is a git-only dependency installed explicitly by setup.bat/setup.sh. diff --git a/pysim_simple_server/server.py b/pysim_simple_server/server.py index b84e8aa..06ca4a2 100644 --- a/pysim_simple_server/server.py +++ b/pysim_simple_server/server.py @@ -32,7 +32,7 @@ from osmocom.tlv import BER_TLV_IE from osmocom.utils import rpad -VERSION = '3.9.0' +VERSION = '3.9.1' MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE @@ -1668,7 +1668,10 @@ def _counter_probe_params(preset, body): 'spi1': spi1, 'spi2': str(body.get('spi2') or preset.get('spi2') or '21').strip().upper(), 'tar': str(body.get('tar') or preset.get('tar') or '000000').strip().upper(), - 'apdu': str(body.get('apdu') or COUNTER_PROBE_DEFAULT_APDU).replace(' ', '').upper(), + # the probe command is fixed: read-only SELECT MF, which every applet + # answers (an error SW is fine - the counter advances on the packet's + # security acceptance, not on the command's own result) + 'apdu': COUNTER_PROBE_DEFAULT_APDU, }