Skip to content

fix(other): validate current two-digit year when it matches century prefix - #169

Open
stevechen256-source wants to merge 1 commit into
braintree:mainfrom
stevechen256-source:fix/expiration-year-current-century
Open

fix(other): validate current two-digit year when it matches century prefix#169
stevechen256-source wants to merge 1 commit into
braintree:mainfrom
stevechen256-source:fix/expiration-year-current-century

Conversation

@stevechen256-source

Copy link
Copy Markdown

Summary of changes

Fixes #127 — a card expiration such as 07/20 was reported as invalid for the entire year 2020.

What & Why

In expirationYear, the two-digit-year branch first checked whether the input matched the century prefix of the current year (String(currentYear).substr(0, 2)):

if (String(currentYear).substr(0, 2) === value) {
  return verification(false, true); // potentially valid only
}

During 2020 the century prefix is "20", which is also a complete two-digit year. So "20" was always short-circuited to "potentially valid" and never evaluated as the current year. Every MM/YY expiration with YY = 20 therefore failed validation in 2020 (e.g. expirationDate("07/20") on 2020-01-01 → { isValid: false }), even though July 2020 was in the future. The same bug mis-classified future years whose two-digit form matched the century prefix (e.g. "20" entered in 2018/2019).

Changes

  • src/expiration-year.ts: compute the actual validity (isCurrentYear / valid window) before the century-prefix check, so a complete two-digit year that is the current year or within the valid window is accepted. The century-prefix match now only serves as a "potentially valid" fallback for partially typed 4-digit years (e.g. "20""2021").
  • src/__tests__/expiration-year.ts: regression tests with the system clock set to 2020-01-01.
  • src/__tests__/expiration-date.ts: regression tests asserting 07/20 is valid (and 06/19 is invalid) in 2020.

Test plan

npm test (jest + eslint):

Test Suites: 11 passed, 11 total
Tests:       588 passed, 588 total

Before the fix, the new regression cases failed:

expirationYear('20') in 2020: {"isValid":false,"isPotentiallyValid":true,"isCurrentYear":false}  // expected isValid: true
expirationDate('07/20') in 2020: {"isValid":false,...}                                           // expected isValid: true

After the fix both return isValid: true. Full suite passes with coverage thresholds met.

Checklist

  • Added a changelog entry
  • Relevant test coverage
  • Tested and confirmed flows affected by this change are functioning as expected

Authors

stevechen256-source

…refix

A two-digit expiration year that equals the current century prefix
(e.g. "20" during 2020) was short-circuited to "potentially valid"
by the century-prefix check, so every MM/YY expiration whose year was
"20" failed to validate for the entire year 2020.

Reorder the checks so a complete two-digit year that is the current
year (or within the valid window) is accepted first, and the century
prefix match only serves as a potentially-valid fallback for partially
typed 4-digit years.

Fixes braintree#127
@stevechen256-source
stevechen256-source requested a review from a team as a code owner August 18, 2026 06:52
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

This PR has had no activity for 14 days. It will be closed in 7 days if no activity is registered.

@github-actions github-actions Bot added the Stale label Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Strange bug with valid.expirationDate returning incorrect result in 2020

1 participant