Skip to content

Commit e5de284

Browse files
jeskewsrchase
authored andcommitted
Ready the V4 signer for clock skew
1 parent 49733c6 commit e5de284

File tree

2 files changed

+35
-31
lines changed

2 files changed

+35
-31
lines changed

packages/signature-v4/__tests__/SignatureV4.ts

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ import {Credentials, HttpRequest} from "@aws/types";
2020
import {iso8601} from "@aws/protocol-timestamp";
2121
import {PassThrough} from 'stream';
2222

23-
const MockDate = () => new Date('2000-01-01T00:00:00.000Z');
24-
2523
const signer = new SignatureV4({
2624
service: 'foo',
2725
region: 'us-bar-1',
@@ -50,14 +48,14 @@ const credentials: Credentials = {
5048
describe('SignatureV4', () => {
5149
describe('#presignRequest', () => {
5250
const expiration = Math.floor(
53-
(MockDate().valueOf() + 60 * 60 * 1000) / 1000
51+
((new Date('2000-01-01T00:00:00.000Z')).valueOf() + 60 * 60 * 1000) / 1000
5452
);
5553

5654
it('should sign requests without bodies', async () => {
5755
const {query} = await signer.presignRequest({
5856
request: minimalRequest,
5957
expiration,
60-
currentDateConstructor: MockDate as any,
58+
signingDate: new Date('2000-01-01T00:00:00.000Z'),
6159
});
6260
expect(query).toEqual({
6361
[ALGORITHM_QUERY_PARAM]: ALGORITHM_IDENTIFIER,
@@ -76,7 +74,7 @@ describe('SignatureV4', () => {
7674
body: 'It was the best of times, it was the worst of times'
7775
},
7876
expiration,
79-
currentDateConstructor: MockDate as any,
77+
signingDate: new Date('2000-01-01T00:00:00.000Z'),
8078
});
8179
expect(query).toEqual({
8280
[ALGORITHM_QUERY_PARAM]: ALGORITHM_IDENTIFIER,
@@ -95,7 +93,7 @@ describe('SignatureV4', () => {
9593
body: new Uint8Array([0xde, 0xad, 0xbe, 0xef])
9694
},
9795
expiration,
98-
currentDateConstructor: MockDate as any,
96+
signingDate: new Date('2000-01-01T00:00:00.000Z'),
9997
});
10098
expect(query).toEqual({
10199
[ALGORITHM_QUERY_PARAM]: ALGORITHM_IDENTIFIER,
@@ -114,7 +112,7 @@ describe('SignatureV4', () => {
114112
body: new PassThrough()
115113
},
116114
expiration,
117-
currentDateConstructor: MockDate as any,
115+
signingDate: new Date('2000-01-01T00:00:00.000Z'),
118116
});
119117
expect(query).toEqual({
120118
[ALGORITHM_QUERY_PARAM]: ALGORITHM_IDENTIFIER,
@@ -141,7 +139,7 @@ describe('SignatureV4', () => {
141139
const {query} = await signer.presignRequest({
142140
request: minimalRequest,
143141
expiration,
144-
currentDateConstructor: MockDate as any,
142+
signingDate: new Date('2000-01-01T00:00:00.000Z'),
145143
});
146144

147145
expect(query).toEqual({
@@ -173,7 +171,7 @@ describe('SignatureV4', () => {
173171
body: new Uint8Array([0xde, 0xad, 0xbe, 0xef]),
174172
},
175173
expiration,
176-
currentDateConstructor: MockDate as any,
174+
signingDate: new Date('2000-01-01T00:00:00.000Z'),
177175
});
178176

179177
expect(query).toEqual({
@@ -203,7 +201,7 @@ describe('SignatureV4', () => {
203201
},
204202
expiration,
205203
hoistHeaders: false,
206-
currentDateConstructor: MockDate as any,
204+
signingDate: new Date('2000-01-01T00:00:00.000Z'),
207205
});
208206
expect(query).toEqual({
209207
[ALGORITHM_QUERY_PARAM]: ALGORITHM_IDENTIFIER,
@@ -229,7 +227,7 @@ describe('SignatureV4', () => {
229227
},
230228
expiration,
231229
hoistHeaders: false,
232-
currentDateConstructor: MockDate as any,
230+
signingDate: new Date('2000-01-01T00:00:00.000Z'),
233231
unsignableHeaders: {foo: true}
234232
});
235233
expect((query as any)[SIGNED_HEADERS_QUERY_PARAM]).toBe('host;user-agent');
@@ -248,7 +246,7 @@ describe('SignatureV4', () => {
248246
},
249247
expiration,
250248
hoistHeaders: false,
251-
currentDateConstructor: MockDate as any,
249+
signingDate: new Date('2000-01-01T00:00:00.000Z'),
252250
});
253251
expect(query[EXPIRES_QUERY_PARAM]).toBe('3600');
254252
}
@@ -261,7 +259,7 @@ describe('SignatureV4', () => {
261259
signer.presignRequest({
262260
request: minimalRequest,
263261
expiration: new Date(),
264-
currentDateConstructor: MockDate as any,
262+
signingDate: new Date('2000-01-01T00:00:00.000Z'),
265263
})
266264
).rejects.toMatch(/less than one week in the future/);
267265
}
@@ -282,7 +280,7 @@ describe('SignatureV4', () => {
282280
it('should sign requests without bodies', async () => {
283281
const {headers} = await signer.signRequest({
284282
request: minimalRequest,
285-
currentDateConstructor: MockDate as any,
283+
signingDate: new Date('2000-01-01T00:00:00.000Z'),
286284
});
287285
expect(headers[AUTH_HEADER]).toBe(
288286
'AWS4-HMAC-SHA256 Credential=foo/20000101/us-bar-1/foo/aws4_request, SignedHeaders=host;x-amz-date, Signature=9fd83bc86a8d79b30697566790e40f832f280c9d7cbb343b213d1544a0273ebb'
@@ -295,7 +293,7 @@ describe('SignatureV4', () => {
295293
...minimalRequest,
296294
body: 'It was the best of times, it was the worst of times'
297295
},
298-
currentDateConstructor: MockDate as any,
296+
signingDate: new Date('2000-01-01T00:00:00.000Z'),
299297
});
300298
expect(headers[AUTH_HEADER]).toBe(
301299
'AWS4-HMAC-SHA256 Credential=foo/20000101/us-bar-1/foo/aws4_request, SignedHeaders=host;x-amz-date, Signature=b281e6664227db05f6f161b1d9725e030f9c2cddb91b42f8b93d7cbffa7eb796'
@@ -308,7 +306,7 @@ describe('SignatureV4', () => {
308306
...minimalRequest,
309307
body: new Uint8Array([0xde, 0xad, 0xbe, 0xef]),
310308
},
311-
currentDateConstructor: MockDate as any,
309+
signingDate: new Date('2000-01-01T00:00:00.000Z'),
312310
});
313311
expect(headers[AUTH_HEADER]).toBe(
314312
'AWS4-HMAC-SHA256 Credential=foo/20000101/us-bar-1/foo/aws4_request, SignedHeaders=host;x-amz-date, Signature=a8def96b8c754e523927d6a49392c02ff803ee49dc56549e244daf3f62b4abdd'
@@ -321,7 +319,7 @@ describe('SignatureV4', () => {
321319
...minimalRequest,
322320
body: new PassThrough(),
323321
},
324-
currentDateConstructor: MockDate as any,
322+
signingDate: new Date('2000-01-01T00:00:00.000Z'),
325323
});
326324

327325
expect(headers[AUTH_HEADER]).toBe(
@@ -333,7 +331,7 @@ describe('SignatureV4', () => {
333331
it(`should set the ${AMZ_DATE_HEADER}`, async () => {
334332
const {headers} = await signer.signRequest({
335333
request: minimalRequest,
336-
currentDateConstructor: MockDate as any,
334+
signingDate: new Date('2000-01-01T00:00:00.000Z'),
337335
});
338336
expect(headers[AMZ_DATE_HEADER]).toBe('20000101T000000Z');
339337
});
@@ -352,7 +350,7 @@ describe('SignatureV4', () => {
352350
});
353351
const {headers} = await signer.signRequest({
354352
request: minimalRequest,
355-
currentDateConstructor: MockDate as any,
353+
signingDate: new Date('2000-01-01T00:00:00.000Z'),
356354
});
357355
expect(headers[AUTH_HEADER]).toBe(
358356
'AWS4-HMAC-SHA256 Credential=foo/20000101/us-bar-1/foo/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=772bb343901420732ab811c947f90e1fafbc3b88697bad072b436a4e895b4bfc'
@@ -376,7 +374,7 @@ describe('SignatureV4', () => {
376374
...minimalRequest,
377375
body: new Uint8Array([0xde, 0xad, 0xbe, 0xef]),
378376
},
379-
currentDateConstructor: MockDate as any,
377+
signingDate: new Date('2000-01-01T00:00:00.000Z'),
380378
});
381379
expect(headers[AUTH_HEADER]).toBe(
382380
'AWS4-HMAC-SHA256 Credential=foo/20000101/us-bar-1/foo/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=2d17bf1aa1624819549626389790503937599b27a998286e0e190b897b1467dd'
@@ -385,7 +383,7 @@ describe('SignatureV4', () => {
385383
}
386384
);
387385

388-
it('should use the current date if no constructor supplied', async () => {
386+
it('should use the current date if no signing date supplied', async () => {
389387
const {headers} = await signer.signRequest({
390388
request: minimalRequest,
391389
});
@@ -404,7 +402,7 @@ describe('SignatureV4', () => {
404402
'user-agent': 'baz',
405403
},
406404
},
407-
currentDateConstructor: MockDate as any,
405+
signingDate: new Date('2000-01-01T00:00:00.000Z'),
408406
unsignableHeaders: {foo: true}
409407
});
410408
expect(headers[AUTH_HEADER]).toMatch(

packages/signature-v4/lib/SignatureV4.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,14 @@ export class SignatureV4 implements RequestSigner {
7474
presignRequest<StreamType>({
7575
request: originalRequest,
7676
expiration,
77-
currentDateConstructor = Date,
77+
signingDate = new Date(),
7878
hoistHeaders = true,
7979
unsignableHeaders = UNSIGNABLE_HEADERS,
8080
}: PresigningArguments<StreamType>): Promise<HttpRequest<StreamType>> {
8181
return Promise.all([this.regionProvider(), this.credentialProvider()])
8282
.then(([region, credentials]) => {
83-
const start = new currentDateConstructor();
84-
const {longDate, shortDate} = formatDate(start);
85-
const ttl = getTtl(start, expiration);
83+
const {longDate, shortDate} = formatDate(signingDate);
84+
const ttl = getTtl(signingDate, expiration);
8685
if (ttl > MAX_PRESIGNED_TTL) {
8786
return Promise.reject('Signature version 4 presigned URLs'
8887
+ ' must have an expiration date less than one week in'
@@ -135,13 +134,13 @@ export class SignatureV4 implements RequestSigner {
135134

136135
signRequest<StreamType>({
137136
request: originalRequest,
138-
currentDateConstructor = Date,
137+
signingDate = new Date(),
139138
unsignableHeaders = UNSIGNABLE_HEADERS,
140139
}: SigningArguments<StreamType>): Promise<HttpRequest<StreamType>> {
141140
return Promise.all([this.regionProvider(), this.credentialProvider()])
142141
.then(([region, credentials]) => {
143142
const request = prepareRequest(originalRequest);
144-
const {longDate, shortDate} = formatDate(new currentDateConstructor());
143+
const {longDate, shortDate} = formatDate(signingDate);
145144
const scope = createScope(shortDate, region, this.service);
146145
const keyPromise = this.getSigningKey(credentials, shortDate);
147146

@@ -279,7 +278,9 @@ function ensureRequestHasQuery<StreamType>(
279278
};
280279
}
281280

282-
function formatDate(now: Date): {longDate: string, shortDate: string} {
281+
function formatDate(
282+
now: string|number|Date
283+
): {longDate: string, shortDate: string} {
283284
const longDate = iso8601(now).replace(/[\-:]/g, '');
284285
return {
285286
longDate,
@@ -293,6 +294,11 @@ function getCanonicalHeaderList(headers: object): string {
293294
.join(';');
294295
}
295296

296-
function getTtl(start: Date, expiration: string|number|Date): number {
297-
return Math.floor((toDate(expiration).valueOf() - start.valueOf()) / 1000);
297+
function getTtl(
298+
start: string|number|Date,
299+
expiration: string|number|Date
300+
): number {
301+
return Math.floor(
302+
(toDate(expiration).valueOf() - toDate(start).valueOf()) / 1000
303+
);
298304
}

0 commit comments

Comments
 (0)