Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
215d0a0ba0 | ||
|
|
8f63368008 | ||
|
|
29d762a662 |
No files matched your search
@@ -9,6 +9,18 @@ every change carries a descriptive commit message.
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [3.40.3] — 2026-10-27
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Equipped card not always auto-selected in SCP80/RAM.** The ICCID-based
|
||||||
|
preset auto-selection latched its "already handled" guard even when no
|
||||||
|
matching preset was found, so a card equipped before `/api/presets` had
|
||||||
|
loaded (the connect-time race) never got auto-selected — navigating to
|
||||||
|
SCP80/RAM showed no preset until the card was re-inserted. The guard is
|
||||||
|
now latched only after a successful selection, and `cardsFetch` re-runs
|
||||||
|
the auto-selection once the store arrives.
|
||||||
|
|
||||||
## [3.40.2] — 2026-10-26
|
## [3.40.2] — 2026-10-26
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -13,11 +13,16 @@ SIMple is a workbench for UICC/SIM card specialists: an offline HTML/JS frontend
|
|||||||
|
|
||||||
**Demo:** [simple.atroshin.ru](https://simple.atroshin.ru) — the frontend alone, for experimenting. Install the server (below) for card-reader functions.
|
**Demo:** [simple.atroshin.ru](https://simple.atroshin.ru) — the frontend alone, for experimenting. Install the server (below) for card-reader functions.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- **Python 3.9+** with `pip`, and **Git** — the app runs on 3.9+, but the **SCP81 TLS-PSK listener needs Python 3.13+** (`ssl`'s PSK callbacks).
|
||||||
|
- **Python venv support** — `setup.sh` creates `.venv`; if that fails with `ensurepip is not available` (Debian/Ubuntu ship the venv module separately), install it (`sudo apt install python3-venv`) and run `./setup.sh` again. An incomplete `.venv` left by the failed run is removed automatically.
|
||||||
|
- **Smart card reader** (PC/SC or serial/FTDI) — PC/SC is preferable (`pcsc-lite` + `ccid` on Linux). `pyscard` has no Linux wheels, so it builds from source: install the PC/SC header package too (`libpcsclite-dev` on Debian/Ubuntu, `pcsc-lite-devel` on Fedora; on Arch `pcsclite` includes them).
|
||||||
|
- **Windows** — use **Python 3.13 (strongly recommended)**: `pyscard` ships precompiled wheels for it, so nothing needs compiling; on **3.14** the `pyscard` and some pysim dependency wheels are missing and build from source (needs MSVC C++ Build Tools).
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
**Frontend only (client-side tools):** open `frontend/index.html` in any browser, or serve `frontend/` with any static server. No Python required.
|
**Install the server** — two ways to get it:
|
||||||
|
|
||||||
**Full (frontend + card server)** — two ways to get it:
|
|
||||||
|
|
||||||
**1. Download the release package (recommended).** From the
|
**1. Download the release package (recommended).** From the
|
||||||
[Releases](https://github.com/anttro/simple/releases) page take the latest package
|
[Releases](https://github.com/anttro/simple/releases) page take the latest package
|
||||||
@@ -745,13 +750,6 @@ The interface is in English with Russian support. The language is detected from
|
|||||||
|
|
||||||
The bundled Python server wraps [pySim](https://osmocom.org/projects/pysim/wiki) and serves both the SIMple frontend (from `frontend/`) and a JSON API under `/api/*`.
|
The bundled Python server wraps [pySim](https://osmocom.org/projects/pysim/wiki) and serves both the SIMple frontend (from `frontend/`) and a JSON API under `/api/*`.
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
- **Python 3.9+** with `pip`, and **Git** — the app runs on 3.9+, but the **SCP81 TLS-PSK listener needs Python 3.13+** (`ssl`'s PSK callbacks).
|
|
||||||
- **Python venv support** — `setup.sh` creates `.venv`; if that fails with `ensurepip is not available` (Debian/Ubuntu ship the venv module separately), install it (`sudo apt install python3-venv`) and run `./setup.sh` again. An incomplete `.venv` left by the failed run is removed automatically.
|
|
||||||
- **Smart card reader** (PC/SC or serial/FTDI) — PC/SC is preferable (`pcsc-lite` + `ccid` on Linux). `pyscard` has no Linux wheels, so it builds from source: install the PC/SC header package too (`libpcsclite-dev` on Debian/Ubuntu, `pcsc-lite-devel` on Fedora; on Arch `pcsclite` includes them).
|
|
||||||
- **Windows** — use **Python 3.13 (strongly recommended)**: `pyscard` ships precompiled wheels for it, so nothing needs compiling; on **3.14** the `pyscard` and some pysim dependency wheels are missing and build from source (needs MSVC C++ Build Tools).
|
|
||||||
|
|
||||||
### Scripts
|
### Scripts
|
||||||
|
|
||||||
| Script | What it does |
|
| Script | What it does |
|
||||||
|
|||||||
+8
-10
@@ -13,11 +13,16 @@ SIMple — инструментарий для специалистов по UIC
|
|||||||
|
|
||||||
**Демо:** [simple.atroshin.ru](https://simple.atroshin.ru) — только фронтенд, для экспериментов. Для функций картридера установите сервер (ниже).
|
**Демо:** [simple.atroshin.ru](https://simple.atroshin.ru) — только фронтенд, для экспериментов. Для функций картридера установите сервер (ниже).
|
||||||
|
|
||||||
|
## Требования
|
||||||
|
|
||||||
|
- **Python 3.9+** с `pip`, и **Git** — приложение работает на 3.9+, но **SCP81 TLS-PSK-слушателю нужен Python 3.13+** (PSK-callback'и `ssl`).
|
||||||
|
- **Поддержка venv в Python** — `setup.sh` создаёт `.venv`; если создание завершается с `ensurepip is not available` (в Debian/Ubuntu модуль venv поставляется отдельно), установите его (`sudo apt install python3-venv`) и запустите `./setup.sh` снова. Неполный `.venv`, оставшийся от неудачного запуска, удаляется автоматически.
|
||||||
|
- **Смарт-картридер** (PC/SC или serial/FTDI) — предпочтителен PC/SC (`pcsc-lite` + `ccid` на Linux). У `pyscard` нет Linux-wheel, поэтому он собирается из исходников: поставьте и пакет с заголовками PC/SC (`libpcsclite-dev` в Debian/Ubuntu, `pcsc-lite-devel` в Fedora; в Arch они входят в `pcsclite`).
|
||||||
|
- **Windows** — используйте **Python 3.13 (настоятельно рекомендуется)**: для него `pyscard` поставляет готовые wheel, так что ничего компилировать не нужно; на **3.14** wheel для `pyscard` и части зависимостей pysim отсутствуют, и они собираются из исходников (нужны MSVC C++ Build Tools).
|
||||||
|
|
||||||
## Быстрый старт
|
## Быстрый старт
|
||||||
|
|
||||||
**Только фронтенд (клиентские функции):** откройте `frontend/index.html` в любом браузере или раздайте `frontend/` любым статическим сервером. Python не нужен.
|
**Установка сервера** — два способа:
|
||||||
|
|
||||||
**Полная установка (фронтенд + сервер карт)** — два способа:
|
|
||||||
|
|
||||||
**1. Скачать релизный пакет (рекомендуется).** На странице
|
**1. Скачать релизный пакет (рекомендуется).** На странице
|
||||||
[Releases](https://github.com/anttro/simple/releases) возьмите последний пакет
|
[Releases](https://github.com/anttro/simple/releases) возьмите последний пакет
|
||||||
@@ -729,13 +734,6 @@ SIMple — Progressive Web App. Можно установить для offline-
|
|||||||
|
|
||||||
Встроенный Python-сервер оборачивает [pySim](https://osmocom.org/projects/pysim/wiki) и раздаёт как фронтенд (из `frontend/`), так и JSON API по `/api/*`.
|
Встроенный Python-сервер оборачивает [pySim](https://osmocom.org/projects/pysim/wiki) и раздаёт как фронтенд (из `frontend/`), так и JSON API по `/api/*`.
|
||||||
|
|
||||||
### Требования
|
|
||||||
|
|
||||||
- **Python 3.9+** с `pip`, и **Git** — приложение работает на 3.9+, но **SCP81 TLS-PSK-слушателю нужен Python 3.13+** (PSK-callback'и `ssl`).
|
|
||||||
- **Поддержка venv в Python** — `setup.sh` создаёт `.venv`; если создание завершается с `ensurepip is not available` (в Debian/Ubuntu модуль venv поставляется отдельно), установите его (`sudo apt install python3-venv`) и запустите `./setup.sh` снова. Неполный `.venv`, оставшийся от неудачного запуска, удаляется автоматически.
|
|
||||||
- **Смарт-картридер** (PC/SC или serial/FTDI) — предпочтителен PC/SC (`pcsc-lite` + `ccid` на Linux). У `pyscard` нет Linux-wheel, поэтому он собирается из исходников: поставьте и пакет с заголовками PC/SC (`libpcsclite-dev` в Debian/Ubuntu, `pcsc-lite-devel` в Fedora; в Arch они входят в `pcsclite`).
|
|
||||||
- **Windows** — используйте **Python 3.13 (настоятельно рекомендуется)**: для него `pyscard` поставляет готовые wheel, так что ничего компилировать не нужно; на **3.14** wheel для `pyscard` и части зависимостей pysim отсутствуют, и они собираются из исходников (нужны MSVC C++ Build Tools).
|
|
||||||
|
|
||||||
### Скрипты
|
### Скрипты
|
||||||
|
|
||||||
| Скрипт | Назначение |
|
| Скрипт | Назначение |
|
||||||
|
|||||||
+11
-2
@@ -1990,7 +1990,7 @@
|
|||||||
// ===== Version =====
|
// ===== Version =====
|
||||||
// Single source of truth for the PWA version: shown in the header and used
|
// Single source of truth for the PWA version: shown in the header and used
|
||||||
// by the server version check in pysimConnect().
|
// by the server version check in pysimConnect().
|
||||||
const SIMPLE_VERSION = '3.40.2';
|
const SIMPLE_VERSION = '3.40.3';
|
||||||
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
|
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
|
||||||
|
|
||||||
// ===== view history (the browser Back/Forward buttons) =====
|
// ===== view history (the browser Back/Forward buttons) =====
|
||||||
@@ -14315,6 +14315,11 @@ async function cardsFetch() {
|
|||||||
cardsRebuildSelect();
|
cardsRebuildSelect();
|
||||||
cardsRender();
|
cardsRender();
|
||||||
tarRender();
|
tarRender();
|
||||||
|
// A card may already be equipped when the presets arrive (the server
|
||||||
|
// starts with a card, or the fetch simply raced the first status poll):
|
||||||
|
// run the auto-selection now that the store is loaded. It is a no-op
|
||||||
|
// once the card's preset is already selected (the latched ICCID guard).
|
||||||
|
cardsAutoSelectByIccid(_pysimCardIccid);
|
||||||
scp81PushPskMap();
|
scp81PushPskMap();
|
||||||
spPresetWarningRender();
|
spPresetWarningRender();
|
||||||
return true;
|
return true;
|
||||||
@@ -15209,12 +15214,16 @@ let _cardsAutoIccid = null;
|
|||||||
function cardsAutoSelectByIccid(iccid) {
|
function cardsAutoSelectByIccid(iccid) {
|
||||||
// Act only when the equip reports a *new* ICCID: a manual preset choice
|
// Act only when the equip reports a *new* ICCID: a manual preset choice
|
||||||
// for the same card must not be overridden by later status updates.
|
// for the same card must not be overridden by later status updates.
|
||||||
|
// The guard is latched only once the card's preset is actually found and
|
||||||
|
// selected - a miss (the preset store not loaded yet, or no preset for
|
||||||
|
// this card) is retried when the store arrives (cardsFetch) so a card
|
||||||
|
// equipped before the presets loaded still gets auto-selected.
|
||||||
const norm = cardsNormIccid(iccid);
|
const norm = cardsNormIccid(iccid);
|
||||||
if (!norm) { _cardsAutoIccid = null; return -1; }
|
if (!norm) { _cardsAutoIccid = null; return -1; }
|
||||||
if (norm === _cardsAutoIccid) return -1;
|
if (norm === _cardsAutoIccid) return -1;
|
||||||
_cardsAutoIccid = norm;
|
|
||||||
const idx = cardsFindByIccid(norm);
|
const idx = cardsFindByIccid(norm);
|
||||||
if (idx < 0) return -1;
|
if (idx < 0) return -1;
|
||||||
|
_cardsAutoIccid = norm;
|
||||||
const sp = document.getElementById('sp-card-sel');
|
const sp = document.getElementById('sp-card-sel');
|
||||||
if (sp) sp.value = String(idx);
|
if (sp) sp.value = String(idx);
|
||||||
const ram = document.getElementById('ram-card-sel');
|
const ram = document.getElementById('ram-card-sel');
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
const CACHE = 'simple-v487';
|
const CACHE = 'simple-v488';
|
||||||
const URLS = [
|
const URLS = [
|
||||||
'index.html',
|
'index.html',
|
||||||
'help.html',
|
'help.html',
|
||||||
|
|||||||
@@ -146,6 +146,30 @@ test('cardsAutoSelectByIccid reacts to a card swap and to unreadable ICCIDs', ()
|
|||||||
assert.strictEqual(cardsAutoSelectByIccid('1234567890123456789'), -1);
|
assert.strictEqual(cardsAutoSelectByIccid('1234567890123456789'), -1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('a miss is not latched, so the store arriving later still auto-selects', () => {
|
||||||
|
// The card equips before /api/presets fills cards[] (the connect-time
|
||||||
|
// race): the auto-selection must not latch the ICCID on a miss, or the
|
||||||
|
// later cardsFetch would be a no-op and the preset would stay unselected
|
||||||
|
// until the card is re-inserted.
|
||||||
|
const els = fakeDoc();
|
||||||
|
const applied = [];
|
||||||
|
globalThis.cardsApply = idx => applied.push(idx);
|
||||||
|
globalThis.cards = []; // presets not loaded yet
|
||||||
|
globalThis._ramCardIdx = null;
|
||||||
|
globalThis._cardsAutoIccid = null;
|
||||||
|
assert.strictEqual(cardsAutoSelectByIccid(DIGITS), -1);
|
||||||
|
assert.strictEqual(globalThis._cardsAutoIccid, null,
|
||||||
|
'a missed auto-selection must not latch the ICCID');
|
||||||
|
// the presets arrive: the retry (from cardsFetch) finds and selects the card
|
||||||
|
globalThis.cards = [{ name: 'A', iccid: RAW_HEX }];
|
||||||
|
assert.strictEqual(cardsAutoSelectByIccid(DIGITS), 0);
|
||||||
|
assert.strictEqual(els['sp-card-sel'].value, '0');
|
||||||
|
assert.strictEqual(els['ram-card-sel'].value, '0');
|
||||||
|
assert.strictEqual(els['tar-card-sel'].value, '0');
|
||||||
|
assert.deepStrictEqual(applied, ['0']);
|
||||||
|
assert.strictEqual(globalThis._ramCardIdx, 0);
|
||||||
|
});
|
||||||
|
|
||||||
test('cardsFindDuplicateIccid catches duplicates across stored formats', () => {
|
test('cardsFindDuplicateIccid catches duplicates across stored formats', () => {
|
||||||
globalThis.cards = [
|
globalThis.cards = [
|
||||||
{ name: 'A', iccid: '1111111111111111111' },
|
{ name: 'A', iccid: '1111111111111111111' },
|
||||||
@@ -201,6 +225,13 @@ test('the card-state update wires the ICCID into the preset selection', () => {
|
|||||||
assert.ok(html.includes("(data.iccid ? ' | ICCID: <b>' + esc(data.iccid) + '</b>' : '')"));
|
assert.ok(html.includes("(data.iccid ? ' | ICCID: <b>' + esc(data.iccid) + '</b>' : '')"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('cardsFetch retries the auto-selection once the presets load', () => {
|
||||||
|
// The equip may be reported before /api/presets resolves, so the fetch
|
||||||
|
// must re-run the auto-selection (a no-op once the card is selected).
|
||||||
|
assert.ok(html.includes('cardsAutoSelectByIccid(_pysimCardIccid);'),
|
||||||
|
'cardsFetch must re-run the auto-selection after loading the store');
|
||||||
|
});
|
||||||
|
|
||||||
test('cardsRender highlights the equipped card preset', () => {
|
test('cardsRender highlights the equipped card preset', () => {
|
||||||
globalThis.t = s => s;
|
globalThis.t = s => s;
|
||||||
const els = { 'cards-tbody': { innerHTML: '' } };
|
const els = { 'cards-tbody': { innerHTML: '' } };
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "pysim-simple-server"
|
name = "pysim-simple-server"
|
||||||
version = "3.40.2"
|
version = "3.40.3"
|
||||||
description = "HTTP REST server wrapping pysim for the SIMple PWA"
|
description = "HTTP REST server wrapping pysim for the SIMple PWA"
|
||||||
license = { text = "GPL-2.0-or-later" }
|
license = { text = "GPL-2.0-or-later" }
|
||||||
requires-python = ">=3.9"
|
requires-python = ">=3.9"
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ from osmocom.tlv import BER_TLV_IE
|
|||||||
from osmocom.utils import rpad
|
from osmocom.utils import rpad
|
||||||
|
|
||||||
|
|
||||||
VERSION = '3.40.2'
|
VERSION = '3.40.3'
|
||||||
|
|
||||||
MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE
|
MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user