mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2026-08-25 20:39:46 +00:00
Second tranche of #1098, after #1102. Keys-found and blocks-read are tracked by two independent masks - mf_classic_set_key_found() writes a key into the sector trailer and never touches block_read_mask - so a sector routinely has both keys known while its data blocks are still zero-filled. Fourteen parsers presented those zeros as card data. Each now uses mf_classic_parser_block_has_data() from #1102: the read mask when it can be trusted, non-zero content when it cannot, because mf_classic_load() wipes the mask for any .nfc saved without "Data format version: 2". WashCity, Microel and MiZIP named a credit they never read, and decline outright once none of them survives - their card number is the UID, which the card info screen already shows, so an all-Unknown page would replace the Keys Found view with nothing. MiZIP additionally read block 10 to choose which of blocks 8 and 9 held the current credit, so an unread selector silently picked block 8 and labelled it the balance. Bip required its card-number block and names an unread balance or trip window, and gates each ring-buffer slot as the loop reaches it - a slot that was never read is not the same as one a card with fewer than three top-ups legitimately left empty, and conflating them either printed a fabricated transaction or hid a real one. CharlieCard picked its live balance sector by comparing two trip counters that may never have been read; on zeros the tie-break chose sector 2 and the use count underflowed to 65535. That decision now refuses to produce a sector it cannot justify. Its transaction history and passes were rendered from sectors nothing verifies, and expiry names all three of its states rather than dropping the line for two different reasons. Saflok verified sector 1 and then decoded every field from blocks 1 and 2, which are sector 0 - seventeen zero bytes decrypt into a Primary Programming Key. CSC has no key check at all and its XOR checksum is satisfied by all zeros; its refill signature also selects the New Card branch, which skips that checksum, so a used card read without sector 3 reported as new. Banapass told the user to scan a clone at a cabinet on the strength of an unread block. H World decoded a room from a block its key check does not cover, and called a card a standard room key from a trailer nothing reads. The SKPPK, SevPPK and SZPPK ticket parsers paired a real departure station with an empty ticket, and - worse - reported it through an existing message that blames the ticket for not being issued, on a screen that has already replaced Keys Found. SmartRider and Bambu had the opposite bug: both called mf_classic_is_block_read() directly, so for a legacy save or a converted PM3 dump the wiped mask refused the card outright with every byte present. Same fault #1102 repaired for Social Moscow. Builds clean with fbt format and fbt lint. Not hardware-tested - none of these cards were available - and the PR carries a manual QA table. The risk is asymmetric: for a block that was never read there is no case that renders correctly today, since the parser was already printing fabricated values. Part of #1098 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>