ARSN-552: don't throw in case of bad Date inputs#2591
ARSN-552: don't throw in case of bad Date inputs#2591leif-scality wants to merge 2 commits intodevelopment/8.2from
Conversation
Hello leif-scality,My role is to assist you with the merge of this Available options
Available commands
Status report is not available. |
c4ded38 to
4bfcb47
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## development/8.2 #2591 +/- ##
===================================================
+ Coverage 71.41% 71.43% +0.01%
===================================================
Files 222 222
Lines 17918 17937 +19
Branches 3728 3733 +5
===================================================
+ Hits 12797 12813 +16
- Misses 5117 5120 +3
Partials 4 4 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
4bfcb47 to
4be2cc6
Compare
1c8bc34 to
c208871
Compare
lib/auth/v4/timeUtils.ts
Outdated
| // Check length | ||
| if (str.length !== 16) { | ||
| return false; | ||
| } | ||
|
|
||
| // Check 'T' at position 8 and 'Z' at position 15 | ||
| if (str[8] !== 'T' || str[15] !== 'Z') { | ||
| return false; | ||
| } | ||
|
|
||
| // Check all other positions are digits | ||
| for (let i = 0; i < 16; i++) { | ||
| if (i === 8 || i === 15) { | ||
| continue; // Skip T and Z | ||
| } | ||
| if (str[i] < '0' || str[i] > '9') { | ||
| return false; | ||
| } | ||
| } |
There was a problem hiding this comment.
This could be simplified and more maintainable with a regex.
Ideally we should use a date library for date manipulation or validation, but I see we don't have any in arsenal
There was a problem hiding this comment.
Do we want to compile and run a regex for each request? I agree the regex is simpler, but the code is not that complicated
There was a problem hiding this comment.
I tend to agree with @BourgoisMickael , I'd prefer a regexp, it's cleaner and less error-prone (and maybe more efficient too, but that would have to be tested). Normally if you use a static regexp (/.../) it's pre-compiled automatically.
Also you can use the result of the regexp parsing to extract components, instead of using substring.
There was a problem hiding this comment.
changed to regex
lib/auth/v4/timeUtils.ts
Outdated
| * convertUTCtoISO8601(1328910895000); // '20120210T213455Z' | ||
| * convertUTCtoISO8601('invalid'); // undefined | ||
| */ | ||
| export function convertUTCtoISO8601(timestamp: unknown): string | undefined { |
There was a problem hiding this comment.
instead of unknown the type should be string | number | null (maybe even | undefined but there is no check for undefined.
There was a problem hiding this comment.
replaced with string | number
lib/auth/auth.ts
Outdated
| Object.assign(request, { headers: {} }); | ||
| const amzDate = convertUTCtoISO8601(Date.now()); | ||
| // Date.now() should always return a valid date so we assert non null. | ||
| const amzDate: string = convertUTCtoISO8601(Date.now())!; |
There was a problem hiding this comment.
if there is a non-null assertion, then you don't need to add the type string, it's the only type left as output of the function
There was a problem hiding this comment.
removed the type
tests/unit/auth/v4/timeUtils.spec.js
Outdated
| it('should convert Date.now() to ISO8601 timestamp', () => { | ||
| const now = Date.now(); |
There was a problem hiding this comment.
prefer a fixed date like the test above should be enough, this test doesn't provide more coverage
There was a problem hiding this comment.
removed the test we already have a test with new Date
tests/unit/auth/v4/timeUtils.spec.js
Outdated
| it('should return undefined for object', () => { | ||
| const actualOutput = convertUTCtoISO8601({}); |
There was a problem hiding this comment.
this should be a typescript error if the function is typed correctly
There was a problem hiding this comment.
the function accepts any even in typescript so we need to test the case. Even with the type string | number
tests/unit/auth/v4/timeUtils.spec.js
Outdated
| const input = '20160208T201405Z'; | ||
| assert.strictEqual(isValidISO8601Compact(input), true); |
There was a problem hiding this comment.
| const input = '20160208T201405Z'; | |
| assert.strictEqual(isValidISO8601Compact(input), true); | |
| assert.strictEqual(isValidISO8601Compact('20160208T201405Z'), true); |
you can go one line like the describe a little below here
There was a problem hiding this comment.
refactored to array
tests/unit/auth/v4/timeUtils.spec.js
Outdated
| }); | ||
| }); | ||
|
|
||
| describe('null/undefined/non-string inputs', () => { |
There was a problem hiding this comment.
anything other than string should raise a typescript error here, you should not be able to use another type
There was a problem hiding this comment.
Oh the file is javascript, that's why you have no typescript error in there
There was a problem hiding this comment.
the function accepts any even in typescript so we need to test the case. Even with the type string | number
tests/unit/auth/v4/timeUtils.spec.js
Outdated
| }); | ||
|
|
||
| describe('invalid format', () => { | ||
| it('should return false for string with wrong length', () => { |
There was a problem hiding this comment.
you could use an array of (test name, input) and loop over it
[
{ name: 'should return false for string with wrong length', input: '2016020T201405Z' },
// ...
].forEach(t => it(t.name, () => assert.strictEqual(isValidISO8601Compact(t.input), false))c208871 to
a3b28b8
Compare
lib/auth/v4/timeUtils.ts
Outdated
| // Check length | ||
| if (str.length !== 16) { | ||
| return false; | ||
| } | ||
|
|
||
| // Check 'T' at position 8 and 'Z' at position 15 | ||
| if (str[8] !== 'T' || str[15] !== 'Z') { | ||
| return false; | ||
| } | ||
|
|
||
| // Check all other positions are digits | ||
| for (let i = 0; i < 16; i++) { | ||
| if (i === 8 || i === 15) { | ||
| continue; // Skip T and Z | ||
| } | ||
| if (str[i] < '0' || str[i] > '9') { | ||
| return false; | ||
| } | ||
| } |
There was a problem hiding this comment.
I tend to agree with @BourgoisMickael , I'd prefer a regexp, it's cleaner and less error-prone (and maybe more efficient too, but that would have to be tested). Normally if you use a static regexp (/.../) it's pre-compiled automatically.
Also you can use the result of the regexp parsing to extract components, instead of using substring.
lib/auth/v4/timeUtils.ts
Outdated
| try { | ||
| // date.toISOString() can throw. | ||
| // date.toISOString() === isoString check prevents silent date corrections (30 February to 1 March) | ||
| return !isNaN(date.getTime()) && date.toISOString() === isoString; |
There was a problem hiding this comment.
nitpick: you can use Number.isNaN to be strict about checking exclusively a NaN value (rather than anything that is not parsable to a valid number)
There was a problem hiding this comment.
changed to Number.isNaN
tests/unit/auth/v4/timeUtils.spec.js
Outdated
| const convertUTCtoISO8601 = | ||
| require('../../../../lib/auth/v4/timeUtils').convertUTCtoISO8601; | ||
| const isValidISO8601Compact = | ||
| require('../../../../lib/auth/v4/timeUtils').isValidISO8601Compact; |
There was a problem hiding this comment.
| require('../../../../lib/auth/v4/timeUtils').isValidISO8601Compact; | |
| const { | |
| checkTimeSkew, | |
| convertAmzTimeToMs, | |
| convertUTCtoISO8601, | |
| isValidISO8601Compact, | |
| } = require('../../../../lib/auth/v4/timeUtils'); |
b0bb4dd to
a81fb2d
Compare
| * ``` | ||
| */ | ||
| export function isValidISO8601Compact(str: string): boolean { | ||
| if (str == null || typeof str !== 'string') { |
There was a problem hiding this comment.
nitpick: typeof str !== 'string' would suffice
Don't throw and crash cloudserver in case of an invalid Date header
Repro code: