Compare commits

..

5 Commits

Author SHA1 Message Date
Frédéric Meinnel 6927f2b6ee yay 2024-01-11 17:04:08 +01:00
Frédéric Meinnel f5fc423b0f handle non utc input date 2024-01-11 16:10:15 +01:00
Frédéric Meinnel d8dc674a1a fixing the lifecycle configuration date parsing 2024-01-11 15:32:05 +01:00
Frédéric Meinnel 471c122e99 add content-md5 header to signed headers 2024-01-11 14:53:25 +01:00
Frédéric Meinnel 22b5de96db adding payload to generateV4Headers 2024-01-11 12:18:14 +01:00
4 changed files with 46 additions and 8 deletions

View File

@ -181,7 +181,8 @@ function generateV4Headers(
secretKeyValue: string, secretKeyValue: string,
awsService: string, awsService: string,
proxyPath: string, proxyPath: string,
sessionToken: string sessionToken: string,
payload: string,
) { ) {
Object.assign(request, { headers: {} }); Object.assign(request, { headers: {} });
const amzDate = convertUTCtoISO8601(Date.now()); const amzDate = convertUTCtoISO8601(Date.now());
@ -194,7 +195,7 @@ function generateV4Headers(
const timestamp = amzDate; const timestamp = amzDate;
const algorithm = 'AWS4-HMAC-SHA256'; const algorithm = 'AWS4-HMAC-SHA256';
let payload = ''; payload = payload || '';
if (request.method === 'POST') { if (request.method === 'POST') {
payload = queryString.stringify(data, undefined, undefined, { payload = queryString.stringify(data, undefined, undefined, {
encodeURIComponent, encodeURIComponent,
@ -205,7 +206,8 @@ function generateV4Headers(
request.setHeader('host', request._headers.host); request.setHeader('host', request._headers.host);
request.setHeader('x-amz-date', amzDate); request.setHeader('x-amz-date', amzDate);
request.setHeader('x-amz-content-sha256', payloadChecksum); request.setHeader('x-amz-content-sha256', payloadChecksum);
request.setHeader('content-md5', crypto.createHash('md5')
.update(payload, 'binary').digest('base64'))
if (sessionToken) { if (sessionToken) {
request.setHeader('x-amz-security-token', sessionToken); request.setHeader('x-amz-security-token', sessionToken);
} }
@ -215,6 +217,7 @@ function generateV4Headers(
.filter(headerName => .filter(headerName =>
headerName.startsWith('x-amz-') headerName.startsWith('x-amz-')
|| headerName.startsWith('x-scal-') || headerName.startsWith('x-scal-')
|| headerName === 'content-md5'
|| headerName === 'host' || headerName === 'host'
).sort().join(';'); ).sort().join(';');
const params = { request, signedHeaders, payloadChecksum, const params = { request, signedHeaders, payloadChecksum,

View File

@ -501,15 +501,27 @@ export default class LifecycleConfiguration {
_checkDate(date: string) { _checkDate(date: string) {
const isoRegex = new RegExp('^(-?(?:[1-9][0-9]*)?[0-9]{4})-' + const isoRegex = new RegExp('^(-?(?:[1-9][0-9]*)?[0-9]{4})-' +
'(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9])' + '(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9])' +
':([0-5][0-9]):([0-5][0-9])(\\.[0-9]+)?(Z)?$'); ':([0-5][0-9]):([0-5][0-9])(\\.[0-9]+)?(Z|[+-][0-5][0-9]:[0-5][0-9])?$');
if (!isoRegex.test(date)) { if (!isoRegex.test(date)) {
const msg = 'Date must be in ISO 8601 format'; const msg = 'Date must be in ISO 8601 format';
return errors.InvalidArgument.customizeDescription(msg); return errors.InvalidArgument.customizeDescription(msg);
} }
const midnightRegex = new RegExp('^(-?(?:[1-9][0-9]*)?[0-9]{4})-' + // Extract the time portion of the date string to check if a timezone
'(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T00' + // is specified. If not, add a Z to indicate UTC. We split to avoid
':00:00(\\.0+)?(Z)?$'); // then hyphens in the date portion.
if (!midnightRegex.test(date)) { const time = date.split('T')[1];
if (!time.includes('Z') && !time.includes('+') && !time.includes('-')) {
date += 'Z';
}
const dateObj = new Date(date);
if (Number.isNaN(dateObj.getTime())) {
const msg = 'Date is not a valid date';
return errors.InvalidArgument.customizeDescription(msg);
}
if (dateObj.getUTCHours() !== 0
|| dateObj.getUTCMinutes() !== 0
|| dateObj.getUTCSeconds() !== 0
|| dateObj.getUTCMilliseconds() !== 0) {
const msg = '\'Date\' must be at midnight GMT'; const msg = '\'Date\' must be at midnight GMT';
return errors.InvalidArgument.customizeDescription(msg); return errors.InvalidArgument.customizeDescription(msg);
} }

View File

@ -80,6 +80,7 @@
"lint_md": "mdlint $(git ls-files '*.md')", "lint_md": "mdlint $(git ls-files '*.md')",
"lint_yml": "yamllint $(git ls-files '*.yml')", "lint_yml": "yamllint $(git ls-files '*.yml')",
"test": "jest tests/unit", "test": "jest tests/unit",
"test_auth": "jest tests/unit/auth",
"build": "tsc", "build": "tsc",
"prepare": "yarn build", "prepare": "yarn build",
"ft_test": "jest tests/functional --testTimeout=120000 --forceExit", "ft_test": "jest tests/functional --testTimeout=120000 --forceExit",

View File

@ -420,6 +420,12 @@ describe('LifecycleConfiguration', () => {
assert.strictEqual(error, null); assert.strictEqual(error, null);
}); });
it('should return no error with a valid ISO date at midnight with timezone', () => {
const date = '2024-01-08T06:00:00+06:00';
const error = lifecycleConfiguration._checkDate(date);
assert.strictEqual(error, null);
});
it('should return an error with a non-ISO date', () => { it('should return an error with a non-ISO date', () => {
const date = '2016-01-01T00:00:00000Z'; const date = '2016-01-01T00:00:00000Z';
const error = lifecycleConfiguration._checkDate(date); const error = lifecycleConfiguration._checkDate(date);
@ -436,6 +442,14 @@ describe('LifecycleConfiguration', () => {
expect(error.description).toEqual(msg); expect(error.description).toEqual(msg);
}); });
it('should return an error with a non-ISO date', () => {
const date = '2024-01-08T00:00:00+34:00';
const error = lifecycleConfiguration._checkDate(date);
const msg = 'Date is not a valid date';
expect(error.is.InvalidArgument).toBeTruthy();
expect(error.description).toEqual(msg);
});
it('should return an error with a date that is not set to midnight', () => { it('should return an error with a date that is not set to midnight', () => {
const date = '2024-01-04T15:22:40Z'; const date = '2024-01-04T15:22:40Z';
const error = lifecycleConfiguration._checkDate(date); const error = lifecycleConfiguration._checkDate(date);
@ -443,6 +457,14 @@ describe('LifecycleConfiguration', () => {
expect(error.is.InvalidArgument).toBeTruthy(); expect(error.is.InvalidArgument).toBeTruthy();
expect(error.description).toEqual(msg); expect(error.description).toEqual(msg);
}); });
it('should return an error with a date that is not set to midnight', () => {
const date = '2024-01-08T00:00:00.123Z';
const error = lifecycleConfiguration._checkDate(date);
const msg = '\'Date\' must be at midnight GMT';
expect(error.is.InvalidArgument).toBeTruthy();
expect(error.description).toEqual(msg);
});
}); });
}); });