From 87dca6b701202700341a4f6720c6e3ecbc4eb382 Mon Sep 17 00:00:00 2001 From: Abe Haskins Date: Wed, 9 Jun 2021 12:05:04 -0500 Subject: [PATCH 1/7] Move from manual JWT creation to jsonwebtoken --- packages/rules-unit-testing/package.json | 3 ++- packages/rules-unit-testing/src/api/index.ts | 20 ++++++-------------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/packages/rules-unit-testing/package.json b/packages/rules-unit-testing/package.json index 96254212907..6cf43f9bf50 100644 --- a/packages/rules-unit-testing/package.json +++ b/packages/rules-unit-testing/package.json @@ -20,10 +20,11 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "8.6.5", "@firebase/component": "0.5.1", "@firebase/logger": "0.2.6", "@firebase/util": "1.1.0", + "firebase": "8.6.5", + "jsonwebtoken": "^8.5.1", "request": "2.88.2" }, "devDependencies": { diff --git a/packages/rules-unit-testing/src/api/index.ts b/packages/rules-unit-testing/src/api/index.ts index 1fdf3800d61..3d384f1838b 100644 --- a/packages/rules-unit-testing/src/api/index.ts +++ b/packages/rules-unit-testing/src/api/index.ts @@ -27,6 +27,7 @@ import * as request from 'request'; import { base64 } from '@firebase/util'; import { setLogLevel, LogLevel } from '@firebase/logger'; import { Component, ComponentType } from '@firebase/component'; +import jwt from 'jsonwebtoken'; const { firestore, database, storage } = firebase; export { firestore, database, storage }; @@ -158,13 +159,6 @@ export type FirebaseEmulatorOptions = { }; function createUnsecuredJwt(token: TokenOptions, projectId?: string): string { - // Unsecured JWTs use "none" as the algorithm. - const header = { - alg: 'none', - kid: 'fakekid', - type: 'JWT' - }; - const project = projectId || 'fake-project'; const iat = token.iat || 0; const uid = token.sub || token.uid || token.user_id; @@ -197,11 +191,7 @@ function createUnsecuredJwt(token: TokenOptions, projectId?: string): string { // Unsecured JWTs use the empty string as a signature. const signature = ''; - return [ - base64.encodeString(JSON.stringify(header), /*webSafe=*/ false), - base64.encodeString(JSON.stringify(payload), /*webSafe=*/ false), - signature - ].join('.'); + return jwt.sign(payload, signature, { algorithm: 'none' }); } export function apps(): firebase.app.App[] { @@ -263,7 +253,9 @@ export function initializeAdminApp(options: AdminAppOptions): app.App { * @param options options object. */ export function useEmulators(options: FirebaseEmulatorOptions): void { - if (!(options.database || options.firestore || options.storage || options.hub)) { + if ( + !(options.database || options.firestore || options.storage || options.hub) + ) { throw new Error( "Argument to useEmulators must contain at least one of 'database', 'firestore', 'storage', or 'hub'." ); @@ -429,7 +421,7 @@ function getHubHost() { } function parseHost(host: string): { hostname: string; port: number } { - const withProtocol = host.startsWith("http") ? host : `http://${host}`; + const withProtocol = host.startsWith('http') ? host : `http://${host}`; const u = new URL(withProtocol); return { hostname: u.hostname, From ffac0d01ee2ea3ff89ca75ab7e576abbe22672c7 Mon Sep 17 00:00:00 2001 From: Abe Haskins Date: Wed, 9 Jun 2021 12:35:26 -0500 Subject: [PATCH 2/7] Adds jsonwebtoken types --- packages/rules-unit-testing/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/rules-unit-testing/package.json b/packages/rules-unit-testing/package.json index 6cf43f9bf50..47790173665 100644 --- a/packages/rules-unit-testing/package.json +++ b/packages/rules-unit-testing/package.json @@ -29,10 +29,11 @@ }, "devDependencies": { "@google-cloud/firestore": "4.8.1", + "@types/jsonwebtoken": "^8.5.1", "@types/request": "2.48.5", "firebase-admin": "9.7.0", - "firebase-tools": "9.10.1", "firebase-functions": "3.13.0", + "firebase-tools": "9.10.1", "rollup": "2.35.1", "rollup-plugin-typescript2": "0.29.0" }, From 2d41a856322bb43ee1010c3ecf5badeb6397571f Mon Sep 17 00:00:00 2001 From: Abe Haskins Date: Wed, 9 Jun 2021 13:00:10 -0500 Subject: [PATCH 3/7] Another type fix attempt --- packages/rules-unit-testing/src/api/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rules-unit-testing/src/api/index.ts b/packages/rules-unit-testing/src/api/index.ts index 3d384f1838b..1e819b28b22 100644 --- a/packages/rules-unit-testing/src/api/index.ts +++ b/packages/rules-unit-testing/src/api/index.ts @@ -27,7 +27,7 @@ import * as request from 'request'; import { base64 } from '@firebase/util'; import { setLogLevel, LogLevel } from '@firebase/logger'; import { Component, ComponentType } from '@firebase/component'; -import jwt from 'jsonwebtoken'; +import * as jwt from 'jsonwebtoken'; const { firestore, database, storage } = firebase; export { firestore, database, storage }; From 7a9d9a2edca68944a96cd40b5c31961a946679b7 Mon Sep 17 00:00:00 2001 From: Abe Haskins Date: Wed, 9 Jun 2021 13:31:09 -0500 Subject: [PATCH 4/7] Replace missing token headers --- packages/rules-unit-testing/src/api/index.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/rules-unit-testing/src/api/index.ts b/packages/rules-unit-testing/src/api/index.ts index 1e819b28b22..d4afb812024 100644 --- a/packages/rules-unit-testing/src/api/index.ts +++ b/packages/rules-unit-testing/src/api/index.ts @@ -166,6 +166,12 @@ function createUnsecuredJwt(token: TokenOptions, projectId?: string): string { throw new Error("Auth must contain 'sub', 'uid', or 'user_id' field!"); } + const header = { + alg: 'none', + kid: 'fakekid', + type: 'JWT' + }; + const payload: FirebaseIdToken = { // Set all required fields to decent defaults iss: `https://securetoken.google.com/${project}`, @@ -191,7 +197,7 @@ function createUnsecuredJwt(token: TokenOptions, projectId?: string): string { // Unsecured JWTs use the empty string as a signature. const signature = ''; - return jwt.sign(payload, signature, { algorithm: 'none' }); + return jwt.sign(payload, signature, { algorithm: 'none', header }); } export function apps(): firebase.app.App[] { From 21cd69bccf1ada633875ba5e8c8e4f34f9f8076f Mon Sep 17 00:00:00 2001 From: Abraham Haskins Date: Mon, 9 Aug 2021 12:14:53 -0500 Subject: [PATCH 5/7] Revert jwt dep --- packages/rules-unit-testing/package.json | 2 -- packages/rules-unit-testing/src/api/index.ts | 22 ++++++++++++-------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/rules-unit-testing/package.json b/packages/rules-unit-testing/package.json index 47790173665..629b999db9a 100644 --- a/packages/rules-unit-testing/package.json +++ b/packages/rules-unit-testing/package.json @@ -24,12 +24,10 @@ "@firebase/logger": "0.2.6", "@firebase/util": "1.1.0", "firebase": "8.6.5", - "jsonwebtoken": "^8.5.1", "request": "2.88.2" }, "devDependencies": { "@google-cloud/firestore": "4.8.1", - "@types/jsonwebtoken": "^8.5.1", "@types/request": "2.48.5", "firebase-admin": "9.7.0", "firebase-functions": "3.13.0", diff --git a/packages/rules-unit-testing/src/api/index.ts b/packages/rules-unit-testing/src/api/index.ts index d4afb812024..ec5cacd07a2 100644 --- a/packages/rules-unit-testing/src/api/index.ts +++ b/packages/rules-unit-testing/src/api/index.ts @@ -27,7 +27,7 @@ import * as request from 'request'; import { base64 } from '@firebase/util'; import { setLogLevel, LogLevel } from '@firebase/logger'; import { Component, ComponentType } from '@firebase/component'; -import * as jwt from 'jsonwebtoken'; +import { base64Encode } from '@firebase/util'; const { firestore, database, storage } = firebase; export { firestore, database, storage }; @@ -159,6 +159,13 @@ export type FirebaseEmulatorOptions = { }; function createUnsecuredJwt(token: TokenOptions, projectId?: string): string { + // Unsecured JWTs use "none" as the algorithm. + const header = { + alg: 'none', + kid: 'fakekid', + type: 'JWT' + }; + const project = projectId || 'fake-project'; const iat = token.iat || 0; const uid = token.sub || token.uid || token.user_id; @@ -166,12 +173,6 @@ function createUnsecuredJwt(token: TokenOptions, projectId?: string): string { throw new Error("Auth must contain 'sub', 'uid', or 'user_id' field!"); } - const header = { - alg: 'none', - kid: 'fakekid', - type: 'JWT' - }; - const payload: FirebaseIdToken = { // Set all required fields to decent defaults iss: `https://securetoken.google.com/${project}`, @@ -197,9 +198,12 @@ function createUnsecuredJwt(token: TokenOptions, projectId?: string): string { // Unsecured JWTs use the empty string as a signature. const signature = ''; - return jwt.sign(payload, signature, { algorithm: 'none', header }); + return [ + base64Encode(JSON.stringify(header)), + base64Encode(JSON.stringify(payload)), + signature + ].join('.'); } - export function apps(): firebase.app.App[] { return firebase.apps; } From 832d30f1c1184f6eed6422443b92e26040a18380 Mon Sep 17 00:00:00 2001 From: Abraham Haskins Date: Mon, 9 Aug 2021 12:18:15 -0500 Subject: [PATCH 6/7] Add manual trimming --- packages/rules-unit-testing/src/api/index.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/rules-unit-testing/src/api/index.ts b/packages/rules-unit-testing/src/api/index.ts index ec5cacd07a2..92d3591d989 100644 --- a/packages/rules-unit-testing/src/api/index.ts +++ b/packages/rules-unit-testing/src/api/index.ts @@ -158,6 +158,10 @@ export type FirebaseEmulatorOptions = { }; }; +function trimmedBase64Encode(val: string): string { + return base64Encode(val).split("=")[0]; +} + function createUnsecuredJwt(token: TokenOptions, projectId?: string): string { // Unsecured JWTs use "none" as the algorithm. const header = { @@ -199,8 +203,8 @@ function createUnsecuredJwt(token: TokenOptions, projectId?: string): string { // Unsecured JWTs use the empty string as a signature. const signature = ''; return [ - base64Encode(JSON.stringify(header)), - base64Encode(JSON.stringify(payload)), + trimmedBase64Encode(JSON.stringify(header)), + trimmedBase64Encode(JSON.stringify(payload)), signature ].join('.'); } From f602b9c16409ee121b5139314d1dd930bbcebfb1 Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Mon, 9 Aug 2021 11:22:02 -0700 Subject: [PATCH 7/7] Fix trimming padding. --- packages/rules-unit-testing/src/api/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/rules-unit-testing/src/api/index.ts b/packages/rules-unit-testing/src/api/index.ts index 2f2bb0eb496..51d16209187 100644 --- a/packages/rules-unit-testing/src/api/index.ts +++ b/packages/rules-unit-testing/src/api/index.ts @@ -159,7 +159,8 @@ export type FirebaseEmulatorOptions = { }; function trimmedBase64Encode(val: string): string { - return base64Encode(val).split("=")[0]; + // Use base64url encoding and remove padding in the end (dot characters). + return base64Encode(val).replace(/\./g, ""); } function createUnsecuredJwt(token: TokenOptions, projectId?: string): string {