From 1b4ee25ca3cf9f2b86f7aa8888c576e59638f77e Mon Sep 17 00:00:00 2001 From: Jonathan Edey <145066863+jonathanedey@users.noreply.github.com> Date: Wed, 3 Sep 2025 15:10:42 -0400 Subject: [PATCH 01/11] chore: Added and `AGENTS.md` file to instruct AI agents how to interact with this repository (#710) --- AGENTS.md | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..e6b95039 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,123 @@ +# Firebase Admin Go SDK - Agent Guide + +This document provides a comprehensive guide for AI agents to understand the conventions, design patterns, and architecture of the Firebase Admin Go SDK. Adhering to these guidelines is crucial for making idiomatic and consistent code contributions. + +## 1. High-Level Overview + +The Firebase Admin Go SDK enables server-side (backend) applications to interact with Firebase services. Its design emphasizes idiomatic Go, thread-safety, and a consistent, discoverable API surface. + +## 2. Directory Structure + +- `firebase.go`: The primary entry point for initializing a Firebase `App` instance. +- `internal/`: Contains private implementation details, such as HTTP clients and utility functions, that are not part of the public API. +- `auth/`, `db/`, `messaging/`, etc.: Each directory contains a specific Firebase service client. +- `*_test.go`: Unit tests are located alongside the code they test (e.g., `auth/auth_test.go`). +- `integration/`: Contains integration tests that make live network calls to Firebase services. +- `snippets/`: Contains code snippets used in documentation. +- `errorutils/`: Contains common error type checkers and other error handling utils. +- `testdata/`: Contains mock data used in some tests. + +## 3. Core Design Patterns + +- **Initialization:** The SDK is initialized by creating an `App` instance via `firebase.NewApp()`. This `App` object is the central point for accessing all service clients. +- **Service Clients:** Service clients (e.g., `auth.Client`, `db.Client`) are obtained from the `App` instance (e.g., `app.Auth(ctx)`). These clients are lightweight and are typically created as needed. +- **Error Handling:** Errors are handled using standard Go idioms. Firbase errors are defined in `internal/errors.go` however these errors can be further modified within each service. This modification is applied using that service's set `internal.HTTPClient.CreateErrFn` value. +- **HTTP Communication:** All outgoing HTTP requests are managed by a centralized client located in `internal/http_client.go`. This ensures consistent handling of authentication, retries, and error parsing. +- **Asynchronous Operations:** The SDK uses `context.Context` to manage deadlines, cancellations, and request-scoped values for all asynchronous operations. + +## 4. Coding Style and Naming Conventions + +- **Naming:** + - Public functions, types, and fields use `PascalCase`. + - Private functions and types use `camelCase`. + - Constants are written in `PascalCase`. + +## 5. Testing Philosophy + +- **Unit Tests:** Unit tests follow the `*_test.go` naming pattern and are placed in the same directory as the code under test. They use standard Go testing packages and mocks to isolate dependencies. +- **Integration Tests:** Integration tests are located in the `integration/` directory. They are designed to run against actual Firebase services and require a configured Firebase project. + +## 6. Dependency Management + +- **Manager:** The SDK uses Go Modules for dependency management. +- **Manifest:** Dependencies are declared in the `go.mod` file. +- **Command:** To add or update dependencies, use `go get` or `go mod tidy`. + +## 7. Critical Developer Journeys + +### Journey 1: How to Add a New API Method + +1. **Define Public Method:** Add the new method or change to the appropriate service client files (e.g., `auth/user_mgt.go`). +2. **Internal Logic:** Implement the core logic within the service package. +3. **HTTP Client:** Use the client in `internal/http_client.go` to make the API calls. +4. **Error Handling:** New or updated error codes implemented in the appropriate location. +5. **Testing:** + - Add unit tests in the corresponding `*_test.go` file (e.g., `auth/user_mgt_test.go`). + - Add integration tests in the `integration/` directory if applicable. +6. **Snippets:** (Optional) Add or update code snippets in the `snippets/` directory. + +### Journey 2: How to Deprecate a Field/Method in an Existing API + +1. **Add Deprecation Note:** Locate where the deprecated object is defined and add a deprecation warning with a note (e.g. `// Deprecated: Use X instead.`). + +## 8. Critical Do's and Don'ts + +- **DO:** Use the centralized HTTP client in `internal/http_client.go` for all network calls. +- **DO:** Pass `context.Context` as the first argument to all functions that perform I/O or other blocking operations. +- **DON'T:** Expose types or functions from the `internal/` directory in the public API. +- **DON'T:** Introduce new third-party dependencies without a strong, documented justification and team consensus. + +## 9. Branch Creation +- When creating a new barnch use the format `agentName-short-description`. + * Example: `jules-auth-token-parsing` + * Example: `gemini-add-storage-file-signer` + + +## 10. Commit and Pull Request Generation + +After implementing and testing a change, you may create a commit and pull request which must follow the following these rules: + +### Commit and Pull Request Title Format: +Use the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification: `type(scope): subject` +- `type` should be one of `feat`, `fix` or `chore`. +- `scope` should be the service package changed (e.g., `auth`, `rtdb`, `deps`). + - **Note**: Some services use specific abbreviations. Use the abbreviation if one exists. Common abbreviations include: + - `messaging` -> `fcm` + - `dataconnect` -> `fdc` + - `database` -> `rtdb` + - `appcheck` -> `fac` +- `subject` should be a brief summary of the change depending on the action: + - For pull requests this should focus on the larger goal the included commits achieve. + - Example: `fix(auth): Resolved issue with custom token verification` + - For commits this should focus on the specific changes made in that commit. + - Example: `fix(auth): Added a new token verification check` + +### Commit Body: + This should be a brief explanation of code changes. + +Example: +``` +feat(fcm): Added `SendEachForMulticast` support for multicast messages + +Added a new `SendEachForMulticast` method to the messaging client. This method wraps the `SendEach` method and sends the same message to each token. +``` + +### Pull Request Body: +- A brief explanation of the problem and the solution. +- A summary of the testing strategy (e.g., "Added a new unit test to verify the fix."). +- A **Context Sources** section that lists the `id` and repository path of every `AGENTS.md` file you used. + +Example: +``` +feat(fcm): Added support for multicast messages + +This change introduces a new `SendEachForMulticast` method to the messaging client, allowing developers to send a single message to multiple tokens efficiently. + +Testing: Added unit tests in `messaging_test.go` with a mock server and an integration test in `integration/messaging_test.go`. + +Context Sources Used: +- id: firebase-admin-go (`/AGENTS.md`) +``` + +## 11. Metadata +- id: firebase-admin-go \ No newline at end of file From bac58d85c1473182e2d27e8601b44f7d61b413d1 Mon Sep 17 00:00:00 2001 From: Jonathan Edey <145066863+jonathanedey@users.noreply.github.com> Date: Wed, 10 Sep 2025 11:14:26 -0400 Subject: [PATCH 02/11] fix(auth): Fixed auth error code parsing (#712) * fix(auth): Fixed auth error code parsing * fix(auth): Fixed test to use error message prefix --- auth/user_mgt.go | 2 +- auth/user_mgt_test.go | 2 +- integration/auth/user_mgt_test.go | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/auth/user_mgt.go b/auth/user_mgt.go index 63a5c381..cc37f56b 100644 --- a/auth/user_mgt.go +++ b/auth/user_mgt.go @@ -1510,7 +1510,7 @@ func parseErrorResponse(resp *internal.Response) (string, string) { idx := strings.Index(code, ":") if idx != -1 { detail = strings.TrimSpace(code[idx+1:]) - code = code[:idx] + code = strings.TrimSpace(code[:idx]) } return code, detail diff --git a/auth/user_mgt_test.go b/auth/user_mgt_test.go index 53ccdc58..445cf718 100644 --- a/auth/user_mgt_test.go +++ b/auth/user_mgt_test.go @@ -2191,7 +2191,7 @@ func TestHTTPErrorWithCode(t *testing.T) { } func TestAuthErrorWithCodeAndDetails(t *testing.T) { - resp := []byte(`{"error":{"message":"USER_NOT_FOUND: extra details"}}`) + resp := []byte(`{"error":{"message":"USER_NOT_FOUND : extra details"}}`) s := echoServer(resp, t) defer s.Close() s.Client.baseClient.httpClient.RetryConfig = nil diff --git a/integration/auth/user_mgt_test.go b/integration/auth/user_mgt_test.go index 1c37cd0a..4311e77a 100644 --- a/integration/auth/user_mgt_test.go +++ b/integration/auth/user_mgt_test.go @@ -35,6 +35,7 @@ import ( const ( continueURL = "http://localhost/?a=1&b=2#c=3" + invalidContinueURL = "http://www.localhost/?a=1&b=2#c=3" continueURLKey = "continueUrl" oobCodeKey = "oobCode" modeKey = "mode" @@ -1297,6 +1298,19 @@ func TestEmailSignInLink(t *testing.T) { } } +func TestAuthErrorParse(t *testing.T) { + user := newUserWithParams(t) + defer deleteUser(user.UID) + _, err := client.EmailSignInLink(context.Background(), user.Email, &auth.ActionCodeSettings{ + URL: invalidContinueURL, + HandleCodeInApp: false, + }) + want := "domain of the continue url is not whitelisted: " + if err == nil || !auth.IsUnauthorizedContinueURI(err) || !strings.HasPrefix(err.Error(), want) { + t.Errorf("EmailSignInLink() expected error, got: %s, want: %s", err, want) + } +} + func resetPassword(email, oldPassword, newPassword, oobCode string) error { req := map[string]interface{}{ "email": email, From da7068d6d46f07b69052c691949a7e65049df7a0 Mon Sep 17 00:00:00 2001 From: Lahiru Maramba Date: Tue, 16 Sep 2025 14:07:42 -0400 Subject: [PATCH 03/11] chore: update copyright headers from Google Inc. to Google LLC (#713) --- .github/scripts/generate_changelog.sh | 2 +- .github/scripts/publish_preflight_check.sh | 2 +- .github/scripts/run_all_tests.sh | 2 +- .github/workflows/nightly.yml | 2 +- .github/workflows/release.yml | 2 +- appcheck/appcheck.go | 2 +- auth/auth.go | 2 +- auth/auth_appengine.go | 2 +- auth/auth_std.go | 2 +- auth/auth_test.go | 2 +- auth/email_action_links.go | 2 +- auth/email_action_links_test.go | 2 +- auth/export_users.go | 2 +- auth/hash/hash.go | 2 +- auth/hash/hash_test.go | 2 +- auth/import_users.go | 2 +- auth/multi_factor_config_mgt.go | 2 +- auth/multi_factor_config_mgt_test.go | 2 +- auth/project_config_mgt.go | 2 +- auth/project_config_mgt_test.go | 2 +- auth/provider_config.go | 2 +- auth/provider_config_test.go | 2 +- auth/tenant_mgt.go | 2 +- auth/tenant_mgt_test.go | 2 +- auth/token_generator.go | 2 +- auth/token_generator_test.go | 2 +- auth/token_verifier.go | 2 +- auth/token_verifier_test.go | 2 +- auth/user_mgt.go | 2 +- auth/user_mgt_test.go | 2 +- db/auth_override_test.go | 2 +- db/db.go | 2 +- db/db_test.go | 2 +- db/query.go | 2 +- db/query_test.go | 2 +- db/ref.go | 2 +- db/ref_test.go | 2 +- errorutils/errorutils.go | 2 +- firebase.go | 2 +- firebase_test.go | 2 +- iid/iid.go | 2 +- iid/iid_test.go | 2 +- integration/auth/auth_test.go | 2 +- integration/auth/project_config_mgt_test.go | 2 +- integration/auth/provider_config_test.go | 2 +- integration/auth/tenant_mgt_test.go | 2 +- integration/auth/user_mgt_test.go | 2 +- integration/db/db_test.go | 2 +- integration/db/query_test.go | 2 +- integration/firestore/firestore_test.go | 2 +- integration/iid/iid_test.go | 2 +- integration/internal/internal.go | 2 +- integration/messaging/messaging_test.go | 2 +- integration/storage/storage_test.go | 2 +- internal/errors.go | 2 +- internal/errors_test.go | 2 +- internal/http_client.go | 2 +- internal/http_client_test.go | 2 +- internal/internal.go | 2 +- internal/json_http_client_test.go | 2 +- messaging/messaging.go | 2 +- messaging/messaging_batch.go | 2 +- messaging/messaging_batch_test.go | 2 +- messaging/messaging_test.go | 2 +- messaging/messaging_utils.go | 2 +- messaging/topic_mgt.go | 2 +- messaging/topic_mgt_test.go | 2 +- remoteconfig/condition_evaluator.go | 2 +- remoteconfig/condition_evaluator_test.go | 2 +- remoteconfig/remoteconfig.go | 2 +- remoteconfig/remoteconfig_test.go | 2 +- remoteconfig/server_config.go | 2 +- remoteconfig/server_template.go | 2 +- remoteconfig/server_template_test.go | 2 +- remoteconfig/server_template_types.go | 2 +- snippets/auth.go | 2 +- snippets/db.go | 2 +- snippets/init.go | 2 +- snippets/messaging.go | 2 +- snippets/storage.go | 2 +- storage/storage.go | 2 +- storage/storage_test.go | 2 +- 82 files changed, 82 insertions(+), 82 deletions(-) diff --git a/.github/scripts/generate_changelog.sh b/.github/scripts/generate_changelog.sh index e393f40e..a0afa6e4 100755 --- a/.github/scripts/generate_changelog.sh +++ b/.github/scripts/generate_changelog.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2020 Google Inc. +# 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. diff --git a/.github/scripts/publish_preflight_check.sh b/.github/scripts/publish_preflight_check.sh index 632960eb..691192d5 100755 --- a/.github/scripts/publish_preflight_check.sh +++ b/.github/scripts/publish_preflight_check.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2020 Google Inc. +# 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. diff --git a/.github/scripts/run_all_tests.sh b/.github/scripts/run_all_tests.sh index c47961b3..96d02d5b 100755 --- a/.github/scripts/run_all_tests.sh +++ b/.github/scripts/run_all_tests.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2020 Google Inc. +# 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. diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 9a819795..b5b7665e 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. +# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bfb0d04e..6b32ee10 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,4 @@ -# Copyright 2020 Google Inc. +# 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. diff --git a/appcheck/appcheck.go b/appcheck/appcheck.go index 89868916..c2fefaa8 100644 --- a/appcheck/appcheck.go +++ b/appcheck/appcheck.go @@ -1,4 +1,4 @@ -// Copyright 2022 Google Inc. All Rights Reserved. +// Copyright 2022 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/auth.go b/auth/auth.go index a7028698..6bd3b0f2 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/auth_appengine.go b/auth/auth_appengine.go index 06eee2a9..1d2c2cc0 100644 --- a/auth/auth_appengine.go +++ b/auth/auth_appengine.go @@ -1,7 +1,7 @@ //go:build appengine // +build appengine -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/auth_std.go b/auth/auth_std.go index e5a9cb87..b8eda30b 100644 --- a/auth/auth_std.go +++ b/auth/auth_std.go @@ -1,7 +1,7 @@ //go:build !appengine // +build !appengine -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/auth_test.go b/auth/auth_test.go index 9c8b1523..69127b22 100644 --- a/auth/auth_test.go +++ b/auth/auth_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/email_action_links.go b/auth/email_action_links.go index 282e79fe..bc08d401 100644 --- a/auth/email_action_links.go +++ b/auth/email_action_links.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google Inc. All Rights Reserved. +// Copyright 2019 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/email_action_links_test.go b/auth/email_action_links_test.go index 2575ff32..8ed55e66 100644 --- a/auth/email_action_links_test.go +++ b/auth/email_action_links_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google Inc. All Rights Reserved. +// Copyright 2019 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/export_users.go b/auth/export_users.go index 7e5670a7..5b086b80 100644 --- a/auth/export_users.go +++ b/auth/export_users.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google Inc. All Rights Reserved. +// Copyright 2019 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/hash/hash.go b/auth/hash/hash.go index dce1217d..b18f8bd6 100644 --- a/auth/hash/hash.go +++ b/auth/hash/hash.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2018 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/hash/hash_test.go b/auth/hash/hash_test.go index 675e7d8f..c1406ac6 100644 --- a/auth/hash/hash_test.go +++ b/auth/hash/hash_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2018 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/import_users.go b/auth/import_users.go index 6de0c37b..6a1e1ff9 100644 --- a/auth/import_users.go +++ b/auth/import_users.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google Inc. All Rights Reserved. +// Copyright 2019 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/multi_factor_config_mgt.go b/auth/multi_factor_config_mgt.go index d01e2f46..8e0bc109 100644 --- a/auth/multi_factor_config_mgt.go +++ b/auth/multi_factor_config_mgt.go @@ -1,4 +1,4 @@ -// Copyright 2023 Google Inc. All Rights Reserved. +// Copyright 2023 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/multi_factor_config_mgt_test.go b/auth/multi_factor_config_mgt_test.go index ebbef4eb..be31774f 100644 --- a/auth/multi_factor_config_mgt_test.go +++ b/auth/multi_factor_config_mgt_test.go @@ -1,4 +1,4 @@ -// Copyright 2023 Google Inc. All Rights Reserved. +// Copyright 2023 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/project_config_mgt.go b/auth/project_config_mgt.go index 5ae739cd..510eb915 100644 --- a/auth/project_config_mgt.go +++ b/auth/project_config_mgt.go @@ -1,4 +1,4 @@ -// Copyright 2023 Google Inc. All Rights Reserved. +// Copyright 2023 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/project_config_mgt_test.go b/auth/project_config_mgt_test.go index ec0fa756..ad19dde3 100644 --- a/auth/project_config_mgt_test.go +++ b/auth/project_config_mgt_test.go @@ -1,4 +1,4 @@ -// Copyright 2023 Google Inc. All Rights Reserved. +// Copyright 2023 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/provider_config.go b/auth/provider_config.go index 312fa349..c33eaf0d 100644 --- a/auth/provider_config.go +++ b/auth/provider_config.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google Inc. All Rights Reserved. +// Copyright 2019 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/provider_config_test.go b/auth/provider_config_test.go index 0defec12..4e2e2551 100644 --- a/auth/provider_config_test.go +++ b/auth/provider_config_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google Inc. All Rights Reserved. +// Copyright 2019 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/tenant_mgt.go b/auth/tenant_mgt.go index 0e3ab205..35b27de1 100644 --- a/auth/tenant_mgt.go +++ b/auth/tenant_mgt.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google Inc. All Rights Reserved. +// Copyright 2019 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/tenant_mgt_test.go b/auth/tenant_mgt_test.go index 77c26851..e411793c 100644 --- a/auth/tenant_mgt_test.go +++ b/auth/tenant_mgt_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google Inc. All Rights Reserved. +// Copyright 2019 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/token_generator.go b/auth/token_generator.go index 7aa2d564..fed6facf 100644 --- a/auth/token_generator.go +++ b/auth/token_generator.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2018 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/token_generator_test.go b/auth/token_generator_test.go index c79e3a9a..6ed5144e 100644 --- a/auth/token_generator_test.go +++ b/auth/token_generator_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/token_verifier.go b/auth/token_verifier.go index 25e7bdc0..fe6cdf0c 100644 --- a/auth/token_verifier.go +++ b/auth/token_verifier.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2018 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/token_verifier_test.go b/auth/token_verifier_test.go index e11c56d9..e24d7d1c 100644 --- a/auth/token_verifier_test.go +++ b/auth/token_verifier_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/user_mgt.go b/auth/user_mgt.go index cc37f56b..bee027e3 100644 --- a/auth/user_mgt.go +++ b/auth/user_mgt.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/user_mgt_test.go b/auth/user_mgt_test.go index 445cf718..01d8734f 100644 --- a/auth/user_mgt_test.go +++ b/auth/user_mgt_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/db/auth_override_test.go b/db/auth_override_test.go index 02f2671a..c179bd74 100644 --- a/db/auth_override_test.go +++ b/db/auth_override_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2018 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/db/db.go b/db/db.go index f53a197c..f30c534c 100644 --- a/db/db.go +++ b/db/db.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2018 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/db/db_test.go b/db/db_test.go index 5766c045..68517189 100644 --- a/db/db_test.go +++ b/db/db_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2018 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/db/query.go b/db/query.go index 424e00a8..ca826db9 100644 --- a/db/query.go +++ b/db/query.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2018 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/db/query_test.go b/db/query_test.go index 9c72971e..df05bf1c 100644 --- a/db/query_test.go +++ b/db/query_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2018 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/db/ref.go b/db/ref.go index bb26a531..e41af43f 100644 --- a/db/ref.go +++ b/db/ref.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2018 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/db/ref_test.go b/db/ref_test.go index 969eedc5..b3427700 100644 --- a/db/ref_test.go +++ b/db/ref_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2018 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/errorutils/errorutils.go b/errorutils/errorutils.go index fe81b756..ebf8d197 100644 --- a/errorutils/errorutils.go +++ b/errorutils/errorutils.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google Inc. All Rights Reserved. +// Copyright 2020 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/firebase.go b/firebase.go index 6101a8d9..9373ae23 100644 --- a/firebase.go +++ b/firebase.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/firebase_test.go b/firebase_test.go index 7830225e..2699146a 100644 --- a/firebase_test.go +++ b/firebase_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/iid/iid.go b/iid/iid.go index 7a3e9b55..c97f6e0f 100644 --- a/iid/iid.go +++ b/iid/iid.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/iid/iid_test.go b/iid/iid_test.go index 208da357..5597cb62 100644 --- a/iid/iid_test.go +++ b/iid/iid_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/auth/auth_test.go b/integration/auth/auth_test.go index 66809972..3bf43461 100644 --- a/integration/auth/auth_test.go +++ b/integration/auth/auth_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/auth/project_config_mgt_test.go b/integration/auth/project_config_mgt_test.go index 50284005..72df927b 100644 --- a/integration/auth/project_config_mgt_test.go +++ b/integration/auth/project_config_mgt_test.go @@ -1,4 +1,4 @@ -// Copyright 2023 Google Inc. All Rights Reserved. +// Copyright 2023 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/auth/provider_config_test.go b/integration/auth/provider_config_test.go index f0c9f285..7d789d7a 100644 --- a/integration/auth/provider_config_test.go +++ b/integration/auth/provider_config_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google Inc. All Rights Reserved. +// Copyright 2019 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/auth/tenant_mgt_test.go b/integration/auth/tenant_mgt_test.go index 8682cb33..a1349d4c 100644 --- a/integration/auth/tenant_mgt_test.go +++ b/integration/auth/tenant_mgt_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google Inc. All Rights Reserved. +// Copyright 2019 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/auth/user_mgt_test.go b/integration/auth/user_mgt_test.go index 4311e77a..cae59097 100644 --- a/integration/auth/user_mgt_test.go +++ b/integration/auth/user_mgt_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/db/db_test.go b/integration/db/db_test.go index 93be1eef..9a5d715a 100644 --- a/integration/db/db_test.go +++ b/integration/db/db_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2018 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/db/query_test.go b/integration/db/query_test.go index 6bb48cf0..392cb498 100644 --- a/integration/db/query_test.go +++ b/integration/db/query_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2018 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/firestore/firestore_test.go b/integration/firestore/firestore_test.go index 8e3dd60f..3e6d2da9 100644 --- a/integration/firestore/firestore_test.go +++ b/integration/firestore/firestore_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/iid/iid_test.go b/integration/iid/iid_test.go index a14b2fdf..ff9067dd 100644 --- a/integration/iid/iid_test.go +++ b/integration/iid/iid_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/internal/internal.go b/integration/internal/internal.go index 3a7948cc..d57b3f91 100644 --- a/integration/internal/internal.go +++ b/integration/internal/internal.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/messaging/messaging_test.go b/integration/messaging/messaging_test.go index e32aac9d..4552988a 100644 --- a/integration/messaging/messaging_test.go +++ b/integration/messaging/messaging_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2018 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/storage/storage_test.go b/integration/storage/storage_test.go index 9912c664..860288bc 100644 --- a/integration/storage/storage_test.go +++ b/integration/storage/storage_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/internal/errors.go b/internal/errors.go index e209d158..2c8b5d9c 100644 --- a/internal/errors.go +++ b/internal/errors.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google Inc. All Rights Reserved. +// Copyright 2020 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/internal/errors_test.go b/internal/errors_test.go index 3733429e..ccd38f20 100644 --- a/internal/errors_test.go +++ b/internal/errors_test.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google Inc. All Rights Reserved. +// Copyright 2020 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/internal/http_client.go b/internal/http_client.go index 9463f98e..9d1257bc 100644 --- a/internal/http_client.go +++ b/internal/http_client.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/internal/http_client_test.go b/internal/http_client_test.go index 2d8d97c4..22b498cf 100644 --- a/internal/http_client_test.go +++ b/internal/http_client_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/internal/internal.go b/internal/internal.go index a6eb1294..58450f45 100644 --- a/internal/internal.go +++ b/internal/internal.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/internal/json_http_client_test.go b/internal/json_http_client_test.go index 15ebed73..be827b75 100644 --- a/internal/json_http_client_test.go +++ b/internal/json_http_client_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google Inc. All Rights Reserved. +// Copyright 2019 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/messaging/messaging.go b/messaging/messaging.go index 8f484684..2eda22a9 100644 --- a/messaging/messaging.go +++ b/messaging/messaging.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2018 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/messaging/messaging_batch.go b/messaging/messaging_batch.go index 365190a4..03129587 100644 --- a/messaging/messaging_batch.go +++ b/messaging/messaging_batch.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google Inc. All Rights Reserved. +// Copyright 2019 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/messaging/messaging_batch_test.go b/messaging/messaging_batch_test.go index e8603eae..ed9a1a42 100644 --- a/messaging/messaging_batch_test.go +++ b/messaging/messaging_batch_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google Inc. All Rights Reserved. +// Copyright 2019 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/messaging/messaging_test.go b/messaging/messaging_test.go index 659a0c96..0cb72065 100644 --- a/messaging/messaging_test.go +++ b/messaging/messaging_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2018 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/messaging/messaging_utils.go b/messaging/messaging_utils.go index e69dd652..5716b328 100644 --- a/messaging/messaging_utils.go +++ b/messaging/messaging_utils.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2018 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/messaging/topic_mgt.go b/messaging/topic_mgt.go index 88492585..0e7e9d0c 100644 --- a/messaging/topic_mgt.go +++ b/messaging/topic_mgt.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google Inc. All Rights Reserved. +// Copyright 2019 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/messaging/topic_mgt_test.go b/messaging/topic_mgt_test.go index 6d58114d..1b0adba9 100644 --- a/messaging/topic_mgt_test.go +++ b/messaging/topic_mgt_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google Inc. All Rights Reserved. +// Copyright 2019 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/remoteconfig/condition_evaluator.go b/remoteconfig/condition_evaluator.go index 02efd451..accbb359 100644 --- a/remoteconfig/condition_evaluator.go +++ b/remoteconfig/condition_evaluator.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google Inc. All Rights Reserved. +// Copyright 2025 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/remoteconfig/condition_evaluator_test.go b/remoteconfig/condition_evaluator_test.go index c7265cff..07b81636 100644 --- a/remoteconfig/condition_evaluator_test.go +++ b/remoteconfig/condition_evaluator_test.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google Inc. All Rights Reserved. +// Copyright 2025 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/remoteconfig/remoteconfig.go b/remoteconfig/remoteconfig.go index 7c6228d1..55117cf5 100644 --- a/remoteconfig/remoteconfig.go +++ b/remoteconfig/remoteconfig.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google Inc. All Rights Reserved. +// Copyright 2025 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/remoteconfig/remoteconfig_test.go b/remoteconfig/remoteconfig_test.go index 14578ab5..f9a39f8a 100644 --- a/remoteconfig/remoteconfig_test.go +++ b/remoteconfig/remoteconfig_test.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google Inc. All Rights Reserved. +// Copyright 2025 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/remoteconfig/server_config.go b/remoteconfig/server_config.go index fc06a235..4aa1668c 100644 --- a/remoteconfig/server_config.go +++ b/remoteconfig/server_config.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google Inc. All Rights Reserved. +// Copyright 2025 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/remoteconfig/server_template.go b/remoteconfig/server_template.go index b6d6e9ec..693d32b6 100644 --- a/remoteconfig/server_template.go +++ b/remoteconfig/server_template.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google Inc. All Rights Reserved. +// Copyright 2025 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/remoteconfig/server_template_test.go b/remoteconfig/server_template_test.go index d09e4e2a..076e1719 100644 --- a/remoteconfig/server_template_test.go +++ b/remoteconfig/server_template_test.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google Inc. All Rights Reserved. +// Copyright 2025 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/remoteconfig/server_template_types.go b/remoteconfig/server_template_types.go index 059e66fd..4986e0dd 100644 --- a/remoteconfig/server_template_types.go +++ b/remoteconfig/server_template_types.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google Inc. All Rights Reserved. +// Copyright 2025 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/snippets/auth.go b/snippets/auth.go index df003339..a3f8cd8a 100644 --- a/snippets/auth.go +++ b/snippets/auth.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/snippets/db.go b/snippets/db.go index 9277ff04..e37e182a 100644 --- a/snippets/db.go +++ b/snippets/db.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2018 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/snippets/init.go b/snippets/init.go index 3125a702..d7db1313 100644 --- a/snippets/init.go +++ b/snippets/init.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/snippets/messaging.go b/snippets/messaging.go index 2b073dcb..1b25cb1c 100644 --- a/snippets/messaging.go +++ b/snippets/messaging.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. +// Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/snippets/storage.go b/snippets/storage.go index 5ef1b1f2..22c09402 100644 --- a/snippets/storage.go +++ b/snippets/storage.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/storage/storage.go b/storage/storage.go index 3f1b9d1b..cbe548c2 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/storage/storage_test.go b/storage/storage_test.go index f0eec7a5..4c66ae71 100644 --- a/storage/storage_test.go +++ b/storage/storage_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2017 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. From c612844e969b7f688678417d17a1d6701f8ec270 Mon Sep 17 00:00:00 2001 From: justinattw Date: Tue, 6 Jan 2026 12:02:14 +0000 Subject: [PATCH 04/11] Make FirebaseError public --- errorutils/errorutils.go | 135 ++++++++++++++--- errorutils/errorutils_test.go | 267 ++++++++++++++++++++++++++++++++++ internal/errors.go | 94 ++++-------- 3 files changed, 408 insertions(+), 88 deletions(-) create mode 100644 errorutils/errorutils_test.go diff --git a/errorutils/errorutils.go b/errorutils/errorutils.go index ebf8d197..ff82a2c1 100644 --- a/errorutils/errorutils.go +++ b/errorutils/errorutils.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC All Rights Reserved. +// Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,31 +17,122 @@ package errorutils import ( "net/http" +) + +// ErrorCode represents the platform-wide error codes that can be raised by +// Admin SDK APIs. +type ErrorCode string + +const ( + // InvalidArgument is a OnePlatform error code. + InvalidArgument ErrorCode = "INVALID_ARGUMENT" + + // FailedPrecondition is a OnePlatform error code. + FailedPrecondition ErrorCode = "FAILED_PRECONDITION" + + // OutOfRange is a OnePlatform error code. + OutOfRange ErrorCode = "OUT_OF_RANGE" + + // Unauthenticated is a OnePlatform error code. + Unauthenticated ErrorCode = "UNAUTHENTICATED" + + // PermissionDenied is a OnePlatform error code. + PermissionDenied ErrorCode = "PERMISSION_DENIED" + + // NotFound is a OnePlatform error code. + NotFound ErrorCode = "NOT_FOUND" + + // Conflict is a custom error code that represents HTTP 409 responses. + // + // OnePlatform APIs typically respond with ABORTED or ALREADY_EXISTS explicitly. But a few + // old APIs send HTTP 409 Conflict without any additional details to distinguish between the two + // cases. For these we currently use this error code. As more APIs adopt OnePlatform conventions + // this will become less important. + Conflict ErrorCode = "CONFLICT" + + // Aborted is a OnePlatform error code. + Aborted ErrorCode = "ABORTED" + + // AlreadyExists is a OnePlatform error code. + AlreadyExists ErrorCode = "ALREADY_EXISTS" + + // ResourceExhausted is a OnePlatform error code. + ResourceExhausted ErrorCode = "RESOURCE_EXHAUSTED" + + // Cancelled is a OnePlatform error code. + Cancelled ErrorCode = "CANCELLED" + + // DataLoss is a OnePlatform error code. + DataLoss ErrorCode = "DATA_LOSS" + + // Unknown is a OnePlatform error code. + Unknown ErrorCode = "UNKNOWN" - "firebase.google.com/go/v4/internal" + // Internal is a OnePlatform error code. + Internal ErrorCode = "INTERNAL" + + // Unavailable is a OnePlatform error code. + Unavailable ErrorCode = "UNAVAILABLE" + + // DeadlineExceeded is a OnePlatform error code. + DeadlineExceeded ErrorCode = "DEADLINE_EXCEEDED" ) +// FirebaseError is an error type containing an: +// - error code string. +// - error message. +// - HTTP response that caused this error, if any. +// - additional metadata about the error. +type FirebaseError struct { + ErrorCode ErrorCode + String string + Response *http.Response + Ext map[string]interface{} +} + +// Error implements the error interface. +func (fe *FirebaseError) Error() string { + return fe.String +} + +// Code returns the canonical error code associated with this error. +func (fe *FirebaseError) Code() ErrorCode { + return fe.ErrorCode +} + +// HTTPResponse returns the HTTP response that caused this error, if any. +// Returns nil if the error was not caused by an HTTP response. +func (fe *FirebaseError) HTTPResponse() *http.Response { + return fe.Response +} + +// Extensions returns additional metadata associated with this error. +// Returns nil if no extensions are available. +func (fe *FirebaseError) Extensions() map[string]interface{} { + return fe.Ext +} + // IsInvalidArgument checks if the given error was due to an invalid client argument. func IsInvalidArgument(err error) bool { - return internal.HasPlatformErrorCode(err, internal.InvalidArgument) + return HasPlatformErrorCode(err, InvalidArgument) } // IsFailedPrecondition checks if the given error was because a request could not be executed // in the current system state, such as deleting a non-empty directory. func IsFailedPrecondition(err error) bool { - return internal.HasPlatformErrorCode(err, internal.FailedPrecondition) + return HasPlatformErrorCode(err, FailedPrecondition) } // IsOutOfRange checks if the given error due to an invalid range specified by the client. func IsOutOfRange(err error) bool { - return internal.HasPlatformErrorCode(err, internal.OutOfRange) + return HasPlatformErrorCode(err, OutOfRange) } // IsUnauthenticated checks if the given error was caused by an unauthenticated request. // // Unauthenticated requests are due to missing, invalid, or expired OAuth token. func IsUnauthenticated(err error) bool { - return internal.HasPlatformErrorCode(err, internal.Unauthenticated) + return HasPlatformErrorCode(err, Unauthenticated) } // IsPermissionDenied checks if the given error was due to a client not having suffificient @@ -50,14 +141,14 @@ func IsUnauthenticated(err error) bool { // This can happen because the OAuth token does not have the right scopes, the client doesn't have // permission, or the API has not been enabled for the client project. func IsPermissionDenied(err error) bool { - return internal.HasPlatformErrorCode(err, internal.PermissionDenied) + return HasPlatformErrorCode(err, PermissionDenied) } // IsNotFound checks if the given error was due to a specified resource being not found. // // This may also occur when the request is rejected by undisclosed reasons, such as whitelisting. func IsNotFound(err error) bool { - return internal.HasPlatformErrorCode(err, internal.NotFound) + return HasPlatformErrorCode(err, NotFound) } // IsConflict checks if the given error was due to a concurrency conflict, such as a @@ -66,58 +157,58 @@ func IsNotFound(err error) bool { // This represents an HTTP 409 Conflict status code, without additional information to distinguish // between ABORTED or ALREADY_EXISTS error conditions. func IsConflict(err error) bool { - return internal.HasPlatformErrorCode(err, internal.Conflict) + return HasPlatformErrorCode(err, Conflict) } // IsAborted checks if the given error was due to a concurrency conflict, such as a // read-modify-write conflict. func IsAborted(err error) bool { - return internal.HasPlatformErrorCode(err, internal.Aborted) + return HasPlatformErrorCode(err, Aborted) } // IsAlreadyExists checks if the given error was because a resource that a client tried to create // already exists. func IsAlreadyExists(err error) bool { - return internal.HasPlatformErrorCode(err, internal.AlreadyExists) + return HasPlatformErrorCode(err, AlreadyExists) } // IsResourceExhausted checks if the given error was caused by either running out of a quota or // reaching a rate limit. func IsResourceExhausted(err error) bool { - return internal.HasPlatformErrorCode(err, internal.ResourceExhausted) + return HasPlatformErrorCode(err, ResourceExhausted) } // IsCancelled checks if the given error was due to the client cancelling a request. func IsCancelled(err error) bool { - return internal.HasPlatformErrorCode(err, internal.Cancelled) + return HasPlatformErrorCode(err, Cancelled) } // IsDataLoss checks if the given error was due to an unrecoverable data loss or corruption. // // The client should report such errors to the end user. func IsDataLoss(err error) bool { - return internal.HasPlatformErrorCode(err, internal.DataLoss) + return HasPlatformErrorCode(err, DataLoss) } // IsUnknown checks if the given error was cuased by an unknown server error. // // This typically indicates a server bug. func IsUnknown(err error) bool { - return internal.HasPlatformErrorCode(err, internal.Unknown) + return HasPlatformErrorCode(err, Unknown) } // IsInternal checks if the given error was due to an internal server error. // // This typically indicates a server bug. func IsInternal(err error) bool { - return internal.HasPlatformErrorCode(err, internal.Internal) + return HasPlatformErrorCode(err, Internal) } // IsUnavailable checks if the given error was caused by an unavailable service. // // This typically indicates that the target service is temporarily down. func IsUnavailable(err error) bool { - return internal.HasPlatformErrorCode(err, internal.Unavailable) + return HasPlatformErrorCode(err, Unavailable) } // IsDeadlineExceeded checks if the given error was due a request exceeding a deadline. @@ -126,7 +217,7 @@ func IsUnavailable(err error) bool { // deadline (i.e. requested deadline is not enough for the server to process the request) and the // request did not finish within the deadline. func IsDeadlineExceeded(err error) bool { - return internal.HasPlatformErrorCode(err, internal.DeadlineExceeded) + return HasPlatformErrorCode(err, DeadlineExceeded) } // HTTPResponse returns the http.Response instance that caused the given error. @@ -136,10 +227,16 @@ func IsDeadlineExceeded(err error) bool { // Returns a buffered copy of the original response received from the network stack. It is safe to // read the response content from the returned http.Response. func HTTPResponse(err error) *http.Response { - fe, ok := err.(*internal.FirebaseError) + fe, ok := err.(*FirebaseError) if ok { return fe.Response } return nil } + +// HasPlatformErrorCode checks if the given error contains a specific error code. +func HasPlatformErrorCode(err error, code ErrorCode) bool { + fe, ok := err.(*FirebaseError) + return ok && fe.ErrorCode == code +} diff --git a/errorutils/errorutils_test.go b/errorutils/errorutils_test.go new file mode 100644 index 00000000..dc2d1b61 --- /dev/null +++ b/errorutils/errorutils_test.go @@ -0,0 +1,267 @@ +// Copyright 2020 Google Inc. All Rights Reserved. +// +// 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. + +package errorutils + +import ( + "errors" + "net/http" + "testing" +) + +func TestFirebaseErrorImplementsError(t *testing.T) { + fe := &FirebaseError{ + ErrorCode: NotFound, + String: "resource not found", + } + + var err error = fe + if err.Error() != "resource not found" { + t.Errorf("Error() = %q; want = %q", err.Error(), "resource not found") + } +} + +func TestFirebaseErrorAccessors(t *testing.T) { + resp := &http.Response{StatusCode: http.StatusNotFound} + ext := map[string]interface{}{"key": "value"} + + fe := &FirebaseError{ + ErrorCode: NotFound, + String: "resource not found", + Response: resp, + Ext: ext, + } + + if fe.Code() != NotFound { + t.Errorf("Code() = %q; want = %q", fe.Code(), NotFound) + } + + if fe.HTTPResponse() != resp { + t.Errorf("HTTPResponse() = %v; want = %v", fe.HTTPResponse(), resp) + } + + if fe.Extensions()["key"] != "value" { + t.Errorf("Extensions()[\"key\"] = %v; want = %q", fe.Extensions()["key"], "value") + } +} + +func TestFirebaseErrorAccessorsWithNilFields(t *testing.T) { + fe := &FirebaseError{ + ErrorCode: Internal, + String: "internal error", + } + + if fe.HTTPResponse() != nil { + t.Errorf("HTTPResponse() = %v; want = nil", fe.HTTPResponse()) + } + + if fe.Extensions() != nil { + t.Errorf("Extensions() = %v; want = nil", fe.Extensions()) + } +} + +func TestHasPlatformErrorCode(t *testing.T) { + fe := &FirebaseError{ + ErrorCode: NotFound, + String: "not found", + } + + if !HasPlatformErrorCode(fe, NotFound) { + t.Error("HasPlatformErrorCode(fe, NotFound) = false; want = true") + } + + if HasPlatformErrorCode(fe, Internal) { + t.Error("HasPlatformErrorCode(fe, Internal) = true; want = false") + } +} + +func TestHasPlatformErrorCodeWithNonFirebaseError(t *testing.T) { + err := errors.New("regular error") + + if HasPlatformErrorCode(err, NotFound) { + t.Error("HasPlatformErrorCode(err, NotFound) = true; want = false") + } +} + +func TestHasPlatformErrorCodeWithNil(t *testing.T) { + if HasPlatformErrorCode(nil, NotFound) { + t.Error("HasPlatformErrorCode(nil, NotFound) = true; want = false") + } +} + +func TestHTTPResponseFunction(t *testing.T) { + resp := &http.Response{StatusCode: http.StatusInternalServerError} + fe := &FirebaseError{ + ErrorCode: Internal, + String: "internal error", + Response: resp, + } + + if HTTPResponse(fe) != resp { + t.Errorf("HTTPResponse(fe) = %v; want = %v", HTTPResponse(fe), resp) + } +} + +func TestHTTPResponseFunctionWithNonFirebaseError(t *testing.T) { + err := errors.New("regular error") + + if HTTPResponse(err) != nil { + t.Errorf("HTTPResponse(err) = %v; want = nil", HTTPResponse(err)) + } +} + +func TestHTTPResponseFunctionWithNil(t *testing.T) { + if HTTPResponse(nil) != nil { + t.Errorf("HTTPResponse(nil) = %v; want = nil", HTTPResponse(nil)) + } +} + +func TestIsErrorCodeFunctions(t *testing.T) { + testCases := []struct { + name string + code ErrorCode + checkFn func(error) bool + wantTrue bool + }{ + {"InvalidArgument", InvalidArgument, IsInvalidArgument, true}, + {"FailedPrecondition", FailedPrecondition, IsFailedPrecondition, true}, + {"OutOfRange", OutOfRange, IsOutOfRange, true}, + {"Unauthenticated", Unauthenticated, IsUnauthenticated, true}, + {"PermissionDenied", PermissionDenied, IsPermissionDenied, true}, + {"NotFound", NotFound, IsNotFound, true}, + {"Conflict", Conflict, IsConflict, true}, + {"Aborted", Aborted, IsAborted, true}, + {"AlreadyExists", AlreadyExists, IsAlreadyExists, true}, + {"ResourceExhausted", ResourceExhausted, IsResourceExhausted, true}, + {"Cancelled", Cancelled, IsCancelled, true}, + {"DataLoss", DataLoss, IsDataLoss, true}, + {"Unknown", Unknown, IsUnknown, true}, + {"Internal", Internal, IsInternal, true}, + {"Unavailable", Unavailable, IsUnavailable, true}, + {"DeadlineExceeded", DeadlineExceeded, IsDeadlineExceeded, true}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + fe := &FirebaseError{ + ErrorCode: tc.code, + String: "test error", + } + + if tc.checkFn(fe) != tc.wantTrue { + t.Errorf("%s check = %v; want = %v", tc.name, tc.checkFn(fe), tc.wantTrue) + } + }) + } +} + +func TestIsErrorCodeFunctionsWithWrongCode(t *testing.T) { + fe := &FirebaseError{ + ErrorCode: NotFound, + String: "not found", + } + + checks := []struct { + name string + checkFn func(error) bool + }{ + {"IsInvalidArgument", IsInvalidArgument}, + {"IsFailedPrecondition", IsFailedPrecondition}, + {"IsOutOfRange", IsOutOfRange}, + {"IsUnauthenticated", IsUnauthenticated}, + {"IsPermissionDenied", IsPermissionDenied}, + {"IsConflict", IsConflict}, + {"IsAborted", IsAborted}, + {"IsAlreadyExists", IsAlreadyExists}, + {"IsResourceExhausted", IsResourceExhausted}, + {"IsCancelled", IsCancelled}, + {"IsDataLoss", IsDataLoss}, + {"IsUnknown", IsUnknown}, + {"IsInternal", IsInternal}, + {"IsUnavailable", IsUnavailable}, + {"IsDeadlineExceeded", IsDeadlineExceeded}, + } + + for _, tc := range checks { + t.Run(tc.name, func(t *testing.T) { + if tc.checkFn(fe) { + t.Errorf("%s(NotFoundError) = true; want = false", tc.name) + } + }) + } +} + +func TestIsErrorCodeFunctionsWithNonFirebaseError(t *testing.T) { + err := errors.New("regular error") + + checks := []struct { + name string + checkFn func(error) bool + }{ + {"IsInvalidArgument", IsInvalidArgument}, + {"IsNotFound", IsNotFound}, + {"IsInternal", IsInternal}, + } + + for _, tc := range checks { + t.Run(tc.name, func(t *testing.T) { + if tc.checkFn(err) { + t.Errorf("%s(regularError) = true; want = false", tc.name) + } + }) + } +} + +func TestIsErrorCodeFunctionsWithNil(t *testing.T) { + if IsNotFound(nil) { + t.Error("IsNotFound(nil) = true; want = false") + } + + if IsInternal(nil) { + t.Error("IsInternal(nil) = true; want = false") + } +} + +func TestErrorCodeValues(t *testing.T) { + // Verify error codes have the expected string values + testCases := []struct { + code ErrorCode + want string + }{ + {InvalidArgument, "INVALID_ARGUMENT"}, + {FailedPrecondition, "FAILED_PRECONDITION"}, + {OutOfRange, "OUT_OF_RANGE"}, + {Unauthenticated, "UNAUTHENTICATED"}, + {PermissionDenied, "PERMISSION_DENIED"}, + {NotFound, "NOT_FOUND"}, + {Conflict, "CONFLICT"}, + {Aborted, "ABORTED"}, + {AlreadyExists, "ALREADY_EXISTS"}, + {ResourceExhausted, "RESOURCE_EXHAUSTED"}, + {Cancelled, "CANCELLED"}, + {DataLoss, "DATA_LOSS"}, + {Unknown, "UNKNOWN"}, + {Internal, "INTERNAL"}, + {Unavailable, "UNAVAILABLE"}, + {DeadlineExceeded, "DEADLINE_EXCEEDED"}, + } + + for _, tc := range testCases { + t.Run(tc.want, func(t *testing.T) { + if string(tc.code) != tc.want { + t.Errorf("ErrorCode = %q; want = %q", tc.code, tc.want) + } + }) + } +} diff --git a/internal/errors.go b/internal/errors.go index 2c8b5d9c..66dce4b2 100644 --- a/internal/errors.go +++ b/internal/errors.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC All Rights Reserved. +// Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -22,83 +22,39 @@ import ( "net/url" "os" "syscall" + + "firebase.google.com/go/v4/errorutils" ) -// ErrorCode represents the platform-wide error codes that can be raised by -// Admin SDK APIs. -type ErrorCode string +// ErrorCode alias to errorutils.ErrorCode +type ErrorCode = errorutils.ErrorCode +// Error code constants aliases to errorutils const ( - // InvalidArgument is a OnePlatform error code. - InvalidArgument ErrorCode = "INVALID_ARGUMENT" - - // FailedPrecondition is a OnePlatform error code. - FailedPrecondition ErrorCode = "FAILED_PRECONDITION" - - // OutOfRange is a OnePlatform error code. - OutOfRange ErrorCode = "OUT_OF_RANGE" - - // Unauthenticated is a OnePlatform error code. - Unauthenticated ErrorCode = "UNAUTHENTICATED" - - // PermissionDenied is a OnePlatform error code. - PermissionDenied ErrorCode = "PERMISSION_DENIED" - - // NotFound is a OnePlatform error code. - NotFound ErrorCode = "NOT_FOUND" - - // Conflict is a custom error code that represents HTTP 409 responses. - // - // OnePlatform APIs typically respond with ABORTED or ALREADY_EXISTS explicitly. But a few - // old APIs send HTTP 409 Conflict without any additional details to distinguish between the two - // cases. For these we currently use this error code. As more APIs adopt OnePlatform conventions - // this will become less important. - Conflict ErrorCode = "CONFLICT" - - // Aborted is a OnePlatform error code. - Aborted ErrorCode = "ABORTED" - - // AlreadyExists is a OnePlatform error code. - AlreadyExists ErrorCode = "ALREADY_EXISTS" - - // ResourceExhausted is a OnePlatform error code. - ResourceExhausted ErrorCode = "RESOURCE_EXHAUSTED" - - // Cancelled is a OnePlatform error code. - Cancelled ErrorCode = "CANCELLED" - - // DataLoss is a OnePlatform error code. - DataLoss ErrorCode = "DATA_LOSS" - - // Unknown is a OnePlatform error code. - Unknown ErrorCode = "UNKNOWN" - - // Internal is a OnePlatform error code. - Internal ErrorCode = "INTERNAL" - - // Unavailable is a OnePlatform error code. - Unavailable ErrorCode = "UNAVAILABLE" - - // DeadlineExceeded is a OnePlatform error code. - DeadlineExceeded ErrorCode = "DEADLINE_EXCEEDED" + InvalidArgument = errorutils.InvalidArgument + FailedPrecondition = errorutils.FailedPrecondition + OutOfRange = errorutils.OutOfRange + Unauthenticated = errorutils.Unauthenticated + PermissionDenied = errorutils.PermissionDenied + NotFound = errorutils.NotFound + Conflict = errorutils.Conflict + Aborted = errorutils.Aborted + AlreadyExists = errorutils.AlreadyExists + ResourceExhausted = errorutils.ResourceExhausted + Cancelled = errorutils.Cancelled + DataLoss = errorutils.DataLoss + Unknown = errorutils.Unknown + Internal = errorutils.Internal + Unavailable = errorutils.Unavailable + DeadlineExceeded = errorutils.DeadlineExceeded ) -// FirebaseError is an error type containing an error code string. -type FirebaseError struct { - ErrorCode ErrorCode - String string - Response *http.Response - Ext map[string]interface{} -} - -func (fe *FirebaseError) Error() string { - return fe.String -} +// FirebaseError is an alias to errorutils.FirebaseError for backwards compatibility. +type FirebaseError = errorutils.FirebaseError // HasPlatformErrorCode checks if the given error contains a specific error code. func HasPlatformErrorCode(err error, code ErrorCode) bool { - fe, ok := err.(*FirebaseError) - return ok && fe.ErrorCode == code + return errorutils.HasPlatformErrorCode(err, code) } var httpStatusToErrorCodes = map[int]ErrorCode{ From 57bc65bf19e0faa1f8600e95720bfdaea2c04159 Mon Sep 17 00:00:00 2001 From: justinattw Date: Tue, 6 Jan 2026 12:06:46 +0000 Subject: [PATCH 05/11] Inc to LLC --- errorutils/errorutils.go | 2 +- errorutils/errorutils_test.go | 2 +- internal/errors.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/errorutils/errorutils.go b/errorutils/errorutils.go index ff82a2c1..132eb2e7 100644 --- a/errorutils/errorutils.go +++ b/errorutils/errorutils.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google Inc. All Rights Reserved. +// Copyright 2020 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/errorutils/errorutils_test.go b/errorutils/errorutils_test.go index dc2d1b61..60dfcca0 100644 --- a/errorutils/errorutils_test.go +++ b/errorutils/errorutils_test.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google Inc. All Rights Reserved. +// Copyright 2020 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/internal/errors.go b/internal/errors.go index 66dce4b2..3db89e8f 100644 --- a/internal/errors.go +++ b/internal/errors.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google Inc. All Rights Reserved. +// Copyright 2020 Google LLC All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. From 40f84eb0abc1f9180d893d6920c97f7227deba87 Mon Sep 17 00:00:00 2001 From: justinattw Date: Tue, 6 Jan 2026 13:15:03 +0000 Subject: [PATCH 06/11] Fix typo Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- errorutils/errorutils.go | 1 - 1 file changed, 1 deletion(-) diff --git a/errorutils/errorutils.go b/errorutils/errorutils.go index 132eb2e7..22291ff8 100644 --- a/errorutils/errorutils.go +++ b/errorutils/errorutils.go @@ -135,7 +135,6 @@ func IsUnauthenticated(err error) bool { return HasPlatformErrorCode(err, Unauthenticated) } -// IsPermissionDenied checks if the given error was due to a client not having suffificient // permissions. // // This can happen because the OAuth token does not have the right scopes, the client doesn't have From 3eb180bf2ece27eeb2d1b6b04f94fb2734a26afb Mon Sep 17 00:00:00 2001 From: justinattw Date: Tue, 6 Jan 2026 13:28:43 +0000 Subject: [PATCH 07/11] Channge FirebaseError.String to FirebaseError.Message --- auth/auth.go | 6 +++--- auth/token_verifier.go | 12 ++++++------ auth/user_mgt.go | 8 ++++---- db/db.go | 2 +- errorutils/errorutils.go | 7 ++++--- errorutils/errorutils_test.go | 14 +++++++------- iid/iid.go | 2 +- internal/errors.go | 6 +++--- messaging/topic_mgt.go | 2 +- remoteconfig/remoteconfig.go | 2 +- 10 files changed, 31 insertions(+), 30 deletions(-) diff --git a/auth/auth.go b/auth/auth.go index 6bd3b0f2..7f24b552 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -332,7 +332,7 @@ func (c *baseClient) verifyIDToken(ctx context.Context, idToken string, checkRev if c.tenantID != "" && c.tenantID != decoded.Firebase.Tenant { return nil, &internal.FirebaseError{ ErrorCode: internal.InvalidArgument, - String: fmt.Sprintf("invalid tenant id: %q", decoded.Firebase.Tenant), + Message: fmt.Sprintf("invalid tenant id: %q", decoded.Firebase.Tenant), Ext: map[string]interface{}{ authErrorCode: tenantIDMismatch, }, @@ -428,7 +428,7 @@ func (c *baseClient) checkRevokedOrDisabled(ctx context.Context, token *Token, e if user.Disabled { return &internal.FirebaseError{ ErrorCode: internal.InvalidArgument, - String: "user has been disabled", + Message: "user has been disabled", Ext: map[string]interface{}{ authErrorCode: userDisabled, }, @@ -438,7 +438,7 @@ func (c *baseClient) checkRevokedOrDisabled(ctx context.Context, token *Token, e if token.IssuedAt*1000 < user.TokensValidAfterMillis { return &internal.FirebaseError{ ErrorCode: internal.InvalidArgument, - String: errMessage, + Message: errMessage, Ext: map[string]interface{}{ authErrorCode: errCode, }, diff --git a/auth/token_verifier.go b/auth/token_verifier.go index fe6cdf0c..827f976c 100644 --- a/auth/token_verifier.go +++ b/auth/token_verifier.go @@ -187,7 +187,7 @@ func (tv *tokenVerifier) verifyContent(token string, isEmulator bool) (*Token, e if token == "" { return nil, &internal.FirebaseError{ ErrorCode: internal.InvalidArgument, - String: fmt.Sprintf("%s must be a non-empty string", tv.shortName), + Message: fmt.Sprintf("%s must be a non-empty string", tv.shortName), Ext: map[string]interface{}{authErrorCode: tv.invalidTokenCode}, } } @@ -196,7 +196,7 @@ func (tv *tokenVerifier) verifyContent(token string, isEmulator bool) (*Token, e if err != nil { return nil, &internal.FirebaseError{ ErrorCode: internal.InvalidArgument, - String: fmt.Sprintf( + Message: fmt.Sprintf( "%s; see %s for details on how to retrieve a valid %s", err.Error(), tv.docURL, tv.shortName), Ext: map[string]interface{}{authErrorCode: tv.invalidTokenCode}, @@ -210,7 +210,7 @@ func (tv *tokenVerifier) verifyTimestamps(payload *Token) error { if (payload.IssuedAt - clockSkewSeconds) > tv.clock.Now().Unix() { return &internal.FirebaseError{ ErrorCode: internal.InvalidArgument, - String: fmt.Sprintf("%s issued at future timestamp: %d", tv.shortName, payload.IssuedAt), + Message: fmt.Sprintf("%s issued at future timestamp: %d", tv.shortName, payload.IssuedAt), Ext: map[string]interface{}{authErrorCode: tv.invalidTokenCode}, } } @@ -218,7 +218,7 @@ func (tv *tokenVerifier) verifyTimestamps(payload *Token) error { if (payload.Expires + clockSkewSeconds) < tv.clock.Now().Unix() { return &internal.FirebaseError{ ErrorCode: internal.InvalidArgument, - String: fmt.Sprintf("%s has expired at: %d", tv.shortName, payload.Expires), + Message: fmt.Sprintf("%s has expired at: %d", tv.shortName, payload.Expires), Ext: map[string]interface{}{authErrorCode: tv.expiredTokenCode}, } } @@ -231,7 +231,7 @@ func (tv *tokenVerifier) verifySignature(ctx context.Context, token string) erro if err != nil { return &internal.FirebaseError{ ErrorCode: internal.Unknown, - String: err.Error(), + Message: err.Error(), Ext: map[string]interface{}{authErrorCode: certificateFetchFailed}, } } @@ -239,7 +239,7 @@ func (tv *tokenVerifier) verifySignature(ctx context.Context, token string) erro if !tv.verifySignatureWithKeys(ctx, token, keys) { return &internal.FirebaseError{ ErrorCode: internal.InvalidArgument, - String: "failed to verify token signature", + Message: "failed to verify token signature", Ext: map[string]interface{}{authErrorCode: tv.invalidTokenCode}, } } diff --git a/auth/user_mgt.go b/auth/user_mgt.go index bee027e3..2ceede79 100644 --- a/auth/user_mgt.go +++ b/auth/user_mgt.go @@ -803,7 +803,7 @@ func (c *baseClient) GetUserByProviderUID(ctx context.Context, providerID string if len(getUsersResult.Users) == 0 { return nil, &internal.FirebaseError{ ErrorCode: internal.NotFound, - String: fmt.Sprintf("cannot find user from providerID: { %s, %s }", providerID, providerUID), + Message: fmt.Sprintf("cannot find user from providerID: { %s, %s }", providerID, providerUID), Response: nil, Ext: map[string]interface{}{ authErrorCode: userNotFound, @@ -848,7 +848,7 @@ func (c *baseClient) getUser(ctx context.Context, query *userQuery) (*UserRecord if len(parsed.Users) == 0 { return nil, &internal.FirebaseError{ ErrorCode: internal.NotFound, - String: fmt.Sprintf("no user exists with the %s", query.description()), + Message: fmt.Sprintf("no user exists with the %s", query.description()), Response: resp.LowLevelResponse(), Ext: map[string]interface{}{ authErrorCode: userNotFound, @@ -1487,9 +1487,9 @@ func handleHTTPError(resp *internal.Response) error { err.ErrorCode = authErr.code err.Ext[authErrorCode] = authErr.authCode if detail != "" { - err.String = fmt.Sprintf("%s: %s", authErr.message, detail) + err.Message = fmt.Sprintf("%s: %s", authErr.message, detail) } else { - err.String = authErr.message + err.Message = authErr.message } } diff --git a/db/db.go b/db/db.go index f30c534c..62e52440 100644 --- a/db/db.go +++ b/db/db.go @@ -150,7 +150,7 @@ func handleRTDBError(resp *internal.Response) error { } json.Unmarshal(resp.Body, &p) if p.Error != "" { - err.String = fmt.Sprintf("http error status: %d; reason: %s", resp.Status, p.Error) + err.Message = fmt.Sprintf("http error status: %d; reason: %s", resp.Status, p.Error) } return err diff --git a/errorutils/errorutils.go b/errorutils/errorutils.go index 22291ff8..79b1d0b6 100644 --- a/errorutils/errorutils.go +++ b/errorutils/errorutils.go @@ -85,14 +85,14 @@ const ( // - additional metadata about the error. type FirebaseError struct { ErrorCode ErrorCode - String string + Message string Response *http.Response Ext map[string]interface{} } // Error implements the error interface. func (fe *FirebaseError) Error() string { - return fe.String + return fe.Message } // Code returns the canonical error code associated with this error. @@ -135,6 +135,7 @@ func IsUnauthenticated(err error) bool { return HasPlatformErrorCode(err, Unauthenticated) } +// IsPermissionDenied checks if the given error was due to a client not having sufficient // permissions. // // This can happen because the OAuth token does not have the right scopes, the client doesn't have @@ -189,7 +190,7 @@ func IsDataLoss(err error) bool { return HasPlatformErrorCode(err, DataLoss) } -// IsUnknown checks if the given error was cuased by an unknown server error. +// IsUnknown checks if the given error was caused by an unknown server error. // // This typically indicates a server bug. func IsUnknown(err error) bool { diff --git a/errorutils/errorutils_test.go b/errorutils/errorutils_test.go index 60dfcca0..e5e64ad9 100644 --- a/errorutils/errorutils_test.go +++ b/errorutils/errorutils_test.go @@ -23,7 +23,7 @@ import ( func TestFirebaseErrorImplementsError(t *testing.T) { fe := &FirebaseError{ ErrorCode: NotFound, - String: "resource not found", + Message: "resource not found", } var err error = fe @@ -38,7 +38,7 @@ func TestFirebaseErrorAccessors(t *testing.T) { fe := &FirebaseError{ ErrorCode: NotFound, - String: "resource not found", + Message: "resource not found", Response: resp, Ext: ext, } @@ -59,7 +59,7 @@ func TestFirebaseErrorAccessors(t *testing.T) { func TestFirebaseErrorAccessorsWithNilFields(t *testing.T) { fe := &FirebaseError{ ErrorCode: Internal, - String: "internal error", + Message: "internal error", } if fe.HTTPResponse() != nil { @@ -74,7 +74,7 @@ func TestFirebaseErrorAccessorsWithNilFields(t *testing.T) { func TestHasPlatformErrorCode(t *testing.T) { fe := &FirebaseError{ ErrorCode: NotFound, - String: "not found", + Message: "not found", } if !HasPlatformErrorCode(fe, NotFound) { @@ -104,7 +104,7 @@ func TestHTTPResponseFunction(t *testing.T) { resp := &http.Response{StatusCode: http.StatusInternalServerError} fe := &FirebaseError{ ErrorCode: Internal, - String: "internal error", + Message: "internal error", Response: resp, } @@ -156,7 +156,7 @@ func TestIsErrorCodeFunctions(t *testing.T) { t.Run(tc.name, func(t *testing.T) { fe := &FirebaseError{ ErrorCode: tc.code, - String: "test error", + Message: "test error", } if tc.checkFn(fe) != tc.wantTrue { @@ -169,7 +169,7 @@ func TestIsErrorCodeFunctions(t *testing.T) { func TestIsErrorCodeFunctionsWithWrongCode(t *testing.T) { fe := &FirebaseError{ ErrorCode: NotFound, - String: "not found", + Message: "not found", } checks := []struct { diff --git a/iid/iid.go b/iid/iid.go index c97f6e0f..137c2310 100644 --- a/iid/iid.go +++ b/iid/iid.go @@ -152,7 +152,7 @@ func createError(resp *internal.Response) error { if msg, ok := errorMessages[resp.Status]; ok { requestPath := resp.LowLevelResponse().Request.URL.Path idx := strings.LastIndex(requestPath, "/") - err.String = fmt.Sprintf("instance id %q: %s", requestPath[idx+1:], msg) + err.Message = fmt.Sprintf("instance id %q: %s", requestPath[idx+1:], msg) } return err diff --git a/internal/errors.go b/internal/errors.go index 3db89e8f..2bbad4de 100644 --- a/internal/errors.go +++ b/internal/errors.go @@ -77,7 +77,7 @@ func NewFirebaseError(resp *Response) *FirebaseError { return &FirebaseError{ ErrorCode: code, - String: fmt.Sprintf("unexpected http response with status: %d\n%s", resp.Status, string(resp.Body)), + Message: fmt.Sprintf("unexpected http response with status: %d\n%s", resp.Status, string(resp.Body)), Response: resp.LowLevelResponse(), Ext: make(map[string]interface{}), } @@ -103,7 +103,7 @@ func NewFirebaseErrorOnePlatform(resp *Response) *FirebaseError { } if gcpError.Error.Message != "" { - base.String = gcpError.Error.Message + base.Message = gcpError.Error.Message } return base @@ -125,7 +125,7 @@ func newFirebaseErrorTransport(err error) *FirebaseError { return &FirebaseError{ ErrorCode: code, - String: msg, + Message: msg, Ext: make(map[string]interface{}), } } diff --git a/messaging/topic_mgt.go b/messaging/topic_mgt.go index 0e7e9d0c..2e9962cf 100644 --- a/messaging/topic_mgt.go +++ b/messaging/topic_mgt.go @@ -156,7 +156,7 @@ func handleIIDError(resp *internal.Response) error { var ie iidErrorResponse json.Unmarshal(resp.Body, &ie) // ignore any json parse errors at this level if ie.Error != "" { - base.String = fmt.Sprintf("error while calling the iid service: %s", ie.Error) + base.Message = fmt.Sprintf("error while calling the iid service: %s", ie.Error) } return base diff --git a/remoteconfig/remoteconfig.go b/remoteconfig/remoteconfig.go index 55117cf5..db77eb78 100644 --- a/remoteconfig/remoteconfig.go +++ b/remoteconfig/remoteconfig.go @@ -111,7 +111,7 @@ func handleRemoteConfigError(resp *internal.Response) error { } json.Unmarshal(resp.Body, &p) if p.Error != "" { - err.String = fmt.Sprintf("http error status: %d; reason: %s", resp.Status, p.Error) + err.Message = fmt.Sprintf("http error status: %d; reason: %s", resp.Status, p.Error) } return err From 972333e2abd3d7b2069df98c36382e87b26ababc Mon Sep 17 00:00:00 2001 From: justinattw Date: Tue, 6 Jan 2026 15:08:18 +0000 Subject: [PATCH 08/11] Add QuotaFailure --- messaging/messaging.go | 135 ---------------- messaging/messaging_errors.go | 241 +++++++++++++++++++++++++++++ messaging/messaging_errors_test.go | 208 +++++++++++++++++++++++++ 3 files changed, 449 insertions(+), 135 deletions(-) create mode 100644 messaging/messaging_errors.go create mode 100644 messaging/messaging_errors_test.go diff --git a/messaging/messaging.go b/messaging/messaging.go index 2eda22a9..ed76aa68 100644 --- a/messaging/messaging.go +++ b/messaging/messaging.go @@ -39,15 +39,6 @@ const ( apiFormatVersionHeader = "X-GOOG-API-FORMAT-VERSION" apiFormatVersion = "2" - apnsAuthError = "APNS_AUTH_ERROR" - internalError = "INTERNAL" - thirdPartyAuthError = "THIRD_PARTY_AUTH_ERROR" - invalidArgument = "INVALID_ARGUMENT" - quotaExceeded = "QUOTA_EXCEEDED" - senderIDMismatch = "SENDER_ID_MISMATCH" - unregistered = "UNREGISTERED" - unavailable = "UNAVAILABLE" - rfc3339Zulu = "2006-01-02T15:04:05.000000000Z" ) @@ -994,99 +985,6 @@ func (c *fcmClient) makeSendRequest(ctx context.Context, req *fcmRequest) (strin return result.Name, err } -// IsInternal checks if the given error was due to an internal server error. -func IsInternal(err error) bool { - return hasMessagingErrorCode(err, internalError) -} - -// IsInvalidAPNSCredentials checks if the given error was due to invalid APNS certificate or auth -// key. -// -// Deprecated: Use IsThirdPartyAuthError(). -func IsInvalidAPNSCredentials(err error) bool { - return IsThirdPartyAuthError(err) -} - -// IsThirdPartyAuthError checks if the given error was due to invalid APNS certificate or auth -// key. -func IsThirdPartyAuthError(err error) bool { - return hasMessagingErrorCode(err, thirdPartyAuthError) || hasMessagingErrorCode(err, apnsAuthError) -} - -// IsInvalidArgument checks if the given error was due to an invalid argument in the request. -func IsInvalidArgument(err error) bool { - return hasMessagingErrorCode(err, invalidArgument) -} - -// IsMessageRateExceeded checks if the given error was due to the client exceeding a quota. -// -// Deprecated: Use IsQuotaExceeded(). -func IsMessageRateExceeded(err error) bool { - return IsQuotaExceeded(err) -} - -// IsQuotaExceeded checks if the given error was due to the client exceeding a quota. -func IsQuotaExceeded(err error) bool { - return hasMessagingErrorCode(err, quotaExceeded) -} - -// IsMismatchedCredential checks if the given error was due to an invalid credential or permission -// error. -// -// Deprecated: Use IsSenderIDMismatch(). -func IsMismatchedCredential(err error) bool { - return IsSenderIDMismatch(err) -} - -// IsSenderIDMismatch checks if the given error was due to an invalid credential or permission -// error. -func IsSenderIDMismatch(err error) bool { - return hasMessagingErrorCode(err, senderIDMismatch) -} - -// IsRegistrationTokenNotRegistered checks if the given error was due to a registration token that -// became invalid. -// -// Deprecated: Use IsUnregistered(). -func IsRegistrationTokenNotRegistered(err error) bool { - return IsUnregistered(err) -} - -// IsUnregistered checks if the given error was due to a registration token that -// became invalid. -func IsUnregistered(err error) bool { - return hasMessagingErrorCode(err, unregistered) -} - -// IsServerUnavailable checks if the given error was due to the backend server being temporarily -// unavailable. -// -// Deprecated: Use IsUnavailable(). -func IsServerUnavailable(err error) bool { - return IsUnavailable(err) -} - -// IsUnavailable checks if the given error was due to the backend server being temporarily -// unavailable. -func IsUnavailable(err error) bool { - return hasMessagingErrorCode(err, unavailable) -} - -// IsTooManyTopics checks if the given error was due to the client exceeding the allowed number -// of topics. -// -// Deprecated: Always returns false. -func IsTooManyTopics(err error) bool { - return false -} - -// IsUnknown checks if the given error was due to unknown error returned by the backend server. -// -// Deprecated: Always returns false. -func IsUnknown(err error) bool { - return false -} - type fcmRequest struct { ValidateOnly bool `json:"validate_only,omitempty"` Message *Message `json:"message,omitempty"` @@ -1095,36 +993,3 @@ type fcmRequest struct { type fcmResponse struct { Name string `json:"name"` } - -type fcmErrorResponse struct { - Error struct { - Details []struct { - Type string `json:"@type"` - ErrorCode string `json:"errorCode"` - } - } `json:"error"` -} - -func handleFCMError(resp *internal.Response) error { - base := internal.NewFirebaseErrorOnePlatform(resp) - var fe fcmErrorResponse - json.Unmarshal(resp.Body, &fe) // ignore any json parse errors at this level - for _, d := range fe.Error.Details { - if d.Type == "type.googleapis.com/google.firebase.fcm.v1.FcmError" { - base.Ext["messagingErrorCode"] = d.ErrorCode - break - } - } - - return base -} - -func hasMessagingErrorCode(err error, code string) bool { - fe, ok := err.(*internal.FirebaseError) - if !ok { - return false - } - - got, ok := fe.Ext["messagingErrorCode"] - return ok && got == code -} diff --git a/messaging/messaging_errors.go b/messaging/messaging_errors.go new file mode 100644 index 00000000..ebd94c17 --- /dev/null +++ b/messaging/messaging_errors.go @@ -0,0 +1,241 @@ +// Copyright 2018 Google LLC All Rights Reserved. +// +// 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. + +package messaging + +import ( + "encoding/json" + + "firebase.google.com/go/v4/errorutils" + "firebase.google.com/go/v4/internal" +) + +// FCM error codes +const ( + apnsAuthError = "APNS_AUTH_ERROR" + internalError = "INTERNAL" + thirdPartyAuthError = "THIRD_PARTY_AUTH_ERROR" + invalidArgument = "INVALID_ARGUMENT" + quotaExceeded = "QUOTA_EXCEEDED" + senderIDMismatch = "SENDER_ID_MISMATCH" + unregistered = "UNREGISTERED" + unavailable = "UNAVAILABLE" +) + +// QuotaViolation describes a single quota violation, identifying which quota +// was exceeded. +// See https://docs.cloud.google.com/tasks/docs/reference/rpc/google.rpc#google.rpc.QuotaFailure.Violation +// for more information on the google.rpc.QuotaFailure.Violation type. +type QuotaViolation struct { + // Subject is the subject on which the quota check failed. + // For example, "clientip:" or "project:". + Subject string + // Description explains how the quota check failed. + Description string + // APIService is the API service from which the QuotaFailure originates. + APIService string + // QuotaMetric is the metric of the violated quota (e.g., "compute.googleapis.com/cpus"). + QuotaMetric string + // QuotaID is the unique identifier of a quota (e.g., "CPUS-per-project-region"). + QuotaID string + // QuotaDimensions contains the dimensions of the violated quota. + QuotaDimensions map[string]string + // QuotaValue is the enforced quota value at the time of the failure. + QuotaValue int64 + // FutureQuotaValue is the new quota value being rolled out, if a rollout is in progress. + FutureQuotaValue int64 +} + +// QuotaFailure contains information about quota violations from FCM. +// This is returned when a rate limit is exceeded (device, topic, or overall). +type QuotaFailure struct { + Violations []*QuotaViolation +} + +// IsInternal checks if the given error was due to an internal server error. +func IsInternal(err error) bool { + return hasMessagingErrorCode(err, internalError) +} + +// IsInvalidAPNSCredentials checks if the given error was due to invalid APNS certificate or auth +// key. +// +// Deprecated: Use IsThirdPartyAuthError(). +func IsInvalidAPNSCredentials(err error) bool { + return IsThirdPartyAuthError(err) +} + +// IsThirdPartyAuthError checks if the given error was due to invalid APNS certificate or auth +// key. +func IsThirdPartyAuthError(err error) bool { + return hasMessagingErrorCode(err, thirdPartyAuthError) || hasMessagingErrorCode(err, apnsAuthError) +} + +// IsInvalidArgument checks if the given error was due to an invalid argument in the request. +func IsInvalidArgument(err error) bool { + return hasMessagingErrorCode(err, invalidArgument) +} + +// IsMessageRateExceeded checks if the given error was due to the client exceeding a quota. +// +// Deprecated: Use IsQuotaExceeded(). +func IsMessageRateExceeded(err error) bool { + return IsQuotaExceeded(err) +} + +// IsQuotaExceeded checks if the given error was due to the client exceeding a quota. +func IsQuotaExceeded(err error) bool { + return hasMessagingErrorCode(err, quotaExceeded) +} + +// GetQuotaFailure extracts the QuotaFailure details from a FirebaseError. +// Returns nil if the error does not contain quota failure information. +// The QuotaFailure indicates which rate limit was violated: device, topic, or overall. +func GetQuotaFailure(err *errorutils.FirebaseError) *QuotaFailure { + if err == nil || err.Ext == nil { + return nil + } + + qf, ok := err.Ext["quotaFailure"].(*QuotaFailure) + if !ok { + return nil + } + + return qf +} + +// IsMismatchedCredential checks if the given error was due to an invalid credential or permission +// error. +// +// Deprecated: Use IsSenderIDMismatch(). +func IsMismatchedCredential(err error) bool { + return IsSenderIDMismatch(err) +} + +// IsSenderIDMismatch checks if the given error was due to an invalid credential or permission +// error. +func IsSenderIDMismatch(err error) bool { + return hasMessagingErrorCode(err, senderIDMismatch) +} + +// IsRegistrationTokenNotRegistered checks if the given error was due to a registration token that +// became invalid. +// +// Deprecated: Use IsUnregistered(). +func IsRegistrationTokenNotRegistered(err error) bool { + return IsUnregistered(err) +} + +// IsUnregistered checks if the given error was due to a registration token that +// became invalid. +func IsUnregistered(err error) bool { + return hasMessagingErrorCode(err, unregistered) +} + +// IsServerUnavailable checks if the given error was due to the backend server being temporarily +// unavailable. +// +// Deprecated: Use IsUnavailable(). +func IsServerUnavailable(err error) bool { + return IsUnavailable(err) +} + +// IsUnavailable checks if the given error was due to the backend server being temporarily +// unavailable. +func IsUnavailable(err error) bool { + return hasMessagingErrorCode(err, unavailable) +} + +// IsTooManyTopics checks if the given error was due to the client exceeding the allowed number +// of topics. +// +// Deprecated: Always returns false. +func IsTooManyTopics(err error) bool { + return false +} + +// IsUnknown checks if the given error was due to unknown error returned by the backend server. +// +// Deprecated: Always returns false. +func IsUnknown(err error) bool { + return false +} + +type fcmErrorResponse struct { + Error struct { + Details []fcmErrorDetail `json:"details"` + } `json:"error"` +} + +type fcmErrorDetail struct { + Type string `json:"@type"` + ErrorCode string `json:"errorCode"` + Violations []struct { + Subject string `json:"subject"` + Description string `json:"description"` + APIService string `json:"api_service"` + QuotaMetric string `json:"quota_metric"` + QuotaID string `json:"quota_id"` + QuotaDimensions map[string]string `json:"quota_dimensions"` + QuotaValue int64 `json:"quota_value"` + FutureQuotaValue int64 `json:"future_quota_value"` + } `json:"violations"` +} + +func handleFCMError(resp *internal.Response) error { + base := internal.NewFirebaseErrorOnePlatform(resp) + var fe fcmErrorResponse + json.Unmarshal(resp.Body, &fe) // ignore any json parse errors at this level + + // FCM error responses include a "details" array with typed extensions. + // See https://firebase.google.com/docs/reference/fcm/rest/v1/ErrorCode + for _, d := range fe.Error.Details { + // FcmError extension contains the FCM-specific error code. + // See https://firebase.google.com/docs/reference/fcm/rest/v1/FcmError + if d.Type == "type.googleapis.com/google.firebase.fcm.v1.FcmError" { + base.Ext["messagingErrorCode"] = d.ErrorCode + } + // QuotaFailure extension is returned when QUOTA_EXCEEDED error occurs. + // See https://firebase.google.com/docs/reference/fcm/rest/v1/ErrorCode + // "An extension of type google.rpc.QuotaFailure is returned to specify which quota was exceeded." + if d.Type == "type.googleapis.com/google.rpc.QuotaFailure" && len(d.Violations) > 0 { + violations := make([]*QuotaViolation, len(d.Violations)) + for i, v := range d.Violations { + violations[i] = &QuotaViolation{ + Subject: v.Subject, + Description: v.Description, + APIService: v.APIService, + QuotaMetric: v.QuotaMetric, + QuotaID: v.QuotaID, + QuotaDimensions: v.QuotaDimensions, + QuotaValue: v.QuotaValue, + FutureQuotaValue: v.FutureQuotaValue, + } + } + base.Ext["quotaFailure"] = &QuotaFailure{Violations: violations} + } + } + + return base +} + +func hasMessagingErrorCode(err error, code string) bool { + fe, ok := err.(*internal.FirebaseError) + if !ok { + return false + } + + got, ok := fe.Ext["messagingErrorCode"] + return ok && got == code +} diff --git a/messaging/messaging_errors_test.go b/messaging/messaging_errors_test.go new file mode 100644 index 00000000..c1d1396f --- /dev/null +++ b/messaging/messaging_errors_test.go @@ -0,0 +1,208 @@ +// Copyright 2018 Google LLC All Rights Reserved. +// +// 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. + +package messaging + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + + "firebase.google.com/go/v4/errorutils" + "firebase.google.com/go/v4/internal" +) + +func TestGetQuotaFailureEdgeCases(t *testing.T) { + tests := []struct { + name string + err *errorutils.FirebaseError + }{ + {"nil error", nil}, + {"no ext", &errorutils.FirebaseError{ErrorCode: internal.Unknown, Message: "test"}}, + {"empty ext", &errorutils.FirebaseError{ErrorCode: internal.Unknown, Ext: map[string]interface{}{}}}, + {"wrong type", &errorutils.FirebaseError{ErrorCode: internal.Unknown, Ext: map[string]interface{}{"quotaFailure": "string"}}}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + if qf := GetQuotaFailure(tc.err); qf != nil { + t.Errorf("GetQuotaFailure() = %v; want nil", qf) + } + }) + } +} + +// TestQuotaFailureParsing verifies all QuotaViolation fields are parsed correctly from FCM responses. +func TestQuotaFailureParsing(t *testing.T) { + resp := `{ + "error": { + "status": "RESOURCE_EXHAUSTED", + "message": "Quota exceeded", + "details": [ + {"@type": "type.googleapis.com/google.firebase.fcm.v1.FcmError", "errorCode": "QUOTA_EXCEEDED"}, + { + "@type": "type.googleapis.com/google.rpc.QuotaFailure", + "violations": [ + { + "subject": "project:test-project", + "description": "Device message rate exceeded", + "api_service": "firebasecloudmessaging.googleapis.com", + "quota_metric": "firebasecloudmessaging.googleapis.com/device_messages", + "quota_id": "DeviceMessagesPerMinute", + "quota_dimensions": {"device_token": "abc123"}, + "quota_value": 100, + "future_quota_value": 200 + }, + {"subject": "device:token123", "description": "Second violation"} + ] + } + ] + } + }` + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusTooManyRequests) + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(resp)) + })) + defer ts.Close() + + client, err := NewClient(context.Background(), testMessagingConfig) + if err != nil { + t.Fatal(err) + } + client.fcmEndpoint = ts.URL + client.fcmClient.httpClient.RetryConfig = nil + + _, sendErr := client.Send(context.Background(), &Message{Topic: "topic"}) + if sendErr == nil { + t.Fatal("Send() = nil; want error") + } + + // Verify error type checks work + if !IsQuotaExceeded(sendErr) { + t.Error("IsQuotaExceeded() = false; want true") + } + if !IsMessageRateExceeded(sendErr) { // deprecated alias + t.Error("IsMessageRateExceeded() = false; want true") + } + + fe := sendErr.(*errorutils.FirebaseError) + qf := GetQuotaFailure(fe) + if qf == nil { + t.Fatal("GetQuotaFailure() = nil; want non-nil") + } + if len(qf.Violations) != 2 { + t.Fatalf("len(Violations) = %d; want 2", len(qf.Violations)) + } + + // Verify all fields on first violation + v := qf.Violations[0] + if v.Subject != "project:test-project" { + t.Errorf("Subject = %q; want %q", v.Subject, "project:test-project") + } + if v.APIService != "firebasecloudmessaging.googleapis.com" { + t.Errorf("APIService = %q; want %q", v.APIService, "firebasecloudmessaging.googleapis.com") + } + if v.QuotaMetric != "firebasecloudmessaging.googleapis.com/device_messages" { + t.Errorf("QuotaMetric = %q; want correct value", v.QuotaMetric) + } + if v.QuotaID != "DeviceMessagesPerMinute" { + t.Errorf("QuotaID = %q; want %q", v.QuotaID, "DeviceMessagesPerMinute") + } + if v.QuotaDimensions == nil || v.QuotaDimensions["device_token"] != "abc123" { + t.Errorf("QuotaDimensions = %v; want map with device_token=abc123", v.QuotaDimensions) + } + if v.QuotaValue != 100 || v.FutureQuotaValue != 200 { + t.Errorf("QuotaValue=%d, FutureQuotaValue=%d; want 100, 200", v.QuotaValue, v.FutureQuotaValue) + } + + // Verify second violation + if qf.Violations[1].Subject != "device:token123" { + t.Errorf("Violations[1].Subject = %q; want %q", qf.Violations[1].Subject, "device:token123") + } +} + +// TestDeprecatedErrorFunctions verifies deprecated functions still work for backwards compatibility. +func TestDeprecatedErrorFunctions(t *testing.T) { + tests := []struct { + name string + httpStatus int + resp string + deprecated func(error) bool + current func(error) bool + }{ + { + name: "IsInvalidAPNSCredentials", + httpStatus: http.StatusUnauthorized, + resp: `{"error": {"status": "UNAUTHENTICATED", "message": "test", "details": [{"@type": "type.googleapis.com/google.firebase.fcm.v1.FcmError", "errorCode": "THIRD_PARTY_AUTH_ERROR"}]}}`, + deprecated: IsInvalidAPNSCredentials, + current: IsThirdPartyAuthError, + }, + { + name: "IsMismatchedCredential", + httpStatus: http.StatusForbidden, + resp: `{"error": {"status": "PERMISSION_DENIED", "message": "test", "details": [{"@type": "type.googleapis.com/google.firebase.fcm.v1.FcmError", "errorCode": "SENDER_ID_MISMATCH"}]}}`, + deprecated: IsMismatchedCredential, + current: IsSenderIDMismatch, + }, + { + name: "IsRegistrationTokenNotRegistered", + httpStatus: http.StatusNotFound, + resp: `{"error": {"status": "NOT_FOUND", "message": "test", "details": [{"@type": "type.googleapis.com/google.firebase.fcm.v1.FcmError", "errorCode": "UNREGISTERED"}]}}`, + deprecated: IsRegistrationTokenNotRegistered, + current: IsUnregistered, + }, + { + name: "IsServerUnavailable", + httpStatus: http.StatusServiceUnavailable, + resp: `{"error": {"status": "UNAVAILABLE", "message": "test", "details": [{"@type": "type.googleapis.com/google.firebase.fcm.v1.FcmError", "errorCode": "UNAVAILABLE"}]}}`, + deprecated: IsServerUnavailable, + current: IsUnavailable, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(tc.httpStatus) + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(tc.resp)) + })) + defer ts.Close() + + client, _ := NewClient(context.Background(), testMessagingConfig) + client.fcmEndpoint = ts.URL + client.fcmClient.httpClient.RetryConfig = nil + + _, err := client.Send(context.Background(), &Message{Topic: "topic"}) + if !tc.deprecated(err) { + t.Errorf("%s() = false; want true", tc.name) + } + if !tc.current(err) { + t.Errorf("current function = false; want true") + } + }) + } +} + +// TestDeprecatedFunctionsAlwaysFalse verifies IsTooManyTopics and IsUnknown always return false. +func TestDeprecatedFunctionsAlwaysFalse(t *testing.T) { + if IsTooManyTopics(nil) { + t.Error("IsTooManyTopics(nil) = true; want false") + } + if IsUnknown(nil) { + t.Error("IsUnknown(nil) = true; want false") + } +} From c791ad2b7e4cbf1839a5344742ea6b1d76df3786 Mon Sep 17 00:00:00 2001 From: justinattw Date: Tue, 6 Jan 2026 15:25:26 +0000 Subject: [PATCH 09/11] LLC back to Inc. --- appcheck/appcheck.go | 2 +- auth/auth.go | 8 ++++---- auth/auth_appengine.go | 2 +- auth/auth_std.go | 2 +- auth/auth_test.go | 2 +- auth/email_action_links.go | 2 +- auth/email_action_links_test.go | 2 +- auth/export_users.go | 2 +- auth/hash/hash.go | 2 +- auth/hash/hash_test.go | 2 +- auth/import_users.go | 2 +- auth/multi_factor_config_mgt.go | 2 +- auth/multi_factor_config_mgt_test.go | 2 +- auth/project_config_mgt.go | 2 +- auth/project_config_mgt_test.go | 2 +- auth/provider_config.go | 2 +- auth/provider_config_test.go | 2 +- auth/tenant_mgt.go | 2 +- auth/tenant_mgt_test.go | 2 +- auth/token_generator.go | 2 +- auth/token_generator_test.go | 2 +- auth/token_verifier.go | 12 ++++++------ auth/token_verifier_test.go | 2 +- auth/user_mgt.go | 2 +- auth/user_mgt_test.go | 2 +- db/auth_override_test.go | 2 +- db/db.go | 2 +- db/db_test.go | 2 +- db/query.go | 2 +- db/query_test.go | 2 +- db/ref.go | 2 +- db/ref_test.go | 2 +- errorutils/errorutils.go | 2 +- errorutils/errorutils_test.go | 2 +- firebase.go | 2 +- firebase_test.go | 2 +- iid/iid.go | 2 +- iid/iid_test.go | 2 +- integration/auth/auth_test.go | 2 +- integration/auth/project_config_mgt_test.go | 2 +- integration/auth/provider_config_test.go | 2 +- integration/auth/tenant_mgt_test.go | 2 +- integration/auth/user_mgt_test.go | 2 +- integration/db/db_test.go | 2 +- integration/db/query_test.go | 2 +- integration/firestore/firestore_test.go | 2 +- integration/iid/iid_test.go | 2 +- integration/internal/internal.go | 2 +- integration/messaging/messaging_test.go | 2 +- integration/storage/storage_test.go | 2 +- internal/errors.go | 6 +++--- internal/errors_test.go | 2 +- internal/http_client.go | 2 +- internal/http_client_test.go | 2 +- internal/internal.go | 2 +- internal/json_http_client_test.go | 2 +- messaging/messaging.go | 2 +- messaging/messaging_batch.go | 2 +- messaging/messaging_batch_test.go | 2 +- messaging/messaging_errors.go | 2 +- messaging/messaging_errors_test.go | 2 +- messaging/messaging_test.go | 2 +- messaging/messaging_utils.go | 2 +- messaging/topic_mgt.go | 2 +- messaging/topic_mgt_test.go | 2 +- remoteconfig/condition_evaluator.go | 2 +- remoteconfig/condition_evaluator_test.go | 2 +- remoteconfig/remoteconfig.go | 2 +- remoteconfig/remoteconfig_test.go | 2 +- remoteconfig/server_config.go | 2 +- remoteconfig/server_template.go | 2 +- remoteconfig/server_template_test.go | 2 +- remoteconfig/server_template_types.go | 2 +- snippets/db.go | 2 +- storage/storage.go | 2 +- storage/storage_test.go | 2 +- 76 files changed, 86 insertions(+), 86 deletions(-) diff --git a/appcheck/appcheck.go b/appcheck/appcheck.go index c2fefaa8..89868916 100644 --- a/appcheck/appcheck.go +++ b/appcheck/appcheck.go @@ -1,4 +1,4 @@ -// Copyright 2022 Google LLC All Rights Reserved. +// Copyright 2022 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/auth.go b/auth/auth.go index 7f24b552..475d3aa7 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -332,7 +332,7 @@ func (c *baseClient) verifyIDToken(ctx context.Context, idToken string, checkRev if c.tenantID != "" && c.tenantID != decoded.Firebase.Tenant { return nil, &internal.FirebaseError{ ErrorCode: internal.InvalidArgument, - Message: fmt.Sprintf("invalid tenant id: %q", decoded.Firebase.Tenant), + Message: fmt.Sprintf("invalid tenant id: %q", decoded.Firebase.Tenant), Ext: map[string]interface{}{ authErrorCode: tenantIDMismatch, }, @@ -428,7 +428,7 @@ func (c *baseClient) checkRevokedOrDisabled(ctx context.Context, token *Token, e if user.Disabled { return &internal.FirebaseError{ ErrorCode: internal.InvalidArgument, - Message: "user has been disabled", + Message: "user has been disabled", Ext: map[string]interface{}{ authErrorCode: userDisabled, }, @@ -438,7 +438,7 @@ func (c *baseClient) checkRevokedOrDisabled(ctx context.Context, token *Token, e if token.IssuedAt*1000 < user.TokensValidAfterMillis { return &internal.FirebaseError{ ErrorCode: internal.InvalidArgument, - Message: errMessage, + Message: errMessage, Ext: map[string]interface{}{ authErrorCode: errCode, }, diff --git a/auth/auth_appengine.go b/auth/auth_appengine.go index 1d2c2cc0..06eee2a9 100644 --- a/auth/auth_appengine.go +++ b/auth/auth_appengine.go @@ -1,7 +1,7 @@ //go:build appengine // +build appengine -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/auth_std.go b/auth/auth_std.go index b8eda30b..e5a9cb87 100644 --- a/auth/auth_std.go +++ b/auth/auth_std.go @@ -1,7 +1,7 @@ //go:build !appengine // +build !appengine -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/auth_test.go b/auth/auth_test.go index 69127b22..9c8b1523 100644 --- a/auth/auth_test.go +++ b/auth/auth_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/email_action_links.go b/auth/email_action_links.go index bc08d401..282e79fe 100644 --- a/auth/email_action_links.go +++ b/auth/email_action_links.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC All Rights Reserved. +// Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/email_action_links_test.go b/auth/email_action_links_test.go index 8ed55e66..2575ff32 100644 --- a/auth/email_action_links_test.go +++ b/auth/email_action_links_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC All Rights Reserved. +// Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/export_users.go b/auth/export_users.go index 5b086b80..7e5670a7 100644 --- a/auth/export_users.go +++ b/auth/export_users.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC All Rights Reserved. +// Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/hash/hash.go b/auth/hash/hash.go index b18f8bd6..dce1217d 100644 --- a/auth/hash/hash.go +++ b/auth/hash/hash.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/hash/hash_test.go b/auth/hash/hash_test.go index c1406ac6..675e7d8f 100644 --- a/auth/hash/hash_test.go +++ b/auth/hash/hash_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/import_users.go b/auth/import_users.go index 6a1e1ff9..6de0c37b 100644 --- a/auth/import_users.go +++ b/auth/import_users.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC All Rights Reserved. +// Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/multi_factor_config_mgt.go b/auth/multi_factor_config_mgt.go index 8e0bc109..d01e2f46 100644 --- a/auth/multi_factor_config_mgt.go +++ b/auth/multi_factor_config_mgt.go @@ -1,4 +1,4 @@ -// Copyright 2023 Google LLC All Rights Reserved. +// Copyright 2023 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/multi_factor_config_mgt_test.go b/auth/multi_factor_config_mgt_test.go index be31774f..ebbef4eb 100644 --- a/auth/multi_factor_config_mgt_test.go +++ b/auth/multi_factor_config_mgt_test.go @@ -1,4 +1,4 @@ -// Copyright 2023 Google LLC All Rights Reserved. +// Copyright 2023 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/project_config_mgt.go b/auth/project_config_mgt.go index 510eb915..5ae739cd 100644 --- a/auth/project_config_mgt.go +++ b/auth/project_config_mgt.go @@ -1,4 +1,4 @@ -// Copyright 2023 Google LLC All Rights Reserved. +// Copyright 2023 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/project_config_mgt_test.go b/auth/project_config_mgt_test.go index ad19dde3..ec0fa756 100644 --- a/auth/project_config_mgt_test.go +++ b/auth/project_config_mgt_test.go @@ -1,4 +1,4 @@ -// Copyright 2023 Google LLC All Rights Reserved. +// Copyright 2023 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/provider_config.go b/auth/provider_config.go index c33eaf0d..312fa349 100644 --- a/auth/provider_config.go +++ b/auth/provider_config.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC All Rights Reserved. +// Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/provider_config_test.go b/auth/provider_config_test.go index 4e2e2551..0defec12 100644 --- a/auth/provider_config_test.go +++ b/auth/provider_config_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC All Rights Reserved. +// Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/tenant_mgt.go b/auth/tenant_mgt.go index 35b27de1..0e3ab205 100644 --- a/auth/tenant_mgt.go +++ b/auth/tenant_mgt.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC All Rights Reserved. +// Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/tenant_mgt_test.go b/auth/tenant_mgt_test.go index e411793c..77c26851 100644 --- a/auth/tenant_mgt_test.go +++ b/auth/tenant_mgt_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC All Rights Reserved. +// Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/token_generator.go b/auth/token_generator.go index fed6facf..7aa2d564 100644 --- a/auth/token_generator.go +++ b/auth/token_generator.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/token_generator_test.go b/auth/token_generator_test.go index 6ed5144e..c79e3a9a 100644 --- a/auth/token_generator_test.go +++ b/auth/token_generator_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/token_verifier.go b/auth/token_verifier.go index 827f976c..3d895715 100644 --- a/auth/token_verifier.go +++ b/auth/token_verifier.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -187,7 +187,7 @@ func (tv *tokenVerifier) verifyContent(token string, isEmulator bool) (*Token, e if token == "" { return nil, &internal.FirebaseError{ ErrorCode: internal.InvalidArgument, - Message: fmt.Sprintf("%s must be a non-empty string", tv.shortName), + Message: fmt.Sprintf("%s must be a non-empty string", tv.shortName), Ext: map[string]interface{}{authErrorCode: tv.invalidTokenCode}, } } @@ -210,7 +210,7 @@ func (tv *tokenVerifier) verifyTimestamps(payload *Token) error { if (payload.IssuedAt - clockSkewSeconds) > tv.clock.Now().Unix() { return &internal.FirebaseError{ ErrorCode: internal.InvalidArgument, - Message: fmt.Sprintf("%s issued at future timestamp: %d", tv.shortName, payload.IssuedAt), + Message: fmt.Sprintf("%s issued at future timestamp: %d", tv.shortName, payload.IssuedAt), Ext: map[string]interface{}{authErrorCode: tv.invalidTokenCode}, } } @@ -218,7 +218,7 @@ func (tv *tokenVerifier) verifyTimestamps(payload *Token) error { if (payload.Expires + clockSkewSeconds) < tv.clock.Now().Unix() { return &internal.FirebaseError{ ErrorCode: internal.InvalidArgument, - Message: fmt.Sprintf("%s has expired at: %d", tv.shortName, payload.Expires), + Message: fmt.Sprintf("%s has expired at: %d", tv.shortName, payload.Expires), Ext: map[string]interface{}{authErrorCode: tv.expiredTokenCode}, } } @@ -231,7 +231,7 @@ func (tv *tokenVerifier) verifySignature(ctx context.Context, token string) erro if err != nil { return &internal.FirebaseError{ ErrorCode: internal.Unknown, - Message: err.Error(), + Message: err.Error(), Ext: map[string]interface{}{authErrorCode: certificateFetchFailed}, } } @@ -239,7 +239,7 @@ func (tv *tokenVerifier) verifySignature(ctx context.Context, token string) erro if !tv.verifySignatureWithKeys(ctx, token, keys) { return &internal.FirebaseError{ ErrorCode: internal.InvalidArgument, - Message: "failed to verify token signature", + Message: "failed to verify token signature", Ext: map[string]interface{}{authErrorCode: tv.invalidTokenCode}, } } diff --git a/auth/token_verifier_test.go b/auth/token_verifier_test.go index e24d7d1c..e11c56d9 100644 --- a/auth/token_verifier_test.go +++ b/auth/token_verifier_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/user_mgt.go b/auth/user_mgt.go index 2ceede79..a32d4f48 100644 --- a/auth/user_mgt.go +++ b/auth/user_mgt.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/auth/user_mgt_test.go b/auth/user_mgt_test.go index 01d8734f..445cf718 100644 --- a/auth/user_mgt_test.go +++ b/auth/user_mgt_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/db/auth_override_test.go b/db/auth_override_test.go index c179bd74..02f2671a 100644 --- a/db/auth_override_test.go +++ b/db/auth_override_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/db/db.go b/db/db.go index 62e52440..ae748069 100644 --- a/db/db.go +++ b/db/db.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/db/db_test.go b/db/db_test.go index 68517189..5766c045 100644 --- a/db/db_test.go +++ b/db/db_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/db/query.go b/db/query.go index ca826db9..424e00a8 100644 --- a/db/query.go +++ b/db/query.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/db/query_test.go b/db/query_test.go index df05bf1c..9c72971e 100644 --- a/db/query_test.go +++ b/db/query_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/db/ref.go b/db/ref.go index e41af43f..bb26a531 100644 --- a/db/ref.go +++ b/db/ref.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/db/ref_test.go b/db/ref_test.go index b3427700..969eedc5 100644 --- a/db/ref_test.go +++ b/db/ref_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/errorutils/errorutils.go b/errorutils/errorutils.go index 79b1d0b6..2d4d37b0 100644 --- a/errorutils/errorutils.go +++ b/errorutils/errorutils.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC All Rights Reserved. +// Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/errorutils/errorutils_test.go b/errorutils/errorutils_test.go index e5e64ad9..60d8c568 100644 --- a/errorutils/errorutils_test.go +++ b/errorutils/errorutils_test.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC All Rights Reserved. +// Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/firebase.go b/firebase.go index 9373ae23..6101a8d9 100644 --- a/firebase.go +++ b/firebase.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/firebase_test.go b/firebase_test.go index 2699146a..7830225e 100644 --- a/firebase_test.go +++ b/firebase_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/iid/iid.go b/iid/iid.go index 137c2310..0566f0e9 100644 --- a/iid/iid.go +++ b/iid/iid.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/iid/iid_test.go b/iid/iid_test.go index 5597cb62..208da357 100644 --- a/iid/iid_test.go +++ b/iid/iid_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/auth/auth_test.go b/integration/auth/auth_test.go index 3bf43461..66809972 100644 --- a/integration/auth/auth_test.go +++ b/integration/auth/auth_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/auth/project_config_mgt_test.go b/integration/auth/project_config_mgt_test.go index 72df927b..50284005 100644 --- a/integration/auth/project_config_mgt_test.go +++ b/integration/auth/project_config_mgt_test.go @@ -1,4 +1,4 @@ -// Copyright 2023 Google LLC All Rights Reserved. +// Copyright 2023 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/auth/provider_config_test.go b/integration/auth/provider_config_test.go index 7d789d7a..f0c9f285 100644 --- a/integration/auth/provider_config_test.go +++ b/integration/auth/provider_config_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC All Rights Reserved. +// Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/auth/tenant_mgt_test.go b/integration/auth/tenant_mgt_test.go index a1349d4c..8682cb33 100644 --- a/integration/auth/tenant_mgt_test.go +++ b/integration/auth/tenant_mgt_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC All Rights Reserved. +// Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/auth/user_mgt_test.go b/integration/auth/user_mgt_test.go index cae59097..4311e77a 100644 --- a/integration/auth/user_mgt_test.go +++ b/integration/auth/user_mgt_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/db/db_test.go b/integration/db/db_test.go index 9a5d715a..93be1eef 100644 --- a/integration/db/db_test.go +++ b/integration/db/db_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/db/query_test.go b/integration/db/query_test.go index 392cb498..6bb48cf0 100644 --- a/integration/db/query_test.go +++ b/integration/db/query_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/firestore/firestore_test.go b/integration/firestore/firestore_test.go index 3e6d2da9..8e3dd60f 100644 --- a/integration/firestore/firestore_test.go +++ b/integration/firestore/firestore_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/iid/iid_test.go b/integration/iid/iid_test.go index ff9067dd..a14b2fdf 100644 --- a/integration/iid/iid_test.go +++ b/integration/iid/iid_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/internal/internal.go b/integration/internal/internal.go index d57b3f91..3a7948cc 100644 --- a/integration/internal/internal.go +++ b/integration/internal/internal.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/messaging/messaging_test.go b/integration/messaging/messaging_test.go index 4552988a..e32aac9d 100644 --- a/integration/messaging/messaging_test.go +++ b/integration/messaging/messaging_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/integration/storage/storage_test.go b/integration/storage/storage_test.go index 860288bc..9912c664 100644 --- a/integration/storage/storage_test.go +++ b/integration/storage/storage_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/internal/errors.go b/internal/errors.go index 2bbad4de..284190aa 100644 --- a/internal/errors.go +++ b/internal/errors.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC All Rights Reserved. +// Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -77,7 +77,7 @@ func NewFirebaseError(resp *Response) *FirebaseError { return &FirebaseError{ ErrorCode: code, - Message: fmt.Sprintf("unexpected http response with status: %d\n%s", resp.Status, string(resp.Body)), + Message: fmt.Sprintf("unexpected http response with status: %d\n%s", resp.Status, string(resp.Body)), Response: resp.LowLevelResponse(), Ext: make(map[string]interface{}), } @@ -125,7 +125,7 @@ func newFirebaseErrorTransport(err error) *FirebaseError { return &FirebaseError{ ErrorCode: code, - Message: msg, + Message: msg, Ext: make(map[string]interface{}), } } diff --git a/internal/errors_test.go b/internal/errors_test.go index ccd38f20..3733429e 100644 --- a/internal/errors_test.go +++ b/internal/errors_test.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC All Rights Reserved. +// Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/internal/http_client.go b/internal/http_client.go index 9d1257bc..9463f98e 100644 --- a/internal/http_client.go +++ b/internal/http_client.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/internal/http_client_test.go b/internal/http_client_test.go index 22b498cf..2d8d97c4 100644 --- a/internal/http_client_test.go +++ b/internal/http_client_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/internal/internal.go b/internal/internal.go index 58450f45..a6eb1294 100644 --- a/internal/internal.go +++ b/internal/internal.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/internal/json_http_client_test.go b/internal/json_http_client_test.go index be827b75..15ebed73 100644 --- a/internal/json_http_client_test.go +++ b/internal/json_http_client_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC All Rights Reserved. +// Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/messaging/messaging.go b/messaging/messaging.go index ed76aa68..b5077c53 100644 --- a/messaging/messaging.go +++ b/messaging/messaging.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/messaging/messaging_batch.go b/messaging/messaging_batch.go index 03129587..365190a4 100644 --- a/messaging/messaging_batch.go +++ b/messaging/messaging_batch.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC All Rights Reserved. +// Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/messaging/messaging_batch_test.go b/messaging/messaging_batch_test.go index ed9a1a42..e8603eae 100644 --- a/messaging/messaging_batch_test.go +++ b/messaging/messaging_batch_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC All Rights Reserved. +// Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/messaging/messaging_errors.go b/messaging/messaging_errors.go index ebd94c17..90cf020c 100644 --- a/messaging/messaging_errors.go +++ b/messaging/messaging_errors.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/messaging/messaging_errors_test.go b/messaging/messaging_errors_test.go index c1d1396f..06b3e761 100644 --- a/messaging/messaging_errors_test.go +++ b/messaging/messaging_errors_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/messaging/messaging_test.go b/messaging/messaging_test.go index 0cb72065..659a0c96 100644 --- a/messaging/messaging_test.go +++ b/messaging/messaging_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/messaging/messaging_utils.go b/messaging/messaging_utils.go index 5716b328..e69dd652 100644 --- a/messaging/messaging_utils.go +++ b/messaging/messaging_utils.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/messaging/topic_mgt.go b/messaging/topic_mgt.go index 2e9962cf..ef01ed9d 100644 --- a/messaging/topic_mgt.go +++ b/messaging/topic_mgt.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC All Rights Reserved. +// Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/messaging/topic_mgt_test.go b/messaging/topic_mgt_test.go index 1b0adba9..6d58114d 100644 --- a/messaging/topic_mgt_test.go +++ b/messaging/topic_mgt_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC All Rights Reserved. +// Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/remoteconfig/condition_evaluator.go b/remoteconfig/condition_evaluator.go index accbb359..02efd451 100644 --- a/remoteconfig/condition_evaluator.go +++ b/remoteconfig/condition_evaluator.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google LLC All Rights Reserved. +// Copyright 2025 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/remoteconfig/condition_evaluator_test.go b/remoteconfig/condition_evaluator_test.go index 07b81636..c7265cff 100644 --- a/remoteconfig/condition_evaluator_test.go +++ b/remoteconfig/condition_evaluator_test.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google LLC All Rights Reserved. +// Copyright 2025 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/remoteconfig/remoteconfig.go b/remoteconfig/remoteconfig.go index db77eb78..b1ec9748 100644 --- a/remoteconfig/remoteconfig.go +++ b/remoteconfig/remoteconfig.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google LLC All Rights Reserved. +// Copyright 2025 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/remoteconfig/remoteconfig_test.go b/remoteconfig/remoteconfig_test.go index f9a39f8a..14578ab5 100644 --- a/remoteconfig/remoteconfig_test.go +++ b/remoteconfig/remoteconfig_test.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google LLC All Rights Reserved. +// Copyright 2025 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/remoteconfig/server_config.go b/remoteconfig/server_config.go index 4aa1668c..fc06a235 100644 --- a/remoteconfig/server_config.go +++ b/remoteconfig/server_config.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google LLC All Rights Reserved. +// Copyright 2025 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/remoteconfig/server_template.go b/remoteconfig/server_template.go index 693d32b6..b6d6e9ec 100644 --- a/remoteconfig/server_template.go +++ b/remoteconfig/server_template.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google LLC All Rights Reserved. +// Copyright 2025 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/remoteconfig/server_template_test.go b/remoteconfig/server_template_test.go index 076e1719..d09e4e2a 100644 --- a/remoteconfig/server_template_test.go +++ b/remoteconfig/server_template_test.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google LLC All Rights Reserved. +// Copyright 2025 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/remoteconfig/server_template_types.go b/remoteconfig/server_template_types.go index 4986e0dd..059e66fd 100644 --- a/remoteconfig/server_template_types.go +++ b/remoteconfig/server_template_types.go @@ -1,4 +1,4 @@ -// Copyright 2025 Google LLC All Rights Reserved. +// Copyright 2025 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/snippets/db.go b/snippets/db.go index e37e182a..9277ff04 100644 --- a/snippets/db.go +++ b/snippets/db.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC All Rights Reserved. +// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/storage/storage.go b/storage/storage.go index cbe548c2..3f1b9d1b 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/storage/storage_test.go b/storage/storage_test.go index 4c66ae71..f0eec7a5 100644 --- a/storage/storage_test.go +++ b/storage/storage_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC All Rights Reserved. +// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. From d33246b4936b81812ae1206c4d11413c869aafdd Mon Sep 17 00:00:00 2001 From: justinattw Date: Tue, 6 Jan 2026 15:27:52 +0000 Subject: [PATCH 10/11] LLC to Inc. 2 --- .github/scripts/generate_changelog.sh | 2 +- .github/scripts/publish_preflight_check.sh | 2 +- .github/scripts/run_all_tests.sh | 2 +- .github/workflows/nightly.yml | 2 +- .github/workflows/release.yml | 2 +- AGENTS.md | 123 --------------------- 6 files changed, 5 insertions(+), 128 deletions(-) delete mode 100644 AGENTS.md diff --git a/.github/scripts/generate_changelog.sh b/.github/scripts/generate_changelog.sh index a0afa6e4..e393f40e 100755 --- a/.github/scripts/generate_changelog.sh +++ b/.github/scripts/generate_changelog.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2020 Google LLC +# Copyright 2020 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.github/scripts/publish_preflight_check.sh b/.github/scripts/publish_preflight_check.sh index 691192d5..632960eb 100755 --- a/.github/scripts/publish_preflight_check.sh +++ b/.github/scripts/publish_preflight_check.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2020 Google LLC +# Copyright 2020 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.github/scripts/run_all_tests.sh b/.github/scripts/run_all_tests.sh index 96d02d5b..c47961b3 100755 --- a/.github/scripts/run_all_tests.sh +++ b/.github/scripts/run_all_tests.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2020 Google LLC +# Copyright 2020 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index b5b7665e..9a819795 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -1,4 +1,4 @@ -# Copyright 2021 Google LLC +# Copyright 2021 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6b32ee10..bfb0d04e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,4 @@ -# Copyright 2020 Google LLC +# Copyright 2020 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index e6b95039..00000000 --- a/AGENTS.md +++ /dev/null @@ -1,123 +0,0 @@ -# Firebase Admin Go SDK - Agent Guide - -This document provides a comprehensive guide for AI agents to understand the conventions, design patterns, and architecture of the Firebase Admin Go SDK. Adhering to these guidelines is crucial for making idiomatic and consistent code contributions. - -## 1. High-Level Overview - -The Firebase Admin Go SDK enables server-side (backend) applications to interact with Firebase services. Its design emphasizes idiomatic Go, thread-safety, and a consistent, discoverable API surface. - -## 2. Directory Structure - -- `firebase.go`: The primary entry point for initializing a Firebase `App` instance. -- `internal/`: Contains private implementation details, such as HTTP clients and utility functions, that are not part of the public API. -- `auth/`, `db/`, `messaging/`, etc.: Each directory contains a specific Firebase service client. -- `*_test.go`: Unit tests are located alongside the code they test (e.g., `auth/auth_test.go`). -- `integration/`: Contains integration tests that make live network calls to Firebase services. -- `snippets/`: Contains code snippets used in documentation. -- `errorutils/`: Contains common error type checkers and other error handling utils. -- `testdata/`: Contains mock data used in some tests. - -## 3. Core Design Patterns - -- **Initialization:** The SDK is initialized by creating an `App` instance via `firebase.NewApp()`. This `App` object is the central point for accessing all service clients. -- **Service Clients:** Service clients (e.g., `auth.Client`, `db.Client`) are obtained from the `App` instance (e.g., `app.Auth(ctx)`). These clients are lightweight and are typically created as needed. -- **Error Handling:** Errors are handled using standard Go idioms. Firbase errors are defined in `internal/errors.go` however these errors can be further modified within each service. This modification is applied using that service's set `internal.HTTPClient.CreateErrFn` value. -- **HTTP Communication:** All outgoing HTTP requests are managed by a centralized client located in `internal/http_client.go`. This ensures consistent handling of authentication, retries, and error parsing. -- **Asynchronous Operations:** The SDK uses `context.Context` to manage deadlines, cancellations, and request-scoped values for all asynchronous operations. - -## 4. Coding Style and Naming Conventions - -- **Naming:** - - Public functions, types, and fields use `PascalCase`. - - Private functions and types use `camelCase`. - - Constants are written in `PascalCase`. - -## 5. Testing Philosophy - -- **Unit Tests:** Unit tests follow the `*_test.go` naming pattern and are placed in the same directory as the code under test. They use standard Go testing packages and mocks to isolate dependencies. -- **Integration Tests:** Integration tests are located in the `integration/` directory. They are designed to run against actual Firebase services and require a configured Firebase project. - -## 6. Dependency Management - -- **Manager:** The SDK uses Go Modules for dependency management. -- **Manifest:** Dependencies are declared in the `go.mod` file. -- **Command:** To add or update dependencies, use `go get` or `go mod tidy`. - -## 7. Critical Developer Journeys - -### Journey 1: How to Add a New API Method - -1. **Define Public Method:** Add the new method or change to the appropriate service client files (e.g., `auth/user_mgt.go`). -2. **Internal Logic:** Implement the core logic within the service package. -3. **HTTP Client:** Use the client in `internal/http_client.go` to make the API calls. -4. **Error Handling:** New or updated error codes implemented in the appropriate location. -5. **Testing:** - - Add unit tests in the corresponding `*_test.go` file (e.g., `auth/user_mgt_test.go`). - - Add integration tests in the `integration/` directory if applicable. -6. **Snippets:** (Optional) Add or update code snippets in the `snippets/` directory. - -### Journey 2: How to Deprecate a Field/Method in an Existing API - -1. **Add Deprecation Note:** Locate where the deprecated object is defined and add a deprecation warning with a note (e.g. `// Deprecated: Use X instead.`). - -## 8. Critical Do's and Don'ts - -- **DO:** Use the centralized HTTP client in `internal/http_client.go` for all network calls. -- **DO:** Pass `context.Context` as the first argument to all functions that perform I/O or other blocking operations. -- **DON'T:** Expose types or functions from the `internal/` directory in the public API. -- **DON'T:** Introduce new third-party dependencies without a strong, documented justification and team consensus. - -## 9. Branch Creation -- When creating a new barnch use the format `agentName-short-description`. - * Example: `jules-auth-token-parsing` - * Example: `gemini-add-storage-file-signer` - - -## 10. Commit and Pull Request Generation - -After implementing and testing a change, you may create a commit and pull request which must follow the following these rules: - -### Commit and Pull Request Title Format: -Use the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification: `type(scope): subject` -- `type` should be one of `feat`, `fix` or `chore`. -- `scope` should be the service package changed (e.g., `auth`, `rtdb`, `deps`). - - **Note**: Some services use specific abbreviations. Use the abbreviation if one exists. Common abbreviations include: - - `messaging` -> `fcm` - - `dataconnect` -> `fdc` - - `database` -> `rtdb` - - `appcheck` -> `fac` -- `subject` should be a brief summary of the change depending on the action: - - For pull requests this should focus on the larger goal the included commits achieve. - - Example: `fix(auth): Resolved issue with custom token verification` - - For commits this should focus on the specific changes made in that commit. - - Example: `fix(auth): Added a new token verification check` - -### Commit Body: - This should be a brief explanation of code changes. - -Example: -``` -feat(fcm): Added `SendEachForMulticast` support for multicast messages - -Added a new `SendEachForMulticast` method to the messaging client. This method wraps the `SendEach` method and sends the same message to each token. -``` - -### Pull Request Body: -- A brief explanation of the problem and the solution. -- A summary of the testing strategy (e.g., "Added a new unit test to verify the fix."). -- A **Context Sources** section that lists the `id` and repository path of every `AGENTS.md` file you used. - -Example: -``` -feat(fcm): Added support for multicast messages - -This change introduces a new `SendEachForMulticast` method to the messaging client, allowing developers to send a single message to multiple tokens efficiently. - -Testing: Added unit tests in `messaging_test.go` with a mock server and an integration test in `integration/messaging_test.go`. - -Context Sources Used: -- id: firebase-admin-go (`/AGENTS.md`) -``` - -## 11. Metadata -- id: firebase-admin-go \ No newline at end of file From c27801470298a62fa759d2845dce995628d9bc9b Mon Sep 17 00:00:00 2001 From: justinattw Date: Tue, 6 Jan 2026 15:31:17 +0000 Subject: [PATCH 11/11] LLC to Inc. --- auth/user_mgt.go | 2 +- auth/user_mgt_test.go | 2 +- integration/auth/user_mgt_test.go | 14 -------------- snippets/auth.go | 2 +- snippets/init.go | 2 +- snippets/messaging.go | 2 +- snippets/storage.go | 2 +- 7 files changed, 6 insertions(+), 20 deletions(-) diff --git a/auth/user_mgt.go b/auth/user_mgt.go index a32d4f48..016e69d3 100644 --- a/auth/user_mgt.go +++ b/auth/user_mgt.go @@ -1510,7 +1510,7 @@ func parseErrorResponse(resp *internal.Response) (string, string) { idx := strings.Index(code, ":") if idx != -1 { detail = strings.TrimSpace(code[idx+1:]) - code = strings.TrimSpace(code[:idx]) + code = code[:idx] } return code, detail diff --git a/auth/user_mgt_test.go b/auth/user_mgt_test.go index 445cf718..53ccdc58 100644 --- a/auth/user_mgt_test.go +++ b/auth/user_mgt_test.go @@ -2191,7 +2191,7 @@ func TestHTTPErrorWithCode(t *testing.T) { } func TestAuthErrorWithCodeAndDetails(t *testing.T) { - resp := []byte(`{"error":{"message":"USER_NOT_FOUND : extra details"}}`) + resp := []byte(`{"error":{"message":"USER_NOT_FOUND: extra details"}}`) s := echoServer(resp, t) defer s.Close() s.Client.baseClient.httpClient.RetryConfig = nil diff --git a/integration/auth/user_mgt_test.go b/integration/auth/user_mgt_test.go index 4311e77a..1c37cd0a 100644 --- a/integration/auth/user_mgt_test.go +++ b/integration/auth/user_mgt_test.go @@ -35,7 +35,6 @@ import ( const ( continueURL = "http://localhost/?a=1&b=2#c=3" - invalidContinueURL = "http://www.localhost/?a=1&b=2#c=3" continueURLKey = "continueUrl" oobCodeKey = "oobCode" modeKey = "mode" @@ -1298,19 +1297,6 @@ func TestEmailSignInLink(t *testing.T) { } } -func TestAuthErrorParse(t *testing.T) { - user := newUserWithParams(t) - defer deleteUser(user.UID) - _, err := client.EmailSignInLink(context.Background(), user.Email, &auth.ActionCodeSettings{ - URL: invalidContinueURL, - HandleCodeInApp: false, - }) - want := "domain of the continue url is not whitelisted: " - if err == nil || !auth.IsUnauthorizedContinueURI(err) || !strings.HasPrefix(err.Error(), want) { - t.Errorf("EmailSignInLink() expected error, got: %s, want: %s", err, want) - } -} - func resetPassword(email, oldPassword, newPassword, oobCode string) error { req := map[string]interface{}{ "email": email, diff --git a/snippets/auth.go b/snippets/auth.go index a3f8cd8a..df003339 100644 --- a/snippets/auth.go +++ b/snippets/auth.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC +// Copyright 2017 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/snippets/init.go b/snippets/init.go index d7db1313..3125a702 100644 --- a/snippets/init.go +++ b/snippets/init.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC +// Copyright 2017 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/snippets/messaging.go b/snippets/messaging.go index 1b25cb1c..2b073dcb 100644 --- a/snippets/messaging.go +++ b/snippets/messaging.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC +// Copyright 2018 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/snippets/storage.go b/snippets/storage.go index 22c09402..5ef1b1f2 100644 --- a/snippets/storage.go +++ b/snippets/storage.go @@ -1,4 +1,4 @@ -// Copyright 2017 Google LLC +// Copyright 2017 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License.