Skip to content

Task queue emulator incorrectly decodes base64 payload with atob(), should be Buffer.from(..., "base64") #8836

Open
@CodingDoug

Description

@CodingDoug

[REQUIRED] Environment info

firebase-tools: 14.9.0

Platform: macOS

[REQUIRED] Test case

The emulator doesn't decode strings with non-ascii utf8 characters correctly, for example, emoji.

Enqueue a task using firebase-admin in one (http) function:

const taskData = {"key":"some value with a utf-8 character, such as emoji"}
const queue = getFunctions().taskQueue("someTask")
await queue.enqueue(taskData)

Receive it:

export default async function someTask(req: TaskRequest) {
    // does not print the original character
    console.log(req.data.key)
}

[REQUIRED] Steps to reproduce

Run the emulator, invoke the http function that enqueues task, watch the task print the unexpected value.

[REQUIRED] Expected behavior

It should print exactly the utf-8 string that was enqueued.

[REQUIRED] Actual behavior

It prints a "junk" decoding.

The problem is that the emulator uses the JavaScript atob() function to decode the base64 payload created by the Admin SDK. Here is what the Admin SDK does (correctly):

https://github.com/firebase/firebase-admin-node/blob/master/src/functions/functions-api-client-internal.ts#L244C15-L244C71

body: Buffer.from(JSON.stringify({ data })).toString('base64'),

Here is what the emulator does (incorrectly):

https://github.com/firebase/firebase-tools/blob/master/src/emulator/tasksEmulator.ts#L271

req.body.task.httpRequest.body = JSON.parse(atob(req.body.task.httpRequest.body));

atob() uses the JavaScript native utf-16 internal encoding for strings, however, this incorrectly decodes anything with a codepoint above 256. What the emulator should do instead is use Buffer.from(data, "base64").toString("utf-8").

Here is a bit of node repl that illustrates the expected translation, including JSON parsing:

> b64 = Buffer.from(JSON.stringify({"A":"👍"})).toString('base64')
'eyJBIjoi8J+RjSJ9'
> JSON.parse(Buffer.from(b64, "base64").toString("utf-8"))
{ A: '👍' }

Note that the production Cloud Functions works fine - it's just the emulator that doesn't decode task payloads correctly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions