diff --git a/spec/fixtures/mockrequest.ts b/spec/fixtures/mockrequest.ts index 928960bd4..c85ea36ed 100644 --- a/spec/fixtures/mockrequest.ts +++ b/spec/fixtures/mockrequest.ts @@ -28,7 +28,8 @@ export function mockRequest( authorization?: string; instanceIdToken?: string; appCheckToken?: string; - } = {} + } = {}, + reqHeaders?: Record, ) { const body: any = {}; if (typeof data !== 'undefined') { @@ -41,6 +42,7 @@ export function mockRequest( 'firebase-instance-id-token': context.instanceIdToken, 'x-firebase-appcheck': context.appCheckToken, origin: 'example.com', + ...reqHeaders, }; return new MockRequest(body, headers); diff --git a/spec/v1/providers/https.spec.ts b/spec/v1/providers/https.spec.ts index f829aa6d3..3fc736952 100644 --- a/spec/v1/providers/https.spec.ts +++ b/spec/v1/providers/https.spec.ts @@ -24,9 +24,17 @@ import { expect } from "chai"; import * as functions from "../../../src/v1"; import * as https from "../../../src/v1/providers/https"; -import { expectedResponseHeaders, MockRequest } from "../../fixtures/mockrequest"; +import * as debug from "../../../src/common/debug"; +import * as sinon from "sinon"; +import { + expectedResponseHeaders, + generateUnsignedIdToken, + MockRequest, + mockRequest, +} from "../../fixtures/mockrequest"; import { runHandler } from "../../helper"; import { MINIMAL_V1_ENDPOINT } from "../../fixtures"; +import { CALLABLE_AUTH_HEADER, ORIGINAL_AUTH_HEADER } from "../../../src/common/providers/https"; describe("CloudHttpsBuilder", () => { describe("#onRequest", () => { @@ -66,6 +74,10 @@ describe("CloudHttpsBuilder", () => { }); describe("#onCall", () => { + afterEach(() => { + sinon.verifyAndRestore(); + }); + it("should return a trigger/endpoint with appropriate values", () => { const result = https.onCall(() => { return "response"; @@ -139,6 +151,45 @@ describe("#onCall", () => { expect(response.status).to.equal(200); expect(gotData).to.deep.equal({ foo: "bar" }); }); + + // Test for firebase-tools#5210 + it("should create context.auth for v1 emulated functions", async () => { + sinon.stub(debug, "isDebugFeatureEnabled").withArgs("skipTokenVerification").returns(true); + + let gotData: Record; + let gotContext: Record; + const reqData = { hello: "world" }; + const authContext = { + uid: "SomeUID", + token: { + aud: "123456", + sub: "SomeUID", + uid: "SomeUID", + }, + }; + const originalAuth = "Bearer " + generateUnsignedIdToken("123456"); + const func = https.onCall((data, context) => { + gotData = data; + gotContext = context; + }); + const mockReq = mockRequest( + reqData, + "application/json", + {}, + { + [CALLABLE_AUTH_HEADER]: encodeURIComponent(JSON.stringify(authContext)), + [ORIGINAL_AUTH_HEADER]: originalAuth, + } + ); + + const response = await runHandler(func, mockReq as any); + + expect(response.status).to.equal(200); + expect(gotData).to.deep.eq(reqData); + expect(gotContext.rawRequest).to.deep.eq(mockReq); + expect(gotContext.rawRequest.headers["authorization"]).to.eq(originalAuth); + expect(gotContext.auth).to.deep.eq(authContext); + }); }); describe("callable CORS", () => { diff --git a/src/common/providers/https.ts b/src/common/providers/https.ts index 3f59bfe39..9961790f7 100644 --- a/src/common/providers/https.ts +++ b/src/common/providers/https.ts @@ -36,8 +36,10 @@ import { TaskContext } from "./tasks"; const JWT_REGEX = /^[a-zA-Z0-9\-_=]+?\.[a-zA-Z0-9\-_=]+?\.([a-zA-Z0-9\-_=]+)?$/; -const CALLABLE_AUTH_HEADER = "x-callable-context-auth"; -const ORIGINAL_AUTH_HEADER = "x-original-auth"; +/** @internal */ +export const CALLABLE_AUTH_HEADER = "x-callable-context-auth"; +/** @internal */ +export const ORIGINAL_AUTH_HEADER = "x-original-auth"; /** An express request with the wire format representation of the request body. */ export interface Request extends express.Request {