Skip to content

Commit

Permalink
fix(@aws-amplify/core): Support clock skew (#4844)
Browse files Browse the repository at this point in the history
* fix(@aws-amplify/core): AWS.config.systemClockOffset for signing requests

* Add Util/Date to support new Date() with clock offset

* Add tests for Utils.Date

* Signer users Util.Date

* Remove unused "date" for mocking

* Rename Date to DateUtils to allow "import { DateUtils }"

* Reference DateUtils directly vs. Utils.DateUtils

* Move DateUtils.test.ts so that core can build

* Add annotation to clockOffset for documentation & intellisense

* Fix test path

* Improve JSDoc

Co-authored-by: Thiago Hirata <hirata@devcase.com.br>
Co-authored-by: Sam Martinez  <sammartinez19@gmail.com>
  • Loading branch information
3 people authored Feb 6, 2020
1 parent 1ed9f0a commit 8156cc9
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 3 deletions.
37 changes: 37 additions & 0 deletions packages/core/__tests__/DateUtils-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { DateUtils } from '../src/Util/DateUtils';

// Mock Date (https://github.com/facebook/jest/issues/2234#issuecomment-308121037)
const staticDate = new Date('2020-01-01');
// @ts-ignore Type 'typeof Date' is not assignable to type 'DateConstructor'.
Date = class extends Date {
// @ts-ignore Constructors for derived classes must contain a 'super' call.ts(2377)
constructor() {
return staticDate;
}
};

describe('Date', () => {
describe('getDateWithClockOffset()', () => {
it('should return a new Date()', () => {
expect(DateUtils.getDateWithClockOffset()).toEqual(new Date());
});
});

describe('getClockOffset()', () => {
it('should default to 0', () => {
expect(DateUtils.getClockOffset()).toEqual(0);
});
});

describe('with setClockOffset()', () => {
beforeAll(() => {
DateUtils.setClockOffset(1000);
});

describe('getDate()', () => {
expect(DateUtils.getDateWithClockOffset()).toEqual(
new Date(new Date().getTime() + 1000)
);
});
});
});
6 changes: 5 additions & 1 deletion packages/core/__tests__/Signer-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ jest.mock('../src/Facet', () => {
};
return { update };
};

return {
AWS: ret,
};
});

import Signer from '../src/Signer';
import AWS from '../src';
import { DateUtils } from '../src';

describe('Signer test', () => {
describe('sign test', () => {
Expand All @@ -45,6 +46,8 @@ describe('Signer test', () => {
.spyOn(Date.prototype, 'toISOString')
.mockReturnValueOnce('0');

const getDateSpy = jest.spyOn(DateUtils, 'getDateWithClockOffset');

const res = {
headers: {
Authorization:
Expand All @@ -56,6 +59,7 @@ describe('Signer test', () => {
url: url,
};
expect(Signer.sign(request, access_info)).toEqual(res);
expect(getDateSpy).toHaveBeenCalledTimes(1);

spyon.mockClear();
});
Expand Down
7 changes: 5 additions & 2 deletions packages/core/src/Signer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/

import { ConsoleLogger as Logger } from './Logger';
import { DateUtils } from './Util';
import { AWS } from './Facet';

const logger = new Logger('Signer'),
Expand Down Expand Up @@ -299,7 +300,7 @@ export default class Signer {
request.headers = request.headers || {};

// datetime string and date string
const dt = new Date(),
const dt = DateUtils.getDateWithClockOffset(),
dt_str = dt.toISOString().replace(/[:\-]|\.\d{3}/g, ''),
d_str = dt_str.substr(0, 8);

Expand Down Expand Up @@ -370,7 +371,9 @@ export default class Signer {
const body: any =
typeof urlOrRequest === 'object' ? urlOrRequest.body : undefined;

const now = new Date().toISOString().replace(/[:\-]|\.\d{3}/g, '');
const now = DateUtils.getDateWithClockOffset()
.toISOString()
.replace(/[:\-]|\.\d{3}/g, '');
const today = now.substr(0, 8);
// Intentionally discarding search
const { search, ...parsedUrl } = url.parse(urlToSign, true, true);
Expand Down
35 changes: 35 additions & 0 deletions packages/core/src/Util/DateUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Date & time utility functions to abstract the `aws-sdk` away from users.
* (v2 => v3 modularization is a breaking change)
*
* @see https://github.com/aws/aws-sdk-js/blob/6edf586dcc1de7fe8fbfbbd9a0d2b1847921e6e1/lib/util.js#L262
*/

export const DateUtils = {
/**
* Milliseconds to offset the date to compensate for clock skew between device & services
*/
clockOffset: 0,

getDateWithClockOffset() {
if (DateUtils.clockOffset) {
return new Date(new Date().getTime() + DateUtils.clockOffset);
} else {
return new Date();
}
},

/**
* @returns {number} Clock offset in milliseconds
*/
getClockOffset() {
return DateUtils.clockOffset;
},

/**
* @param {number} offset Clock offset in milliseconds
*/
setClockOffset(offset: number) {
DateUtils.clockOffset = offset;
},
};
1 change: 1 addition & 0 deletions packages/core/src/Util/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './Retry';
export { default as Mutex } from './Mutex';
export { default as Reachability } from './Reachability';
export * from './DateUtils';

0 comments on commit 8156cc9

Please sign in to comment.