Repository: firebase/firebase-tools (ts)

Issue:
"request entity too large" when trying to import into auth emulator
<!-- DO NOT DELETE
validate_template=true
template_path=.github/ISSUE_TEMPLATE/bug_report.md
-->

<!--
Thank you for contributing to the Firebase community!

Think you found a bug?
=======================
Yeah, we're definitely not perfect! Please use this template and include a minimal repro when opening the issue. If you know how to solve the issue, please create a Pull Request, and we'd be happy to review it!

Have a feature request?
========================
Great, we love hearing how we can improve our products! However, do not use this template to submit a feature request. Please submit your feature requests to: https://firebase.google.com/support/contact/bugs-features/

Have a usage question?
=======================
We get lots of those and we love helping you, but GitHub is not the best place for them and they will be closed. Please take a look at the guide first: https://firebase.google.com/docs/cli/

If the official documentation doesn't help, try asking through our official support channel: https://firebase.google.com/support/

Additional locations to check for solutions or assistance from the community:
- Stack Overflow: https://stackoverflow.com/
- Firebase Slack Community: https://firebase.community/

*Please avoid duplicate posting across multiple channels!*
-->

### [REQUIRED] Environment info

<!-- What version of the Firebase CLI (`firebase-tools`) are you using? Note that your issue may already be fixed in the latest versions. The latest version can be found at https://github.com/firebase/firebase-tools/releases -->

<!-- Output of `firebase --version` -->

**firebase-tools:** 9.13.0

<!-- e.g. macOS, Windows, Ubuntu -->

**Platform:** Windows (using WSL)

### [REQUIRED] Test case

