scp81 passthru, proactive decoders, ADM badge, file manager layout (v2.2.1)

SCP81:
- New listener mode "passthru": no local listener - the card's BIP
  channels connect straight to a configured external platform
  (host/port required), which terminates TLS and runs the dialog.
  The status API reports mode/target (_SCP81_MODE/_SCP81_TARGET) and
  clears them on stop. PWA mode select, hint, Start validation; TLS PSK
  stays the default.

Proactive command decoding (Phone tab log):
- SEND SHORT MESSAGE (0x13) is now decoded: alpha, address (TON/NPI +
  number), 3GPP-SMS TPDU (type, TP-MR, TP-DA, TP-PID 0x7F flagged as
  SIM data download, TP-DCS, TP-VP, TP-UDL), UDH concatenation IEs, and
  the TP-UD as text (GSM-7 with a septet unpacker, UCS2, 8-bit) or as a
  TS 31.115 secured packet for PID 0x7F; malformed TPDUs fall back to
  the raw hex line.
- PROVIDE LOCAL INFORMATION qualifier names completed per TS 102 223
  V18.3.0: ESN (07), MEID (0B), Supported RATs (1A); 05 relabelled
  "Reserved for GSM (Timing Advance)". Fixed in the server dict and
  both frontend tables.

Header:
- Compact ADM badge next to the card indicator: "ADM ✓" green when
  pySim's adm_verified is set, "ADM ✗" red otherwise, hidden without a
  card session or when the server is down; updated ahead of the card
  state-key early return so it never disturbs the connect/reset flow.

File manager:
- Sort pills (FID/Name), Probe all files button and progress line are
  pinned above the tree instead of scrolling with it; the tree box cap
  grows from 420px to 65vh.

SW cache otaman-v165; help EN/RU updated; tests 234 Python + 361 frontend.
This commit is contained in:
2026-09-16 15:29:01 +03:00
parent 8c90958718
commit 20fbfd99a5
12 changed files with 479 additions and 39 deletions
+26
View File
@@ -152,6 +152,32 @@ class BipTerminalTest(unittest.TestCase):
self.assertIn('close', kinds)
peer.stop()
def test_passthru_mode_roundtrip_via_bip_control(self):
# SCP81 passthru: the control API enables BIP with the external
# platform as the target and starts no local listener; the card's
# channel talks straight to that platform.
peer = PeerServer(greeting=b'PLATFORM')
peer.start()
try:
resp = server._scp81_bip_control({'action': 'start', 'mode': 'passthru',
'host': '127.0.0.1', 'port': peer.port})
self.assertTrue(resp['ok'], resp)
self.assertEqual(resp['listener']['mode'], 'passthru')
self.assertEqual(server._BIP.target, ('127.0.0.1', peer.port))
cid, err = server._BIP.open('10.9.9.9', 10174, 512)
self.assertIsNone(err)
self.assertTrue(server._BIP.send(cid, b'CARDHELLO'))
data = b''
for _ in range(20):
data = server._BIP.receive(cid, 100)
if data:
break
time.sleep(0.05)
self.assertEqual(data, b'PLATFORM')
finally:
server._scp81_bip_control({'action': 'stop'})
peer.stop()
def test_disabled_terminal_refuses_open(self):
bip = httpota.BipTerminal()
cid, err = bip.open('127.0.0.1', 1, 512)