From 34ae33af6f1284ef6f1c9612312a855ae970f39b Mon Sep 17 00:00:00 2001 From: Sam Olsen Date: Fri, 10 Apr 2020 12:20:45 -0700 Subject: [PATCH 1/7] Initial user object implementation --- .../auth-exp/src/core/user_impl.test.ts | 84 ++++++++++++++++ packages-exp/auth-exp/src/core/user_impl.ts | 70 ++++++++++++++ packages-exp/auth-exp/src/model/user.d.ts | 19 +++- packages-exp/auth-exp/test/mock_auth.ts | 27 ++++++ yarn.lock | 96 +++++++++++-------- 5 files changed, 250 insertions(+), 46 deletions(-) create mode 100644 packages-exp/auth-exp/src/core/user_impl.test.ts create mode 100644 packages-exp/auth-exp/src/core/user_impl.ts create mode 100644 packages-exp/auth-exp/test/mock_auth.ts diff --git a/packages-exp/auth-exp/src/core/user_impl.test.ts b/packages-exp/auth-exp/src/core/user_impl.test.ts new file mode 100644 index 00000000000..e09e3341c62 --- /dev/null +++ b/packages-exp/auth-exp/src/core/user_impl.test.ts @@ -0,0 +1,84 @@ +/** + * @license + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect } from 'chai'; +import { UserImpl } from './user_impl'; +import { mockAuth } from '../../test/mock_auth'; + +describe('core/user_impl', () => { + const auth = mockAuth('foo', 'i-am-the-api-key'); + + describe('constructor', () => { + it('attaches required fields', () => { + const user = new UserImpl({uid: 'uid', auth}); + expect(user.auth).to.eq(auth); + expect(user.uid).to.eq('uid'); + }); + + it('attaches optional fields if provided', () => { + const user = new UserImpl({ + uid: 'uid', + auth, + displayName: 'displayName', + email: 'email', + phoneNumber: 'phoneNumber', + photoURL: 'photoURL', + }); + + expect(user.displayName).to.eq('displayName'); + expect(user.email).to.eq('email'); + expect(user.phoneNumber).to.eq('phoneNumber'); + expect(user.photoURL).to.eq('photoURL'); + }); + + it('sets optional fields to null if not provided', () => { + const user = new UserImpl({uid: 'uid', auth}); + expect(user.displayName).to.eq(null); + expect(user.email).to.eq(null); + expect(user.phoneNumber).to.eq(null); + expect(user.photoURL).to.eq(null); + }); + }); + + describe('#getIdToken', () => { + it('throws', () => { + const user = new UserImpl({uid: 'uid', auth}); + expect(() => user.getIdToken()).to.throw(); + }); + }); + + describe('#getIdTokenResult', () => { + it('throws', () => { + const user = new UserImpl({uid: 'uid', auth}); + expect(() => user.getIdTokenResult()).to.throw(); + }); + }); + + describe('#reload', () => { + it('throws', () => { + const user = new UserImpl({uid: 'uid', auth}); + expect(() => user.reload()).to.throw(); + }); + }); + + describe('#delete', () => { + it('throws', () => { + const user = new UserImpl({uid: 'uid', auth}); + expect(() => user.delete()).to.throw(); + }); + }); +}); \ No newline at end of file diff --git a/packages-exp/auth-exp/src/core/user_impl.ts b/packages-exp/auth-exp/src/core/user_impl.ts new file mode 100644 index 00000000000..b2933ccb503 --- /dev/null +++ b/packages-exp/auth-exp/src/core/user_impl.ts @@ -0,0 +1,70 @@ +/** + * @license + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { User } from '../model/user'; +import { Auth } from '../model/auth'; +import { IdTokenResult } from '../model/id_token'; +import { ProviderId } from './providers'; + +export interface UserParameters { + uid: string; + auth: Auth; + + displayName?: string; + email?: string; + phoneNumber?: string; + photoURL?: string; +} + +export class UserImpl implements User { + // For the user object, provider is always Firebase. + readonly providerId = ProviderId.FIREBASE; + + uid: string; + auth: Auth; + + // Optional fields from UserInfo + displayName: string | null; + email: string | null; + phoneNumber: string | null; + photoURL: string | null; + + constructor({uid, auth, ...opt}: UserParameters) { + this.uid = uid; + this.auth = auth; + this.displayName = opt.displayName || null; + this.email = opt.email || null; + this.phoneNumber = opt.phoneNumber || null; + this.photoURL = opt.photoURL || null; + } + + getIdToken(forceRefresh?: boolean): Promise { + throw new Error(`Method not implemented. forceRefresh: ${forceRefresh}`); + } + + getIdTokenResult(forceRefresh?: boolean): Promise { + throw new Error(`Method not implemented. forceRefresh: ${forceRefresh}`); + } + + reload(): Promise { + throw new Error('Method not implemented.'); + } + + delete(): Promise { + throw new Error('Method not implemented.'); + } +} \ No newline at end of file diff --git a/packages-exp/auth-exp/src/model/user.d.ts b/packages-exp/auth-exp/src/model/user.d.ts index 361ca3b6e68..343efc47a56 100644 --- a/packages-exp/auth-exp/src/model/user.d.ts +++ b/packages-exp/auth-exp/src/model/user.d.ts @@ -15,14 +15,23 @@ * limitations under the License. */ +import { IdTokenResult } from "./id_token"; +import { ProviderId } from "../core/providers"; + export interface UserInfo { readonly uid: string; -} - -export interface UserParameters { - uid: string; + readonly providerId: ProviderId; + readonly displayName: string | null; + readonly email: string | null; + readonly phoneNumber: string | null; + readonly photoURL: string | null; } export interface User extends UserInfo { - uid: string; + providerId: ProviderId.FIREBASE; + + getIdToken(forceRefresh?: boolean): Promise; + getIdTokenResult(forceRefresh?: boolean): Promise; + reload(): Promise; + delete(): Promise; } diff --git a/packages-exp/auth-exp/test/mock_auth.ts b/packages-exp/auth-exp/test/mock_auth.ts new file mode 100644 index 00000000000..6d0ab0b3ae8 --- /dev/null +++ b/packages-exp/auth-exp/test/mock_auth.ts @@ -0,0 +1,27 @@ +/** + * @license + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AppName, ApiKey, Auth } from '../src/model/auth'; + +export function mockAuth(name: AppName, apiKey: ApiKey): Auth { + return { + name, + config: { + apiKey, + } + }; +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index f1c0e41c024..b76140956f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10397,6 +10397,36 @@ mocha@7.1.0: yargs-parser "13.1.1" yargs-unparser "1.6.0" +mocha@^7.1.1: + version "7.1.1" + resolved "https://registry.npmjs.org/mocha/-/mocha-7.1.1.tgz#89fbb30d09429845b1bb893a830bf5771049a441" + integrity sha512-3qQsu3ijNS3GkWcccT5Zw0hf/rWvu1fTN9sPvEd81hlwsr30GX2GcDSSoBxo24IR8FelmrAydGC6/1J5QQP4WA== + dependencies: + ansi-colors "3.2.3" + browser-stdout "1.3.1" + chokidar "3.3.0" + debug "3.2.6" + diff "3.5.0" + escape-string-regexp "1.0.5" + find-up "3.0.0" + glob "7.1.3" + growl "1.10.5" + he "1.2.0" + js-yaml "3.13.1" + log-symbols "3.0.0" + minimatch "3.0.4" + mkdirp "0.5.3" + ms "2.1.1" + node-environment-flags "1.0.6" + object.assign "4.1.0" + strip-json-comments "2.0.1" + supports-color "6.0.0" + which "1.3.1" + wide-align "1.1.3" + yargs "13.3.2" + yargs-parser "13.1.2" + yargs-unparser "1.6.0" + modify-values@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" @@ -10692,22 +10722,6 @@ node-localstorage@^1.3.1: dependencies: write-file-atomic "^1.1.4" -node-pre-gyp@*: - version "0.14.0" - resolved "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83" - integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4.4.2" - node-pre-gyp@^0.11.0: version "0.11.0" resolved "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054" @@ -13915,7 +13929,7 @@ tar@4.4.2: safe-buffer "^5.1.2" yallist "^3.0.2" -tar@^4, tar@^4.3.0, tar@^4.4.10, tar@^4.4.12, tar@^4.4.2, tar@^4.4.8: +tar@^4, tar@^4.3.0, tar@^4.4.10, tar@^4.4.12, tar@^4.4.8: version "4.4.13" resolved "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== @@ -15483,14 +15497,7 @@ yargs-parser@13.1.1: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^10.0.0: - version "10.1.0" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" - integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== - dependencies: - camelcase "^4.1.0" - -yargs-parser@^13.1.0, yargs-parser@^13.1.1, yargs-parser@^13.1.2: +yargs-parser@13.1.2, yargs-parser@^13.1.0, yargs-parser@^13.1.1, yargs-parser@^13.1.2: version "13.1.2" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== @@ -15498,6 +15505,13 @@ yargs-parser@^13.1.0, yargs-parser@^13.1.1, yargs-parser@^13.1.2: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^10.0.0: + version "10.1.0" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" + integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== + dependencies: + camelcase "^4.1.0" + yargs-parser@^15.0.1: version "15.0.1" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz#54786af40b820dcb2fb8025b11b4d659d76323b3" @@ -15563,6 +15577,22 @@ yargs@13.3.0: y18n "^4.0.0" yargs-parser "^13.1.1" +yargs@13.3.2, yargs@^13.3.0: + version "13.3.2" + resolved "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" + integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.2" + yargs@15.3.1, yargs@^15.0.2: version "15.3.1" resolved "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b" @@ -15580,22 +15610,6 @@ yargs@15.3.1, yargs@^15.0.2: y18n "^4.0.0" yargs-parser "^18.1.1" -yargs@^13.3.0: - version "13.3.2" - resolved "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" - integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.2" - yargs@^14.2.2: version "14.2.3" resolved "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz#1a1c3edced1afb2a2fea33604bc6d1d8d688a414" From 4a3a1258152b8132d9ff491903d1453f290b85df Mon Sep 17 00:00:00 2001 From: Sam Olsen Date: Fri, 10 Apr 2020 12:20:58 -0700 Subject: [PATCH 2/7] [AUTOMATED]: Prettier Code Styling --- packages-exp/auth-exp/src/core/user_impl.test.ts | 16 ++++++++-------- packages-exp/auth-exp/src/core/user_impl.ts | 6 +++--- packages-exp/auth-exp/src/model/user.d.ts | 4 ++-- packages-exp/auth-exp/test/mock_auth.ts | 4 ++-- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages-exp/auth-exp/src/core/user_impl.test.ts b/packages-exp/auth-exp/src/core/user_impl.test.ts index e09e3341c62..ad5ab731908 100644 --- a/packages-exp/auth-exp/src/core/user_impl.test.ts +++ b/packages-exp/auth-exp/src/core/user_impl.test.ts @@ -24,7 +24,7 @@ describe('core/user_impl', () => { describe('constructor', () => { it('attaches required fields', () => { - const user = new UserImpl({uid: 'uid', auth}); + const user = new UserImpl({ uid: 'uid', auth }); expect(user.auth).to.eq(auth); expect(user.uid).to.eq('uid'); }); @@ -36,7 +36,7 @@ describe('core/user_impl', () => { displayName: 'displayName', email: 'email', phoneNumber: 'phoneNumber', - photoURL: 'photoURL', + photoURL: 'photoURL' }); expect(user.displayName).to.eq('displayName'); @@ -46,7 +46,7 @@ describe('core/user_impl', () => { }); it('sets optional fields to null if not provided', () => { - const user = new UserImpl({uid: 'uid', auth}); + const user = new UserImpl({ uid: 'uid', auth }); expect(user.displayName).to.eq(null); expect(user.email).to.eq(null); expect(user.phoneNumber).to.eq(null); @@ -56,29 +56,29 @@ describe('core/user_impl', () => { describe('#getIdToken', () => { it('throws', () => { - const user = new UserImpl({uid: 'uid', auth}); + const user = new UserImpl({ uid: 'uid', auth }); expect(() => user.getIdToken()).to.throw(); }); }); describe('#getIdTokenResult', () => { it('throws', () => { - const user = new UserImpl({uid: 'uid', auth}); + const user = new UserImpl({ uid: 'uid', auth }); expect(() => user.getIdTokenResult()).to.throw(); }); }); describe('#reload', () => { it('throws', () => { - const user = new UserImpl({uid: 'uid', auth}); + const user = new UserImpl({ uid: 'uid', auth }); expect(() => user.reload()).to.throw(); }); }); describe('#delete', () => { it('throws', () => { - const user = new UserImpl({uid: 'uid', auth}); + const user = new UserImpl({ uid: 'uid', auth }); expect(() => user.delete()).to.throw(); }); }); -}); \ No newline at end of file +}); diff --git a/packages-exp/auth-exp/src/core/user_impl.ts b/packages-exp/auth-exp/src/core/user_impl.ts index b2933ccb503..23821eef530 100644 --- a/packages-exp/auth-exp/src/core/user_impl.ts +++ b/packages-exp/auth-exp/src/core/user_impl.ts @@ -23,7 +23,7 @@ import { ProviderId } from './providers'; export interface UserParameters { uid: string; auth: Auth; - + displayName?: string; email?: string; phoneNumber?: string; @@ -43,7 +43,7 @@ export class UserImpl implements User { phoneNumber: string | null; photoURL: string | null; - constructor({uid, auth, ...opt}: UserParameters) { + constructor({ uid, auth, ...opt }: UserParameters) { this.uid = uid; this.auth = auth; this.displayName = opt.displayName || null; @@ -67,4 +67,4 @@ export class UserImpl implements User { delete(): Promise { throw new Error('Method not implemented.'); } -} \ No newline at end of file +} diff --git a/packages-exp/auth-exp/src/model/user.d.ts b/packages-exp/auth-exp/src/model/user.d.ts index 343efc47a56..ac4591ce355 100644 --- a/packages-exp/auth-exp/src/model/user.d.ts +++ b/packages-exp/auth-exp/src/model/user.d.ts @@ -15,8 +15,8 @@ * limitations under the License. */ -import { IdTokenResult } from "./id_token"; -import { ProviderId } from "../core/providers"; +import { IdTokenResult } from './id_token'; +import { ProviderId } from '../core/providers'; export interface UserInfo { readonly uid: string; diff --git a/packages-exp/auth-exp/test/mock_auth.ts b/packages-exp/auth-exp/test/mock_auth.ts index 6d0ab0b3ae8..23a2b26de16 100644 --- a/packages-exp/auth-exp/test/mock_auth.ts +++ b/packages-exp/auth-exp/test/mock_auth.ts @@ -21,7 +21,7 @@ export function mockAuth(name: AppName, apiKey: ApiKey): Auth { return { name, config: { - apiKey, + apiKey } }; -} \ No newline at end of file +} From af1571a454a59fe37d261813bfd0b3428a793a34 Mon Sep 17 00:00:00 2001 From: Sam Olsen Date: Fri, 10 Apr 2020 15:26:41 -0700 Subject: [PATCH 3/7] Add token manager --- .../src/core/user/token_manager.test.ts | 99 +++++++++++++++++++ .../auth-exp/src/core/user/token_manager.ts | 63 ++++++++++++ .../src/core/{ => user}/user_impl.test.ts | 50 +++++++--- .../auth-exp/src/core/{ => user}/user_impl.ts | 29 ++++-- packages-exp/auth-exp/src/model/id_token.d.ts | 20 ++++ packages-exp/auth-exp/src/model/user.d.ts | 1 + 6 files changed, 240 insertions(+), 22 deletions(-) create mode 100644 packages-exp/auth-exp/src/core/user/token_manager.test.ts create mode 100644 packages-exp/auth-exp/src/core/user/token_manager.ts rename packages-exp/auth-exp/src/core/{ => user}/user_impl.test.ts (54%) rename packages-exp/auth-exp/src/core/{ => user}/user_impl.ts (62%) diff --git a/packages-exp/auth-exp/src/core/user/token_manager.test.ts b/packages-exp/auth-exp/src/core/user/token_manager.test.ts new file mode 100644 index 00000000000..201dc759327 --- /dev/null +++ b/packages-exp/auth-exp/src/core/user/token_manager.test.ts @@ -0,0 +1,99 @@ +/** + * @license + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect, use } from 'chai'; +import * as chaiAsPromised from 'chai-as-promised'; +import { StsTokenManager, DATE_GENERATOR } from './token_manager'; +import { IdTokenResponse } from '../../model/id_token'; +import { createSandbox } from 'sinon'; + +use(chaiAsPromised); + +const sandbox = createSandbox(); + +describe('core/user/token_manager', () => { + let stsTokenManager: StsTokenManager; + let now: number; + + beforeEach(() => { + stsTokenManager = new StsTokenManager(); + now = Date.now(); + sandbox.stub(DATE_GENERATOR, 'now').returns(now); + }); + + afterEach(() => sandbox.restore()); + + describe('#isExpired', () => { + it('is true if past expiration time', () => { + stsTokenManager.expirationTime = 1; // Ancient history + expect(stsTokenManager.isExpired).to.eq(true); + }); + + it('is true if exp is in future but within buffer', () => { + // Buffer is 30_000 + stsTokenManager.expirationTime = now + 20_000; + expect(stsTokenManager.isExpired).to.eq(true); + }); + + it('is fals if exp is far enough in future', () => { + stsTokenManager.expirationTime = now + 40_000; + expect(stsTokenManager.isExpired).to.eq(false); + }); + }); + + describe('#updateFromServerResponse', () => { + it('sets all the fields correctly', () => { + stsTokenManager.updateFromServerResponse({ + idToken: 'id-token', + refreshToken: 'refresh-token', + expiresIn: '60', // From the server this is 30s + } as IdTokenResponse); + + expect(stsTokenManager.expirationTime).to.eq(now + 60_000); + expect(stsTokenManager.accessToken).to.eq('id-token'); + expect(stsTokenManager.refreshToken).to.eq('refresh-token'); + }); + }); + + describe('#getToken', () => { + it('throws if forceRefresh is true', async () => { + Object.assign(stsTokenManager, {accessToken: 'token', expirationTime: now + 100_000}); + await expect(stsTokenManager.getToken(true)).to.be.rejectedWith(Error); + }); + + it('throws if token is expired', async () => { + Object.assign(stsTokenManager, {accessToken: 'token', expirationTime: now - 1}); + await expect(stsTokenManager.getToken()).to.be.rejectedWith(Error); + }); + + it('throws if access token is missing', async () => { + await expect(stsTokenManager.getToken()).to.be.rejectedWith(Error); + }); + + it('returns access token if not expired, not refreshing', async () => { + Object.assign(stsTokenManager, { + accessToken: 'token', + refreshToken: 'refresh', + expirationTime: now + 100_000, + }); + + const tokens = await stsTokenManager.getToken(); + expect(tokens.accessToken).to.eq('token'); + expect(tokens.refreshToken).to.eq('refresh'); + }); + }); +}); \ No newline at end of file diff --git a/packages-exp/auth-exp/src/core/user/token_manager.ts b/packages-exp/auth-exp/src/core/user/token_manager.ts new file mode 100644 index 00000000000..221dfd583b3 --- /dev/null +++ b/packages-exp/auth-exp/src/core/user/token_manager.ts @@ -0,0 +1,63 @@ +/** + * @license + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { IdTokenResponse } from '../../model/id_token'; + +/** + * The number of milliseconds before the official expiration time of a token + * to refresh that token, to provide a buffer for RPCs to complete. + */ +const TOKEN_REFRESH_BUFFER_MS = 30_000; + +export interface Tokens { + accessToken: string; + refreshToken: string|null; +} + +export const DATE_GENERATOR = { + now: () => Date.now(), +}; + +export class StsTokenManager { + refreshToken: string|null = null; + accessToken: string|null = null; + expirationTime: number|null = null; + + get isExpired(): boolean { + return !this.expirationTime || + DATE_GENERATOR.now() > this.expirationTime - TOKEN_REFRESH_BUFFER_MS; + } + + updateFromServerResponse({idToken, refreshToken, expiresIn}: IdTokenResponse): void { + this.refreshToken = refreshToken; + this.accessToken = idToken; + this.expirationTime = DATE_GENERATOR.now() + (Number.parseInt(expiresIn, 10) * 1000); + } + + async getToken(forceRefresh = false): Promise { + if (!forceRefresh && this.accessToken && !this.isExpired) { + return { + accessToken: this.accessToken, + refreshToken: this.refreshToken, + }; + } + + throw new Error('StsTokenManager: token refresh not implemented'); + } + + // TODO: There are a few more methods in here that need implemented +} \ No newline at end of file diff --git a/packages-exp/auth-exp/src/core/user_impl.test.ts b/packages-exp/auth-exp/src/core/user/user_impl.test.ts similarity index 54% rename from packages-exp/auth-exp/src/core/user_impl.test.ts rename to packages-exp/auth-exp/src/core/user/user_impl.test.ts index ad5ab731908..0548c3bfa96 100644 --- a/packages-exp/auth-exp/src/core/user_impl.test.ts +++ b/packages-exp/auth-exp/src/core/user/user_impl.test.ts @@ -15,16 +15,26 @@ * limitations under the License. */ -import { expect } from 'chai'; +import { expect, use } from 'chai'; +import * as chaiAsPromised from 'chai-as-promised'; import { UserImpl } from './user_impl'; -import { mockAuth } from '../../test/mock_auth'; +import { mockAuth } from '../../../test/mock_auth'; +import { StsTokenManager } from './token_manager'; +import { IdTokenResponse } from '../../model/id_token'; -describe('core/user_impl', () => { +use(chaiAsPromised); + +describe('core/user/user_impl', () => { const auth = mockAuth('foo', 'i-am-the-api-key'); + let stsTokenManager: StsTokenManager; + + beforeEach(() => { + stsTokenManager = new StsTokenManager(); + }); describe('constructor', () => { it('attaches required fields', () => { - const user = new UserImpl({ uid: 'uid', auth }); + const user = new UserImpl({ uid: 'uid', auth, stsTokenManager }); expect(user.auth).to.eq(auth); expect(user.uid).to.eq('uid'); }); @@ -33,6 +43,7 @@ describe('core/user_impl', () => { const user = new UserImpl({ uid: 'uid', auth, + stsTokenManager, displayName: 'displayName', email: 'email', phoneNumber: 'phoneNumber', @@ -46,7 +57,7 @@ describe('core/user_impl', () => { }); it('sets optional fields to null if not provided', () => { - const user = new UserImpl({ uid: 'uid', auth }); + const user = new UserImpl({ uid: 'uid', auth, stsTokenManager }); expect(user.displayName).to.eq(null); expect(user.email).to.eq(null); expect(user.phoneNumber).to.eq(null); @@ -55,29 +66,42 @@ describe('core/user_impl', () => { }); describe('#getIdToken', () => { - it('throws', () => { - const user = new UserImpl({ uid: 'uid', auth }); - expect(() => user.getIdToken()).to.throw(); + it('returns the raw token if refresh tokens are in order', async () => { + stsTokenManager.updateFromServerResponse({ + idToken: 'id-token-string', + refreshToken: 'refresh-token-string', + expiresIn: '100000', + } as IdTokenResponse); + + const user = new UserImpl({uid: 'uid', auth, stsTokenManager}); + const token = await user.getIdToken(); + expect(token).to.eq('id-token-string'); + expect(user.refreshToken).to.eq('refresh-token-string'); + }); + + it('throws if refresh is required', async () => { + const user = new UserImpl({ uid: 'uid', auth, stsTokenManager }); + await expect(user.getIdToken()).to.be.rejectedWith(Error); }); }); describe('#getIdTokenResult', () => { - it('throws', () => { - const user = new UserImpl({ uid: 'uid', auth }); - expect(() => user.getIdTokenResult()).to.throw(); + it('throws', async () => { + const user = new UserImpl({ uid: 'uid', auth, stsTokenManager }); + await expect(user.getIdTokenResult()).to.be.rejectedWith(Error); }); }); describe('#reload', () => { it('throws', () => { - const user = new UserImpl({ uid: 'uid', auth }); + const user = new UserImpl({ uid: 'uid', auth, stsTokenManager }); expect(() => user.reload()).to.throw(); }); }); describe('#delete', () => { it('throws', () => { - const user = new UserImpl({ uid: 'uid', auth }); + const user = new UserImpl({ uid: 'uid', auth, stsTokenManager }); expect(() => user.delete()).to.throw(); }); }); diff --git a/packages-exp/auth-exp/src/core/user_impl.ts b/packages-exp/auth-exp/src/core/user/user_impl.ts similarity index 62% rename from packages-exp/auth-exp/src/core/user_impl.ts rename to packages-exp/auth-exp/src/core/user/user_impl.ts index 23821eef530..c14695352c9 100644 --- a/packages-exp/auth-exp/src/core/user_impl.ts +++ b/packages-exp/auth-exp/src/core/user/user_impl.ts @@ -15,14 +15,16 @@ * limitations under the License. */ -import { User } from '../model/user'; -import { Auth } from '../model/auth'; -import { IdTokenResult } from '../model/id_token'; -import { ProviderId } from './providers'; +import { User } from '../../model/user'; +import { Auth } from '../../model/auth'; +import { IdTokenResult } from '../../model/id_token'; +import { ProviderId } from '../providers'; +import { StsTokenManager } from './token_manager'; export interface UserParameters { uid: string; auth: Auth; + stsTokenManager: StsTokenManager; displayName?: string; email?: string; @@ -33,6 +35,8 @@ export interface UserParameters { export class UserImpl implements User { // For the user object, provider is always Firebase. readonly providerId = ProviderId.FIREBASE; + stsTokenManager: StsTokenManager; + refreshToken = ''; uid: string; auth: Auth; @@ -43,21 +47,28 @@ export class UserImpl implements User { phoneNumber: string | null; photoURL: string | null; - constructor({ uid, auth, ...opt }: UserParameters) { + constructor({ uid, auth, stsTokenManager, ...opt }: UserParameters) { this.uid = uid; this.auth = auth; + this.stsTokenManager = stsTokenManager; this.displayName = opt.displayName || null; this.email = opt.email || null; this.phoneNumber = opt.phoneNumber || null; this.photoURL = opt.photoURL || null; } - getIdToken(forceRefresh?: boolean): Promise { - throw new Error(`Method not implemented. forceRefresh: ${forceRefresh}`); + async getIdToken(forceRefresh?: boolean): Promise { + const {refreshToken, accessToken} = await this.stsTokenManager.getToken(forceRefresh); + this.refreshToken = refreshToken || ''; + + // TODO: notify listeners at this point + return accessToken; } - getIdTokenResult(forceRefresh?: boolean): Promise { - throw new Error(`Method not implemented. forceRefresh: ${forceRefresh}`); + async getIdTokenResult(forceRefresh?: boolean): Promise { + await this.getIdToken(forceRefresh); + // TODO: Parse token + throw new Error('Method not implemented'); } reload(): Promise { diff --git a/packages-exp/auth-exp/src/model/id_token.d.ts b/packages-exp/auth-exp/src/model/id_token.d.ts index 49d4db9c800..7cf492dfb1f 100644 --- a/packages-exp/auth-exp/src/model/id_token.d.ts +++ b/packages-exp/auth-exp/src/model/id_token.d.ts @@ -22,6 +22,26 @@ import { ProviderId } from '../core/providers/index'; */ export type IdToken = string; +/** + * Raw parsed JWT + */ +export interface ParsedIdToken { + iss: string; + aud: string; + exp: number; + sub: string; + iat: number; + email?: string; + verified: boolean; + providerId?: string; + tenantId?: string; + anonymous: boolean; + federatedId?: string; + displayName?: string; + photoURL?: string; + toString(): string; +} + /** * IdToken as returned by the API */ diff --git a/packages-exp/auth-exp/src/model/user.d.ts b/packages-exp/auth-exp/src/model/user.d.ts index ac4591ce355..d21eae226d8 100644 --- a/packages-exp/auth-exp/src/model/user.d.ts +++ b/packages-exp/auth-exp/src/model/user.d.ts @@ -29,6 +29,7 @@ export interface UserInfo { export interface User extends UserInfo { providerId: ProviderId.FIREBASE; + refreshToken: string; getIdToken(forceRefresh?: boolean): Promise; getIdTokenResult(forceRefresh?: boolean): Promise; From 50bfb9221c3bbe0db195f5675645dd679667bb26 Mon Sep 17 00:00:00 2001 From: Sam Olsen Date: Fri, 10 Apr 2020 15:26:46 -0700 Subject: [PATCH 4/7] [AUTOMATED]: Prettier Code Styling --- .../src/core/user/token_manager.test.ts | 18 ++++++++---- .../auth-exp/src/core/user/token_manager.ts | 29 ++++++++++++------- .../auth-exp/src/core/user/user_impl.test.ts | 4 +-- .../auth-exp/src/core/user/user_impl.ts | 4 ++- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/packages-exp/auth-exp/src/core/user/token_manager.test.ts b/packages-exp/auth-exp/src/core/user/token_manager.test.ts index 201dc759327..baf41932e01 100644 --- a/packages-exp/auth-exp/src/core/user/token_manager.test.ts +++ b/packages-exp/auth-exp/src/core/user/token_manager.test.ts @@ -39,7 +39,7 @@ describe('core/user/token_manager', () => { describe('#isExpired', () => { it('is true if past expiration time', () => { - stsTokenManager.expirationTime = 1; // Ancient history + stsTokenManager.expirationTime = 1; // Ancient history expect(stsTokenManager.isExpired).to.eq(true); }); @@ -60,7 +60,7 @@ describe('core/user/token_manager', () => { stsTokenManager.updateFromServerResponse({ idToken: 'id-token', refreshToken: 'refresh-token', - expiresIn: '60', // From the server this is 30s + expiresIn: '60' // From the server this is 30s } as IdTokenResponse); expect(stsTokenManager.expirationTime).to.eq(now + 60_000); @@ -71,12 +71,18 @@ describe('core/user/token_manager', () => { describe('#getToken', () => { it('throws if forceRefresh is true', async () => { - Object.assign(stsTokenManager, {accessToken: 'token', expirationTime: now + 100_000}); + Object.assign(stsTokenManager, { + accessToken: 'token', + expirationTime: now + 100_000 + }); await expect(stsTokenManager.getToken(true)).to.be.rejectedWith(Error); }); it('throws if token is expired', async () => { - Object.assign(stsTokenManager, {accessToken: 'token', expirationTime: now - 1}); + Object.assign(stsTokenManager, { + accessToken: 'token', + expirationTime: now - 1 + }); await expect(stsTokenManager.getToken()).to.be.rejectedWith(Error); }); @@ -88,7 +94,7 @@ describe('core/user/token_manager', () => { Object.assign(stsTokenManager, { accessToken: 'token', refreshToken: 'refresh', - expirationTime: now + 100_000, + expirationTime: now + 100_000 }); const tokens = await stsTokenManager.getToken(); @@ -96,4 +102,4 @@ describe('core/user/token_manager', () => { expect(tokens.refreshToken).to.eq('refresh'); }); }); -}); \ No newline at end of file +}); diff --git a/packages-exp/auth-exp/src/core/user/token_manager.ts b/packages-exp/auth-exp/src/core/user/token_manager.ts index 221dfd583b3..e3d06745a9c 100644 --- a/packages-exp/auth-exp/src/core/user/token_manager.ts +++ b/packages-exp/auth-exp/src/core/user/token_manager.ts @@ -25,34 +25,41 @@ const TOKEN_REFRESH_BUFFER_MS = 30_000; export interface Tokens { accessToken: string; - refreshToken: string|null; + refreshToken: string | null; } export const DATE_GENERATOR = { - now: () => Date.now(), + now: () => Date.now() }; export class StsTokenManager { - refreshToken: string|null = null; - accessToken: string|null = null; - expirationTime: number|null = null; + refreshToken: string | null = null; + accessToken: string | null = null; + expirationTime: number | null = null; get isExpired(): boolean { - return !this.expirationTime || - DATE_GENERATOR.now() > this.expirationTime - TOKEN_REFRESH_BUFFER_MS; + return ( + !this.expirationTime || + DATE_GENERATOR.now() > this.expirationTime - TOKEN_REFRESH_BUFFER_MS + ); } - updateFromServerResponse({idToken, refreshToken, expiresIn}: IdTokenResponse): void { + updateFromServerResponse({ + idToken, + refreshToken, + expiresIn + }: IdTokenResponse): void { this.refreshToken = refreshToken; this.accessToken = idToken; - this.expirationTime = DATE_GENERATOR.now() + (Number.parseInt(expiresIn, 10) * 1000); + this.expirationTime = + DATE_GENERATOR.now() + Number.parseInt(expiresIn, 10) * 1000; } async getToken(forceRefresh = false): Promise { if (!forceRefresh && this.accessToken && !this.isExpired) { return { accessToken: this.accessToken, - refreshToken: this.refreshToken, + refreshToken: this.refreshToken }; } @@ -60,4 +67,4 @@ export class StsTokenManager { } // TODO: There are a few more methods in here that need implemented -} \ No newline at end of file +} diff --git a/packages-exp/auth-exp/src/core/user/user_impl.test.ts b/packages-exp/auth-exp/src/core/user/user_impl.test.ts index 0548c3bfa96..4f3d9d0d616 100644 --- a/packages-exp/auth-exp/src/core/user/user_impl.test.ts +++ b/packages-exp/auth-exp/src/core/user/user_impl.test.ts @@ -70,10 +70,10 @@ describe('core/user/user_impl', () => { stsTokenManager.updateFromServerResponse({ idToken: 'id-token-string', refreshToken: 'refresh-token-string', - expiresIn: '100000', + expiresIn: '100000' } as IdTokenResponse); - const user = new UserImpl({uid: 'uid', auth, stsTokenManager}); + const user = new UserImpl({ uid: 'uid', auth, stsTokenManager }); const token = await user.getIdToken(); expect(token).to.eq('id-token-string'); expect(user.refreshToken).to.eq('refresh-token-string'); diff --git a/packages-exp/auth-exp/src/core/user/user_impl.ts b/packages-exp/auth-exp/src/core/user/user_impl.ts index c14695352c9..1e535299ca4 100644 --- a/packages-exp/auth-exp/src/core/user/user_impl.ts +++ b/packages-exp/auth-exp/src/core/user/user_impl.ts @@ -58,7 +58,9 @@ export class UserImpl implements User { } async getIdToken(forceRefresh?: boolean): Promise { - const {refreshToken, accessToken} = await this.stsTokenManager.getToken(forceRefresh); + const { refreshToken, accessToken } = await this.stsTokenManager.getToken( + forceRefresh + ); this.refreshToken = refreshToken || ''; // TODO: notify listeners at this point From b62fabae0ba0b0fcf1808862850f2b4a17626e05 Mon Sep 17 00:00:00 2001 From: Sam Olsen Date: Mon, 13 Apr 2020 13:18:35 -0700 Subject: [PATCH 5/7] Address comments in token manager, restore yarn.lock --- .../src/core/user/token_manager.test.ts | 15 ++- .../auth-exp/src/core/user/token_manager.ts | 17 ++-- yarn.lock | 98 ++++++++----------- 3 files changed, 57 insertions(+), 73 deletions(-) diff --git a/packages-exp/auth-exp/src/core/user/token_manager.test.ts b/packages-exp/auth-exp/src/core/user/token_manager.test.ts index baf41932e01..019ea63fc92 100644 --- a/packages-exp/auth-exp/src/core/user/token_manager.test.ts +++ b/packages-exp/auth-exp/src/core/user/token_manager.test.ts @@ -17,7 +17,7 @@ import { expect, use } from 'chai'; import * as chaiAsPromised from 'chai-as-promised'; -import { StsTokenManager, DATE_GENERATOR } from './token_manager'; +import { StsTokenManager, TOKEN_REFRESH_BUFFER_MS } from './token_manager'; import { IdTokenResponse } from '../../model/id_token'; import { createSandbox } from 'sinon'; @@ -32,7 +32,7 @@ describe('core/user/token_manager', () => { beforeEach(() => { stsTokenManager = new StsTokenManager(); now = Date.now(); - sandbox.stub(DATE_GENERATOR, 'now').returns(now); + sandbox.stub(Date, 'now').returns(now); }); afterEach(() => sandbox.restore()); @@ -44,13 +44,12 @@ describe('core/user/token_manager', () => { }); it('is true if exp is in future but within buffer', () => { - // Buffer is 30_000 - stsTokenManager.expirationTime = now + 20_000; + stsTokenManager.expirationTime = now + (TOKEN_REFRESH_BUFFER_MS - 10); expect(stsTokenManager.isExpired).to.eq(true); }); it('is fals if exp is far enough in future', () => { - stsTokenManager.expirationTime = now + 40_000; + stsTokenManager.expirationTime = now + (TOKEN_REFRESH_BUFFER_MS + 10); expect(stsTokenManager.isExpired).to.eq(false); }); }); @@ -75,7 +74,7 @@ describe('core/user/token_manager', () => { accessToken: 'token', expirationTime: now + 100_000 }); - await expect(stsTokenManager.getToken(true)).to.be.rejectedWith(Error); + await expect(stsTokenManager.getToken(true)).to.be.rejectedWith(Error, 'StsTokenManager: token refresh not implemented'); }); it('throws if token is expired', async () => { @@ -83,11 +82,11 @@ describe('core/user/token_manager', () => { accessToken: 'token', expirationTime: now - 1 }); - await expect(stsTokenManager.getToken()).to.be.rejectedWith(Error); + await expect(stsTokenManager.getToken()).to.be.rejectedWith(Error, 'StsTokenManager: token refresh not implemented'); }); it('throws if access token is missing', async () => { - await expect(stsTokenManager.getToken()).to.be.rejectedWith(Error); + await expect(stsTokenManager.getToken()).to.be.rejectedWith(Error, 'StsTokenManager: token refresh not implemented'); }); it('returns access token if not expired, not refreshing', async () => { diff --git a/packages-exp/auth-exp/src/core/user/token_manager.ts b/packages-exp/auth-exp/src/core/user/token_manager.ts index e3d06745a9c..3a84c0ccc5c 100644 --- a/packages-exp/auth-exp/src/core/user/token_manager.ts +++ b/packages-exp/auth-exp/src/core/user/token_manager.ts @@ -21,17 +21,13 @@ import { IdTokenResponse } from '../../model/id_token'; * The number of milliseconds before the official expiration time of a token * to refresh that token, to provide a buffer for RPCs to complete. */ -const TOKEN_REFRESH_BUFFER_MS = 30_000; +export const TOKEN_REFRESH_BUFFER_MS = 30_000; export interface Tokens { accessToken: string; refreshToken: string | null; } -export const DATE_GENERATOR = { - now: () => Date.now() -}; - export class StsTokenManager { refreshToken: string | null = null; accessToken: string | null = null; @@ -40,19 +36,19 @@ export class StsTokenManager { get isExpired(): boolean { return ( !this.expirationTime || - DATE_GENERATOR.now() > this.expirationTime - TOKEN_REFRESH_BUFFER_MS + Date.now() > this.expirationTime - TOKEN_REFRESH_BUFFER_MS ); } updateFromServerResponse({ idToken, refreshToken, - expiresIn + expiresIn: expiresInSec }: IdTokenResponse): void { this.refreshToken = refreshToken; this.accessToken = idToken; this.expirationTime = - DATE_GENERATOR.now() + Number.parseInt(expiresIn, 10) * 1000; + Date.now() + Number.parseInt(expiresInSec, 10) * 1000; } async getToken(forceRefresh = false): Promise { @@ -66,5 +62,8 @@ export class StsTokenManager { throw new Error('StsTokenManager: token refresh not implemented'); } - // TODO: There are a few more methods in here that need implemented + // TODO: There are a few more methods in here that need implemented: + // # toPlainObject + // # fromPlainObject + // # (private) performRefresh } diff --git a/yarn.lock b/yarn.lock index b76140956f2..c2b89459a84 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10397,36 +10397,6 @@ mocha@7.1.0: yargs-parser "13.1.1" yargs-unparser "1.6.0" -mocha@^7.1.1: - version "7.1.1" - resolved "https://registry.npmjs.org/mocha/-/mocha-7.1.1.tgz#89fbb30d09429845b1bb893a830bf5771049a441" - integrity sha512-3qQsu3ijNS3GkWcccT5Zw0hf/rWvu1fTN9sPvEd81hlwsr30GX2GcDSSoBxo24IR8FelmrAydGC6/1J5QQP4WA== - dependencies: - ansi-colors "3.2.3" - browser-stdout "1.3.1" - chokidar "3.3.0" - debug "3.2.6" - diff "3.5.0" - escape-string-regexp "1.0.5" - find-up "3.0.0" - glob "7.1.3" - growl "1.10.5" - he "1.2.0" - js-yaml "3.13.1" - log-symbols "3.0.0" - minimatch "3.0.4" - mkdirp "0.5.3" - ms "2.1.1" - node-environment-flags "1.0.6" - object.assign "4.1.0" - strip-json-comments "2.0.1" - supports-color "6.0.0" - which "1.3.1" - wide-align "1.1.3" - yargs "13.3.2" - yargs-parser "13.1.2" - yargs-unparser "1.6.0" - modify-values@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" @@ -10722,6 +10692,22 @@ node-localstorage@^1.3.1: dependencies: write-file-atomic "^1.1.4" +node-pre-gyp@*: + version "0.14.0" + resolved "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83" + integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4.4.2" + node-pre-gyp@^0.11.0: version "0.11.0" resolved "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054" @@ -13929,7 +13915,7 @@ tar@4.4.2: safe-buffer "^5.1.2" yallist "^3.0.2" -tar@^4, tar@^4.3.0, tar@^4.4.10, tar@^4.4.12, tar@^4.4.8: +tar@^4, tar@^4.3.0, tar@^4.4.10, tar@^4.4.12, tar@^4.4.2, tar@^4.4.8: version "4.4.13" resolved "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== @@ -15497,14 +15483,6 @@ yargs-parser@13.1.1: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@13.1.2, yargs-parser@^13.1.0, yargs-parser@^13.1.1, yargs-parser@^13.1.2: - version "13.1.2" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" - integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - yargs-parser@^10.0.0: version "10.1.0" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" @@ -15512,6 +15490,14 @@ yargs-parser@^10.0.0: dependencies: camelcase "^4.1.0" +yargs-parser@^13.1.0, yargs-parser@^13.1.1, yargs-parser@^13.1.2: + version "13.1.2" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" + integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs-parser@^15.0.1: version "15.0.1" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz#54786af40b820dcb2fb8025b11b4d659d76323b3" @@ -15577,22 +15563,6 @@ yargs@13.3.0: y18n "^4.0.0" yargs-parser "^13.1.1" -yargs@13.3.2, yargs@^13.3.0: - version "13.3.2" - resolved "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" - integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.2" - yargs@15.3.1, yargs@^15.0.2: version "15.3.1" resolved "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b" @@ -15610,6 +15580,22 @@ yargs@15.3.1, yargs@^15.0.2: y18n "^4.0.0" yargs-parser "^18.1.1" +yargs@^13.3.0: + version "13.3.2" + resolved "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" + integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.2" + yargs@^14.2.2: version "14.2.3" resolved "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz#1a1c3edced1afb2a2fea33604bc6d1d8d688a414" @@ -15682,4 +15668,4 @@ zip-stream@^2.1.2: dependencies: archiver-utils "^2.1.0" compress-commons "^2.1.1" - readable-stream "^3.4.0" + readable-stream "^3.4.0" \ No newline at end of file From 09f95ef36c08616fadd4f744b21a36c85baeaf6f Mon Sep 17 00:00:00 2001 From: Sam Olsen Date: Mon, 13 Apr 2020 13:18:46 -0700 Subject: [PATCH 6/7] [AUTOMATED]: Prettier Code Styling --- .../auth-exp/src/core/user/token_manager.test.ts | 15 ++++++++++++--- .../auth-exp/src/core/user/token_manager.ts | 3 +-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages-exp/auth-exp/src/core/user/token_manager.test.ts b/packages-exp/auth-exp/src/core/user/token_manager.test.ts index 019ea63fc92..c6a943a62ed 100644 --- a/packages-exp/auth-exp/src/core/user/token_manager.test.ts +++ b/packages-exp/auth-exp/src/core/user/token_manager.test.ts @@ -74,7 +74,10 @@ describe('core/user/token_manager', () => { accessToken: 'token', expirationTime: now + 100_000 }); - await expect(stsTokenManager.getToken(true)).to.be.rejectedWith(Error, 'StsTokenManager: token refresh not implemented'); + await expect(stsTokenManager.getToken(true)).to.be.rejectedWith( + Error, + 'StsTokenManager: token refresh not implemented' + ); }); it('throws if token is expired', async () => { @@ -82,11 +85,17 @@ describe('core/user/token_manager', () => { accessToken: 'token', expirationTime: now - 1 }); - await expect(stsTokenManager.getToken()).to.be.rejectedWith(Error, 'StsTokenManager: token refresh not implemented'); + await expect(stsTokenManager.getToken()).to.be.rejectedWith( + Error, + 'StsTokenManager: token refresh not implemented' + ); }); it('throws if access token is missing', async () => { - await expect(stsTokenManager.getToken()).to.be.rejectedWith(Error, 'StsTokenManager: token refresh not implemented'); + await expect(stsTokenManager.getToken()).to.be.rejectedWith( + Error, + 'StsTokenManager: token refresh not implemented' + ); }); it('returns access token if not expired, not refreshing', async () => { diff --git a/packages-exp/auth-exp/src/core/user/token_manager.ts b/packages-exp/auth-exp/src/core/user/token_manager.ts index 3a84c0ccc5c..60b0c4b1554 100644 --- a/packages-exp/auth-exp/src/core/user/token_manager.ts +++ b/packages-exp/auth-exp/src/core/user/token_manager.ts @@ -47,8 +47,7 @@ export class StsTokenManager { }: IdTokenResponse): void { this.refreshToken = refreshToken; this.accessToken = idToken; - this.expirationTime = - Date.now() + Number.parseInt(expiresInSec, 10) * 1000; + this.expirationTime = Date.now() + Number.parseInt(expiresInSec, 10) * 1000; } async getToken(forceRefresh = false): Promise { From c93391fa085ee581ec50ff131154c24cbb3469eb Mon Sep 17 00:00:00 2001 From: Sam Olsen Date: Tue, 14 Apr 2020 09:46:09 -0700 Subject: [PATCH 7/7] parseInt() -> Number() --- packages-exp/auth-exp/src/core/user/token_manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages-exp/auth-exp/src/core/user/token_manager.ts b/packages-exp/auth-exp/src/core/user/token_manager.ts index 60b0c4b1554..49bd349f03b 100644 --- a/packages-exp/auth-exp/src/core/user/token_manager.ts +++ b/packages-exp/auth-exp/src/core/user/token_manager.ts @@ -47,7 +47,7 @@ export class StsTokenManager { }: IdTokenResponse): void { this.refreshToken = refreshToken; this.accessToken = idToken; - this.expirationTime = Date.now() + Number.parseInt(expiresInSec, 10) * 1000; + this.expirationTime = Date.now() + Number(expiresInSec) * 1000; } async getToken(forceRefresh = false): Promise {