<!-- Provide a minimal, complete, and verifiable example (http://stackoverflow.com/help/mcve) -->
- Auth having more than 200 users triggers this error. 

### [REQUIRED] Steps to reproduce
- Create at least 200 users with the auth emulator running
- Export this using firebase emulators:export <dir-name> 
- Try importing this using firebase emulators:start --import <dir-name> and you will encounter this bug. 

<!-- Provide the steps needed to reproduce the issue with the above test case. -->

### [REQUIRED] Expected behavior
Expected behaviour is for the import to succeed. 
<!-- What is the expected behavior? -->

### [REQUIRED] Actual behavior
![image](https://user-images.githubusercontent.com/2641144/125108206-bb3a7080-e0af-11eb-86b7-aec1bff8bf62.png)


<!-- Run the command with --debug flag, and include the logs below. -->

Log file when ran with --debug: [log.log](https://github.com/firebase/firebase-tools/files/6792707/log.log)


Pull request:
Allow larger request body in Auth Emulator. Fixes #3570.
<!--

Thank you for contributing to the Firebase community! Please fill out the form below.

Run the linter and test suite
==============================
Run `npm test` to make sure your changes compile properly and the tests all pass on your local machine. We've hooked up this repo with continuous integration to double check those things for you.

-->

### Description

Fixes #3570.

### Scenarios Tested

See integration test added.

### Sample Commands

`firebase emulators:start --import foo`

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e69de29bb..6e6ebade9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -0,0 +1,1 @@
+- Fix Auth Emulator errors when importing many users (#3577).
diff --git a/src/emulator/auth/server.ts b/src/emulator/auth/server.ts
index 4ab40fea9..4104b0688 100644
--- a/src/emulator/auth/server.ts
+++ b/src/emulator/auth/server.ts
@@ -226,6 +226,7 @@ export async function createApp(
       // Let errors propagate to our universal error handler below.
       throw err;
     },
+    defaultMaxBodySize: 1024 * 1024 * 1024, // 1GB instead of the default 10k.
     validateDefaultResponses: true,
     onResponseValidationError({ errors }) {
       logError(


Test patch:
diff --git a/scripts/triggers-end-to-end-tests/run.sh b/scripts/triggers-end-to-end-tests/run.sh
index 57fe15392..2399b8996 100755
--- a/scripts/triggers-end-to-end-tests/run.sh
+++ b/scripts/triggers-end-to-end-tests/run.sh
@@ -8,7 +8,7 @@ source scripts/set-default-credentials.sh
   npm install
 )
 
-mocha \
+npx mocha \
   --require ts-node/register \
   --require source-map-support/register \
   --require src/test/helpers/mocha-bootstrap.ts \
diff --git a/scripts/triggers-end-to-end-tests/tests.ts b/scripts/triggers-end-to-end-tests/tests.ts
index 0870104b2..38f16eba8 100755
--- a/scripts/triggers-end-to-end-tests/tests.ts
+++ b/scripts/triggers-end-to-end-tests/tests.ts
@@ -7,7 +7,6 @@ import * as path from "path";
 
 import { CLIProcess } from "../integration-helpers/cli";
 import { FrameworkOptions, TriggerEndToEndTest } from "../integration-helpers/framework";
-import { assert } from "sinon";
 
 const FIREBASE_PROJECT = process.env.FBTOOLS_TARGET_PROJECT || "";
 const ADMIN_CREDENTIAL = {
@@ -518,6 +517,89 @@ describe("import/export end to end", () => {
     }
   });
 
+  it("should be able to import/export auth data with many users", async function (this) {
+    this.timeout(2 * TEST_SETUP_TIMEOUT);
+    await new Promise((resolve) => setTimeout(resolve, 2000));
+
+    // Start up emulator suite
+    const project = FIREBASE_PROJECT || "example";
+    const emulatorsCLI = new CLIProcess("1", __dirname);
+
+    await emulatorsCLI.start("emulators:start", project, ["--only", "auth"], (data: unknown) => {
+      if (typeof data !== "string" && !Buffer.isBuffer(data)) {
+        throw new Error(`data is not a string or buffer (${typeof data})`);
+      }
+      return data.includes(ALL_EMULATORS_STARTED_LOG);
+    });
+
+    // Create some accounts to export:
+    const accountCount = 777; // ~120KB data when exported
+    const config = readConfig();
+    const port = config.emulators!.auth.port;
+    try {
+      process.env.FIREBASE_AUTH_EMULATOR_HOST = `localhost:${port}`;
+      const adminApp = admin.initializeApp(
+        {
+          projectId: project,
+          credential: ADMIN_CREDENTIAL,
+        },
+        "admin-app2"
+      );
+      for (let i = 0; i < accountCount; i++) {
+        await adminApp
+          .auth()
+          .createUser({ uid: `u${i}`, email: `u${i}@example.com`, password: "testing" });
+      }
+      // Ask for export
+      const exportCLI = new CLIProcess("2", __dirname);
+      const exportPath = fs.mkdtempSync(path.join(os.tmpdir(), "emulator-data"));
+      await exportCLI.start("emulators:export", project, [exportPath], (data: unknown) => {
+        if (typeof data !== "string" && !Buffer.isBuffer(data)) {
+          throw new Error(`data is not a string or buffer (${typeof data})`);
+        }
+        return data.includes("Export complete");
+      });
+      await exportCLI.stop();
+
+      // Stop the suite
+      await emulatorsCLI.stop();
+
+      // Confirm the data is exported as expected
+      const configPath = path.join(exportPath, "auth_export", "config.json");
+      const configData = JSON.parse(fs.readFileSync(configPath).toString());
+      expect(configData).to.deep.equal({
+        signIn: {
+          allowDuplicateEmails: false,
+        },
+      });
+
+      const accountsPath = path.join(exportPath, "auth_export", "accounts.json");
+      const accountsData = JSON.parse(fs.readFileSync(accountsPath).toString());
+      expect(accountsData.users).to.have.length(accountCount);
+
+      // Attempt to import
+      const importCLI = new CLIProcess("3", __dirname);
+      await importCLI.start(
+        "emulators:start",
+        project,
+        ["--only", "auth", "--import", exportPath],
+        (data: unknown) => {
+          if (typeof data !== "string" && !Buffer.isBuffer(data)) {
+            throw new Error(`data is not a string or buffer (${typeof data})`);
+          }
+          return data.includes(ALL_EMULATORS_STARTED_LOG);
+        }
+      );
+
+      // Check users are indeed imported correctly
+      const user = await adminApp.auth().getUserByEmail(`u${accountCount - 1}@example.com`);
+      expect(user.passwordHash).to.match(/:password=testing$/);
+
+      await importCLI.stop();
+    } finally {
+      delete process.env.FIREBASE_AUTH_EMULATOR_HOST;
+    }
+  });
   it("should be able to export / import auth data with no users", async function (this) {
     this.timeout(2 * TEST_SETUP_TIMEOUT);
     await new Promise((resolve) => setTimeout(resolve, 2000));