From 32af2b8141bddb7230dd4db7e6612703f2dfc25b Mon Sep 17 00:00:00 2001 From: Lahiru Maramba Date: Thu, 22 Jun 2023 18:05:56 -0400 Subject: [PATCH 1/8] [chore] Release 4.12.0 (#561) - Release 4.12.0 --- firebase.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firebase.go b/firebase.go index a06829b1d..fb3b0b471 100644 --- a/firebase.go +++ b/firebase.go @@ -39,7 +39,7 @@ import ( var defaultAuthOverrides = make(map[string]interface{}) // Version of the Firebase Go Admin SDK. -const Version = "4.11.0" +const Version = "4.12.0" // firebaseEnvName is the name of the environment variable with the Config. const firebaseEnvName = "FIREBASE_CONFIG" From 02300a8e865290c35d0ff92ff241ee38ccd814a7 Mon Sep 17 00:00:00 2001 From: Lahiru Maramba Date: Tue, 11 Jul 2023 12:21:57 -0400 Subject: [PATCH 2/8] Revert "[chore] Release 4.12.0 (#561)" (#565) This reverts commit 32af2b8141bddb7230dd4db7e6612703f2dfc25b. --- firebase.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firebase.go b/firebase.go index fb3b0b471..a06829b1d 100644 --- a/firebase.go +++ b/firebase.go @@ -39,7 +39,7 @@ import ( var defaultAuthOverrides = make(map[string]interface{}) // Version of the Firebase Go Admin SDK. -const Version = "4.12.0" +const Version = "4.11.0" // firebaseEnvName is the name of the environment variable with the Config. const firebaseEnvName = "FIREBASE_CONFIG" From 9ca523c220c172f7a85d1b5e989a1a89dc7a66e8 Mon Sep 17 00:00:00 2001 From: toshinori sato Date: Fri, 20 May 2022 14:51:41 +0900 Subject: [PATCH 3/8] add feature to create email action link of verify and change email (cherry picked from commit 2c5dd06172854f4388663eefd3db50b109259a44) --- auth/email_action_links.go | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/auth/email_action_links.go b/auth/email_action_links.go index 6b649254a..30b66af5a 100644 --- a/auth/email_action_links.go +++ b/auth/email_action_links.go @@ -64,9 +64,10 @@ func (settings *ActionCodeSettings) toMap() (map[string]interface{}, error) { type linkType string const ( - emailLinkSignIn linkType = "EMAIL_SIGNIN" - emailVerification linkType = "VERIFY_EMAIL" - passwordReset linkType = "PASSWORD_RESET" + emailLinkSignIn linkType = "EMAIL_SIGNIN" + emailVerification linkType = "VERIFY_EMAIL" + passwordReset linkType = "PASSWORD_RESET" + verifyAndChangeEmail linkType = "VERIFY_AND_CHANGE_EMAIL" ) // EmailVerificationLink generates the out-of-band email action link for email verification flows for the specified @@ -79,7 +80,7 @@ func (c *baseClient) EmailVerificationLink(ctx context.Context, email string) (s // specified email address, using the action code settings provided. func (c *baseClient) EmailVerificationLinkWithSettings( ctx context.Context, email string, settings *ActionCodeSettings) (string, error) { - return c.generateEmailActionLink(ctx, emailVerification, email, settings) + return c.generateEmailActionLink(ctx, emailVerification, email, settings, nil) } // PasswordResetLink generates the out-of-band email action link for password reset flows for the specified email @@ -92,18 +93,31 @@ func (c *baseClient) PasswordResetLink(ctx context.Context, email string) (strin // specified email address, using the action code settings provided. func (c *baseClient) PasswordResetLinkWithSettings( ctx context.Context, email string, settings *ActionCodeSettings) (string, error) { - return c.generateEmailActionLink(ctx, passwordReset, email, settings) + return c.generateEmailActionLink(ctx, passwordReset, email, settings, nil) } // EmailSignInLink generates the out-of-band email action link for email link sign-in flows, using the action // code settings provided. func (c *baseClient) EmailSignInLink( ctx context.Context, email string, settings *ActionCodeSettings) (string, error) { - return c.generateEmailActionLink(ctx, emailLinkSignIn, email, settings) + return c.generateEmailActionLink(ctx, emailLinkSignIn, email, settings, nil) +} + +// VerifyAndChangeEmailLink generates the out-of-band email action link for email verification and change flows for the +// specified email address. +func (c *baseClient) VerifyAndChangeEmailLink(ctx context.Context, email string, newEmail string) (string, error) { + return c.VerifyAndChangeEmailLinkWithSettings(ctx, email, newEmail, nil) +} + +// VerifyAndChangeEmailLinkWithSettings generates the out-of-band email action link for email verification and change +// flows for the specified email address, using the action code settings provided. +func (c *baseClient) VerifyAndChangeEmailLinkWithSettings( + ctx context.Context, email string, newEmail string, settings *ActionCodeSettings) (string, error) { + return c.generateEmailActionLink(ctx, verifyAndChangeEmail, email, settings, &newEmail) } func (c *baseClient) generateEmailActionLink( - ctx context.Context, linkType linkType, email string, settings *ActionCodeSettings) (string, error) { + ctx context.Context, linkType linkType, email string, settings *ActionCodeSettings, newEmail *string) (string, error) { if email == "" { return "", errors.New("email must not be empty") @@ -118,6 +132,14 @@ func (c *baseClient) generateEmailActionLink( "email": email, "returnOobLink": true, } + + if linkType == verifyAndChangeEmail { + if newEmail == nil { + return "", errors.New("newEmail must not be nil when linkType is verifyAndChangeEmail") + } + payload["newEmail"] = *newEmail + } + if settings != nil { settingsMap, err := settings.toMap() if err != nil { From dfb7d168c98fe397033037231147e73215af0a6e Mon Sep 17 00:00:00 2001 From: toshinori sato Date: Fri, 20 May 2022 14:51:57 +0900 Subject: [PATCH 4/8] add test for VerifyAndChangeEmailLink (cherry picked from commit 57b9ee10658a6869ad4855d6fc1fc6075d669160) --- auth/email_action_links_test.go | 50 +++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/auth/email_action_links_test.go b/auth/email_action_links_test.go index 876f33007..0f7b6db2b 100644 --- a/auth/email_action_links_test.go +++ b/auth/email_action_links_test.go @@ -29,6 +29,7 @@ const ( testActionLink = "https://test.link" testActionLinkFormat = `{"oobLink": %q}` testEmail = "user@domain.com" + testNewEmail = "user-new@domain.com" ) var testActionLinkResponse = []byte(fmt.Sprintf(testActionLinkFormat, testActionLink)) @@ -309,6 +310,55 @@ func TestEmailVerificationLinkError(t *testing.T) { } } +func TestVerifyAndChangeEmailLink(t *testing.T) { + s := echoServer(testActionLinkResponse, t) + defer s.Close() + + link, err := s.Client.VerifyAndChangeEmailLink(context.Background(), testEmail, testNewEmail) + if err != nil { + t.Fatal(err) + } + if link != testActionLink { + t.Errorf("TestVerifyAndChangeEmailLink() = %q; want = %q", link, testActionLink) + } + + want := map[string]interface{}{ + "requestType": "VERIFY_AND_CHANGE_EMAIL", + "email": testEmail, + "returnOobLink": true, + "newEmail": testNewEmail, + } + if err := checkActionLinkRequest(want, s); err != nil { + t.Fatalf("TestVerifyAndChangeEmailLink() %v", err) + } +} + +func TestVerifyAndChangeEmailLinkWithSettings(t *testing.T) { + s := echoServer(testActionLinkResponse, t) + defer s.Close() + + link, err := s.Client.VerifyAndChangeEmailLinkWithSettings(context.Background(), testEmail, testNewEmail, testActionCodeSettings) + if err != nil { + t.Fatal(err) + } + if link != testActionLink { + t.Errorf("VerifyAndChangeEmailLinkWithSettings() = %q; want = %q", link, testActionLink) + } + + want := map[string]interface{}{ + "requestType": "VERIFY_AND_CHANGE_EMAIL", + "email": testEmail, + "returnOobLink": true, + "newEmail": testNewEmail, + } + for k, v := range testActionCodeSettingsMap { + want[k] = v + } + if err := checkActionLinkRequest(want, s); err != nil { + t.Fatalf("VerifyAndChangeEmailLinkWithSettings() %v", err) + } +} + func checkActionLinkRequest(want map[string]interface{}, s *mockAuthServer) error { wantURL := "/projects/mock-project-id/accounts:sendOobCode" return checkActionLinkRequestWithURL(want, wantURL, s) From da74cd2ed96ed20cd435898423309315ebfab5e5 Mon Sep 17 00:00:00 2001 From: toshinori sato Date: Fri, 20 May 2022 14:52:18 +0900 Subject: [PATCH 5/8] add tenant test for VerifyAndChangeEmailLink (cherry picked from commit 108834beeda018c2699e4c67a5aca80161dacb17) --- auth/tenant_mgt_test.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/auth/tenant_mgt_test.go b/auth/tenant_mgt_test.go index 77c268519..f545ad6a5 100644 --- a/auth/tenant_mgt_test.go +++ b/auth/tenant_mgt_test.go @@ -569,6 +569,34 @@ func TestTenantEmailSignInLink(t *testing.T) { } } +func TestTenantVerifyAndChangeEmail(t *testing.T) { + s := echoServer(testActionLinkResponse, t) + defer s.Close() + + client, err := s.Client.TenantManager.AuthForTenant("tenantID") + if err != nil { + t.Fatalf("AuthForTenant() = %v", err) + } + + link, err := client.VerifyAndChangeEmailLink(context.Background(), testEmail, testNewEmail) + if err != nil { + t.Fatal(err) + } + if link != testActionLink { + t.Errorf("VerifyAndChangeEmailLink() = %q; want = %q", link, testActionLink) + } + + want := map[string]interface{}{ + "requestType": "VERIFY_AND_CHANGE_EMAIL", + "email": testEmail, + "returnOobLink": true, + "newEmail": testNewEmail, + } + if err := checkActionLinkRequestWithURL(want, wantEmailActionURL, s); err != nil { + t.Fatalf("VerifyAndChangeEmailLink() %v", err) + } +} + func TestTenantOIDCProviderConfig(t *testing.T) { s := echoServer([]byte(oidcConfigResponse), t) defer s.Close() From cf66b07957b7709e273f6c7c0008bf3eae288453 Mon Sep 17 00:00:00 2001 From: toshinori sato Date: Fri, 20 May 2022 14:53:15 +0900 Subject: [PATCH 6/8] add tenant integration test for VerifyAndChangeEmailLink (cherry picked from commit 8a7ccb605a8bf8cdbec15548cdcad82fa473b0ad) --- integration/auth/tenant_mgt_test.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/integration/auth/tenant_mgt_test.go b/integration/auth/tenant_mgt_test.go index 8682cb332..ce0bfe144 100644 --- a/integration/auth/tenant_mgt_test.go +++ b/integration/auth/tenant_mgt_test.go @@ -372,6 +372,23 @@ func testTenantAwareUserManagement(t *testing.T, id string) { } }) + t.Run("VerifyAndChangeEmailLink()", func(t *testing.T) { + newEmail := "new-" + want.Email + link, err := tenantClient.VerifyAndChangeEmailLink(context.Background(), want.Email, newEmail) + if err != nil { + t.Fatalf("VerifyAndChangeEmailLink() = %v", err) + } + + tenant, err := extractTenantID(link) + if err != nil { + t.Fatalf("VerifyAndChangeEmailLink() = %v", err) + } + + if id != tenant { + t.Fatalf("VerifyAndChangeEmailLink() TenantID = %q; want = %q", tenant, id) + } + }) + t.Run("RevokeRefreshTokens()", func(t *testing.T) { validSinceMillis := time.Now().Unix() * 1000 time.Sleep(1 * time.Second) From b8a379fa5dc9621f659b98f15c71d22def1ecfef Mon Sep 17 00:00:00 2001 From: toshinori sato Date: Thu, 9 Jun 2022 08:07:15 +0900 Subject: [PATCH 7/8] fix error message in test --- auth/email_action_links_test.go | 2 +- auth/tenant_mgt_test.go | 2 +- integration/auth/tenant_mgt_test.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/auth/email_action_links_test.go b/auth/email_action_links_test.go index 0f7b6db2b..90651875d 100644 --- a/auth/email_action_links_test.go +++ b/auth/email_action_links_test.go @@ -355,7 +355,7 @@ func TestVerifyAndChangeEmailLinkWithSettings(t *testing.T) { want[k] = v } if err := checkActionLinkRequest(want, s); err != nil { - t.Fatalf("VerifyAndChangeEmailLinkWithSettings() %v", err) + t.Fatalf("checkActionLinkRequest() = %v", err) } } diff --git a/auth/tenant_mgt_test.go b/auth/tenant_mgt_test.go index f545ad6a5..7db83894e 100644 --- a/auth/tenant_mgt_test.go +++ b/auth/tenant_mgt_test.go @@ -593,7 +593,7 @@ func TestTenantVerifyAndChangeEmail(t *testing.T) { "newEmail": testNewEmail, } if err := checkActionLinkRequestWithURL(want, wantEmailActionURL, s); err != nil { - t.Fatalf("VerifyAndChangeEmailLink() %v", err) + t.Fatalf("checkActionLinkRequestWithURL() = %v", err) } } diff --git a/integration/auth/tenant_mgt_test.go b/integration/auth/tenant_mgt_test.go index ce0bfe144..5ecbbea06 100644 --- a/integration/auth/tenant_mgt_test.go +++ b/integration/auth/tenant_mgt_test.go @@ -381,7 +381,7 @@ func testTenantAwareUserManagement(t *testing.T, id string) { tenant, err := extractTenantID(link) if err != nil { - t.Fatalf("VerifyAndChangeEmailLink() = %v", err) + t.Fatalf("extractTenantID(%s) = %v", link, err) } if id != tenant { From 2be35567d04e46b43fa082ff991831c8fd10b51e Mon Sep 17 00:00:00 2001 From: utamori Date: Fri, 5 Jun 2026 08:03:13 +0900 Subject: [PATCH 8/8] refactor email action link generation to use functional options --- auth/email_action_links.go | 36 ++++++++++++++++++++++----------- auth/email_action_links_test.go | 15 ++++++++++++++ 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/auth/email_action_links.go b/auth/email_action_links.go index 30b66af5a..99a373dac 100644 --- a/auth/email_action_links.go +++ b/auth/email_action_links.go @@ -76,11 +76,22 @@ func (c *baseClient) EmailVerificationLink(ctx context.Context, email string) (s return c.EmailVerificationLinkWithSettings(ctx, email, nil) } +// emailActionLinkOption modifies the request payload sent to the email action link generation API. +type emailActionLinkOption func(payload map[string]interface{}) + +// withNewEmail adds the newEmail field to the request payload. Used when generating links for +// verify-and-change-email flows. +func withNewEmail(newEmail string) emailActionLinkOption { + return func(payload map[string]interface{}) { + payload["newEmail"] = newEmail + } +} + // EmailVerificationLinkWithSettings generates the out-of-band email action link for email verification flows for the // specified email address, using the action code settings provided. func (c *baseClient) EmailVerificationLinkWithSettings( ctx context.Context, email string, settings *ActionCodeSettings) (string, error) { - return c.generateEmailActionLink(ctx, emailVerification, email, settings, nil) + return c.generateEmailActionLink(ctx, emailVerification, email, settings) } // PasswordResetLink generates the out-of-band email action link for password reset flows for the specified email @@ -93,31 +104,35 @@ func (c *baseClient) PasswordResetLink(ctx context.Context, email string) (strin // specified email address, using the action code settings provided. func (c *baseClient) PasswordResetLinkWithSettings( ctx context.Context, email string, settings *ActionCodeSettings) (string, error) { - return c.generateEmailActionLink(ctx, passwordReset, email, settings, nil) + return c.generateEmailActionLink(ctx, passwordReset, email, settings) } // EmailSignInLink generates the out-of-band email action link for email link sign-in flows, using the action // code settings provided. func (c *baseClient) EmailSignInLink( ctx context.Context, email string, settings *ActionCodeSettings) (string, error) { - return c.generateEmailActionLink(ctx, emailLinkSignIn, email, settings, nil) + return c.generateEmailActionLink(ctx, emailLinkSignIn, email, settings) } // VerifyAndChangeEmailLink generates the out-of-band email action link for email verification and change flows for the -// specified email address. +// specified current email address and new email address. func (c *baseClient) VerifyAndChangeEmailLink(ctx context.Context, email string, newEmail string) (string, error) { return c.VerifyAndChangeEmailLinkWithSettings(ctx, email, newEmail, nil) } // VerifyAndChangeEmailLinkWithSettings generates the out-of-band email action link for email verification and change -// flows for the specified email address, using the action code settings provided. +// flows for the specified current email address and new email address, using the action code settings provided. func (c *baseClient) VerifyAndChangeEmailLinkWithSettings( ctx context.Context, email string, newEmail string, settings *ActionCodeSettings) (string, error) { - return c.generateEmailActionLink(ctx, verifyAndChangeEmail, email, settings, &newEmail) + if newEmail == "" { + return "", errors.New("newEmail must not be empty") + } + return c.generateEmailActionLink(ctx, verifyAndChangeEmail, email, settings, withNewEmail(newEmail)) } func (c *baseClient) generateEmailActionLink( - ctx context.Context, linkType linkType, email string, settings *ActionCodeSettings, newEmail *string) (string, error) { + ctx context.Context, linkType linkType, email string, settings *ActionCodeSettings, + opts ...emailActionLinkOption) (string, error) { if email == "" { return "", errors.New("email must not be empty") @@ -133,11 +148,8 @@ func (c *baseClient) generateEmailActionLink( "returnOobLink": true, } - if linkType == verifyAndChangeEmail { - if newEmail == nil { - return "", errors.New("newEmail must not be nil when linkType is verifyAndChangeEmail") - } - payload["newEmail"] = *newEmail + for _, opt := range opts { + opt(payload) } if settings != nil { diff --git a/auth/email_action_links_test.go b/auth/email_action_links_test.go index 90651875d..1b890bba4 100644 --- a/auth/email_action_links_test.go +++ b/auth/email_action_links_test.go @@ -242,6 +242,21 @@ func TestEmailActionLinkNoEmail(t *testing.T) { if _, err := client.EmailSignInLink(context.Background(), "", testActionCodeSettings); err == nil { t.Errorf("EmailSignInLink('') = nil; want error") } + + if _, err := client.VerifyAndChangeEmailLink(context.Background(), "", testNewEmail); err == nil { + t.Errorf("VerifyAndChangeEmailLink('') = nil; want error") + } +} + +func TestVerifyAndChangeEmailLinkNoNewEmail(t *testing.T) { + client := &Client{ + baseClient: &baseClient{}, + } + + want := "newEmail must not be empty" + if _, err := client.VerifyAndChangeEmailLink(context.Background(), testEmail, ""); err == nil || err.Error() != want { + t.Errorf("VerifyAndChangeEmailLink('') = %v; want = %q", err, want) + } } func TestEmailVerificationLinkInvalidSettings(t *testing.T) {