Skip to content

Replace @randyd45/curp-validation with validate-curp - #296

Draft
ricardobcl wants to merge 1 commit into
masterfrom
bugfix/restore-curp-check-digit-validation
Draft

Replace @randyd45/curp-validation with validate-curp#296
ricardobcl wants to merge 1 commit into
masterfrom
bugfix/restore-curp-check-digit-validation

Conversation

@ricardobcl

Copy link
Copy Markdown
Contributor

Description

v11.0.0 replaced the GPL-licensed curp lib with @randyd45/curp-validation (#287), but the two are not equivalent: curp.validar() validated the CURP check digit, while @randyd45/curp-validation's isFormatValid() only tests the format regex — the 18th character is matched by (\d) but never verified. Both libraries use the same regex, so the swap silently made the assert strictly more permissive.

Verified empirically — same 17-character prefix, all ten possible check digits:

CURP curp@1.2.3 @randyd45/curp-validation@1.0.4
SABC560626MDFLRN01 (correct digit)
SABC560626MDFLRN00, 0209

9 of 10 previously-rejected values pass v11. The check digit is a weighted mod-10 sum over the 17 preceding characters — it is what catches single-character typos and transpositions anywhere in the CURP.

This PR replaces @randyd45/curp-validation with validate-curp (MIT, same author as the validate-rfc lib already backing the RfcNumber assert), mirroring the RfcNumber assert one-to-one. validate-curp restores check-digit validation — its algorithm is identical to the original curp lib's (same 37-character dictionary, weights 18 - i, mod 10) — and additionally validates the state code (including NE) and RENAPO's forbidden-word list (identical to curp's 81-word malasPalabras list).

Behavioral notes:

  • Like validate-rfc, validate-curp normalizes input before validating (trim, uppercase, strip non-alphanumerics), so e.g. lowercase CURPs are now accepted — consistent with how RfcNumber behaves today.
  • The forbidden-word check is stricter than the original curp.validar(), which never checked it (only generar() substituted forbidden words). Genuine RENAPO-issued CURPs never carry those prefixes.

Also adds a check-digit negative test — the test that would have caught this in #287.

Related issues

Follow-up to #287. Affects uphold/backend#18451.

Impacted areas

  • CurpNumber assert.

Steps to reproduce or test

Development

yarn test

523/523 passing, including the new check-digit case.

QA

N/A

Checklist

  • Add label Breaking Change if it applies.
  • Commits are atomic and logically separated.
  • Performance implications have been considered.
  • Security implications have been considered.
  • The new and updated code has good coverage.
  • API documentation, if required, has been created or updated.
  • New dependencies have been added to package.json.
  • The README file, if required, has been updated.
  • Architectural diagram, if required, has been updated.

Deploy notes

Peer dependency change (@randyd45/curp-validationvalidate-curp), so the next release should be a major (v12.0.0). Consumers must swap the optional peer dependency when upgrading.

@ricardobcl ricardobcl added the bug Something isn't working label Aug 31, 2026
@ricardobcl ricardobcl self-assigned this Aug 31, 2026
The curp lib validated the CURP check digit, but its replacement
@randyd45/curp-validation only checks the format regex, so 9 out of 10
possible check digits on any structurally-valid CURP were accepted.

validate-curp (MIT, same author as validate-rfc) restores check-digit
validation and additionally validates the state code and RENAPO's
forbidden-word list, matching the original curp lib's behavior.
@ricardobcl
ricardobcl force-pushed the bugfix/restore-curp-check-digit-validation branch from e27838d to c83f085 Compare August 31, 2026 15:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants