Skip to content

Fix validation of fiscal codes with non-contiguous omocodia substitutions - #10

Open
MFranceschi6 wants to merge 1 commit into
TheInkedEngineer:developfrom
FlowPay:fix/non-contiguous-omocodia
Open

Fix validation of fiscal codes with non-contiguous omocodia substitutions#10
MFranceschi6 wants to merge 1 commit into
TheInkedEngineer:developfrom
FlowPay:fix/non-contiguous-omocodia

Conversation

@MFranceschi6

Copy link
Copy Markdown

Problem

Spritz.isValid rejects real fiscal codes issued by the Agenzia delle Entrate when the omocodia substitutions are not contiguous starting from the rightmost digit (e.g. position 13 substituted while position 14 still holds a digit). We hit this in production with a code the Agenzia delle Entrate verification service confirms as valid.

While reproducing it, two more issues surfaced in the omocodia handling:

  1. originalFiscalCode(from:) enforced right-to-left contiguous substitutions. The progressive pattern is how new omocode variants are generated, but it is not a validity constraint: codes with any subset of the seven numeric positions substituted exist and are accepted by the Agenzia delle Entrate (each numeric position is independently [0-9LMNPQRSTUV], guarded by the checksum).
  2. Restoring digits used characters.lastIndex(of:), which searches the whole code. When the substitution letter also appears later in the code (first letter of the place-of-birth code, or the checksum letter), the wrong character was replaced, corrupting the decoded code.
  3. isValid compared mismatched checksums for every omocode variant: the expected checksum was computed on the value as passed, but compared against the recomputed checksum of the decoded original code. As a result, isValid returned false for any omocodia variant, contiguous ones included (e.g. MRCMLD92C42D96VG, which originalFiscalCode itself decodes correctly).

Fix

  • originalFiscalCode(from:) now restores digits by their known positions (6, 7, 9, 10, 12, 13, 14), accepting any combination of substituted positions. The checksum pre-check and the omocodia-letter mapping still reject malformed codes (e.g. SFAFRS92C02ZN2ZW, which carries a valid checksum but a letter outside the omocodia alphabet).
  • isValid validates the checksum against the passed value itself.

Behavioral note: SFAFRS92C02ZN2VJ, previously treated as corrupted because of the non-contiguity rule, is a well-formed omocode (valid checksum, valid substitution letters) and now decodes to SFAFRS92C02Z229F. The corresponding test expectation moved accordingly.

Tests

All fiscal codes in the new tests are synthetic (built on the classic fictional RSSMRA... data), no real personal data is included:

  • RSSMRA90A01H5L1H — non-contiguous substitution (position 13 substituted, 14 not), mirrors the production case; decodes to RSSMRA90A01H501W.
  • RSSMRA90A0MM002M — the substituted letter M also appears as the first letter of the municipality code and as the checksum; guards the positional replacement against lastIndex-style regressions.
  • MRCMLD92C42D96VG — contiguous omocode now accepted by isValid, covering the checksum-comparison fix.

Full suite passes: 67 tests, 0 failures.

Decoding enforced right-to-left contiguous substitutions, but codes
exist where any subset of the seven numeric positions is substituted.
Such codes failed validation despite a valid checksum, matching what
the Agenzia delle Entrate considers valid.

- drop the contiguity requirement in originalFiscalCode
- restore digits by position instead of lastIndex(of:), which
  corrupted codes when the substitution letter also appeared in the
  place-of-birth code or checksum
- validate the checksum in isValid against the passed value: it was
  compared against the recomputed checksum of the decoded code,
  rejecting every omocodia variant
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant