commit 7358b27a289c4899a3de32852e72f5145a6bcb6b
parent 047035bf58e4fec5d5c9f6b3f449d8e36e724ebb
Author: Christian Grothoff <christian@grothoff.org>
Date: Wed, 29 Jul 2026 18:55:25 +0200
accept Corsican NIR numbers in the French identity check
Diffstat:
3 files changed, 47 insertions(+), 2 deletions(-)
diff --git a/contrib/redux.fr.json b/contrib/redux.fr.json
@@ -30,7 +30,7 @@
"tooltip": "Code Insee",
"widget": "anastasis_gtk_ia_insee_fr",
"uuid": "2f36a81c-3f6d-41f3-97ee-9c885bc41873",
- "validation-regex": "^[0-9]{15}$",
+ "validation-regex": "^[0-9]{5}([0-9]{2}|2[AB])[0-9]{8}$",
"validation-logic": "FR_INSEE_check"
}
]
diff --git a/src/reducer/test_validation.c b/src/reducer/test_validation.c
@@ -140,6 +140,34 @@ main (int argc,
return 1;
}
+ /* French NIR: mainland and both Corsican department codes. 2A must map to
+ 19 and 2B to 18, so the two must not produce the same check digits. */
+ if (! FR_INSEE_check ("180057512345627"))
+ {
+ GNUNET_break (0);
+ return 1;
+ }
+ if (! FR_INSEE_check ("180052A12345684"))
+ {
+ GNUNET_break (0);
+ return 1;
+ }
+ if (! FR_INSEE_check ("180052B12345614"))
+ {
+ GNUNET_break (0);
+ return 1;
+ }
+ if (FR_INSEE_check ("180052A12345614")) /* 2B's key on a 2A number */
+ {
+ GNUNET_break (0);
+ return 1;
+ }
+ if (FR_INSEE_check ("180052C12345684")) /* no such department letter */
+ {
+ GNUNET_break (0);
+ return 1;
+ }
+
/* AL_NID_check has no implementation yet and deliberately accepts
everything; when it is implemented, this expectation must change. */
if (! AL_NID_check ("I05101999I"))
diff --git a/src/reducer/validation_FR_INSEE.c b/src/reducer/validation_FR_INSEE.c
@@ -29,7 +29,8 @@
* See https://en.wikipedia.org/wiki/INSEE_code
*
* Note that we do not implement checks on the month
- * and also allow non-binary prefixes.
+ * and also allow non-binary prefixes. Corsican numbers carry 2A or 2B in
+ * the department field and are accepted.
*
* @param insee_number social security number to validate (input)
* @return true if validation passed, else false
@@ -52,6 +53,22 @@ FR_INSEE_check (const char *insee_number)
insee_number,
13);
pfx[13] = '\0';
+ /* Corsica carries a letter in the department field (positions 5-6): the
+ official rule is to substitute 2A -> 19 and 2B -> 18 before the mod-97,
+ since the remaining digits alone would collide between the two. */
+ if ('2' == pfx[5])
+ {
+ if ('A' == pfx[6])
+ {
+ pfx[5] = '1';
+ pfx[6] = '9';
+ }
+ else if ('B' == pfx[6])
+ {
+ pfx[5] = '1';
+ pfx[6] = '8';
+ }
+ }
if (1 !=
sscanf (pfx,
"%llu%c",