diff --git a/cmd/server/assets/login/_loginscripts.html b/cmd/server/assets/login/_loginscripts.html index 6cba421f8..7873166df 100644 --- a/cmd/server/assets/login/_loginscripts.html +++ b/cmd/server/assets/login/_loginscripts.html @@ -82,6 +82,41 @@ {{end}} +{{define "login/pwd-validate"}} +{{if .requirements.HasRequirements}} +

+ + Password should be: + {{if gt .requirements.Length 0}} + + At least {{.requirements.Length}} characters long + + {{end}} + {{if gt .requirements.Uppercase 0}} + + Contain {{.requirements.Uppercase}} uppercase letter + + {{end}} + {{if gt .requirements.Lowercase 0}} + + Contain {{.requirements.Lowercase}} lowercase letter + + {{end}} + {{if gt .requirements.Number 0}} + + Contain {{.requirements.Number}} number + + {{end}} + {{if gt .requirements.Special 0}} + + Contain {{.requirements.Special}} special character + + {{end}} + +

+{{end}} +{{end}} + {{define "login/pwd-validate-js"}} {{if .requirements.HasRequirements}} let $lenReq = $('#length-req'); diff --git a/cmd/server/assets/login/change-password.html b/cmd/server/assets/login/change-password.html index 1849db96b..37735d4a4 100644 --- a/cmd/server/assets/login/change-password.html +++ b/cmd/server/assets/login/change-password.html @@ -39,38 +39,7 @@ - {{if .requirements.HasRequirements}} -

- - Password should be: - {{if gt .requirements.Length 0}} - - At least {{.requirements.Length}} characters long - - {{end}} - {{if gt .requirements.Uppercase 0}} - - Contain {{.requirements.Uppercase}} uppercase letter - - {{end}} - {{if gt .requirements.Lowercase 0}} - - Contain {{.requirements.Lowercase}} lowercase letter - - {{end}} - {{if gt .requirements.Number 0}} - - Contain {{.requirements.Number}} number - - {{end}} - {{if gt .requirements.Special 0}} - - Contain {{.requirements.Special}} special character - - {{end}} - -

- {{end}} + {{template "login/pwd-validate" .}} diff --git a/cmd/server/assets/login/select-password.html b/cmd/server/assets/login/select-password.html index a0d2f70cd..150a1212c 100644 --- a/cmd/server/assets/login/select-password.html +++ b/cmd/server/assets/login/select-password.html @@ -5,7 +5,6 @@ {{template "floatingform" .}} {{template "head" .}} - {{template "firebase" .}} @@ -18,16 +17,16 @@
Select new password
-
+ {{.csrfField}}
- +
-
@@ -37,38 +36,7 @@
- {{if .requirements.HasRequirements}} -

- - Password should be: - {{if gt .requirements.Length 0}} - - At least {{.requirements.Length}} characters long - - {{end}} - {{if gt .requirements.Uppercase 0}} - - Contain {{.requirements.Uppercase}} uppercase letter - - {{end}} - {{if gt .requirements.Lowercase 0}} - - Contain {{.requirements.Lowercase}} lowercase letter - - {{end}} - {{if gt .requirements.Number 0}} - - Contain {{.requirements.Number}} number - - {{end}} - {{if gt .requirements.Special 0}} - - Contain {{.requirements.Special}} special character - - {{end}} - -

- {{end}} + {{template "login/pwd-validate" .}} @@ -87,25 +55,9 @@ $(function() { let $form = $('#loginForm'); let $submit = $('#submit'); - let $email = $('#email'); let $password = $('#password'); let $retype = $('#retype'); - let urlVars = getUrlVars(); - let code = urlVars["oobCode"]; - if (!code) { - code = ""; - } - - firebase.auth().verifyPasswordResetCode(code) - .then(function(email) { - $email.val(email); - }).catch(function(error) { - flash.error("Invalid password reset code. " - + "The code may be malformed, expired, or has already been used."); - $submit.prop('disabled', true); - }); - $password.keyup(function() { $submit.prop('disabled', !checkPasswordValid($password.val())); }); @@ -121,7 +73,6 @@ }); function selectPassword() { - let email = $email.val(); let pwd = $password.val(); if (pwd != $retype.val()) { flash.clear(); @@ -135,31 +86,11 @@ // Disable the submit button so we only attempt once. $submit.prop('disabled', true); - - return firebase.auth().confirmPasswordReset(code, pwd) - .then(function() { - return true; - }).catch(function(error) { - flash.clear(); - flash.error(error); - $submit.prop('disabled', false); - return false; - }); + return true; } {{template "login/pwd-validate-js" .}} }); - - function getUrlVars() { - let vars = [], hash; - let queryParams = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); - for (var i = 0; i < queryParams.length; i++) { - v = queryParams[i].split('='); - vars.push(v[0]); - vars[v[0]] = v[1]; - } - return vars; - } diff --git a/cmd/server/main.go b/cmd/server/main.go index 95e8b49be..577bea757 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -227,8 +227,8 @@ func realMain(ctx context.Context) error { sub.Handle("/", loginController.HandleLogin()).Methods("GET") sub.Handle("/login/reset-password", loginController.HandleShowResetPassword()).Methods("GET") sub.Handle("/login/reset-password", loginController.HandleSubmitResetPassword()).Methods("POST") - sub.Handle("/login/select-password", loginController.HandleShowSelectNewPassword()).Methods("GET") - sub.Handle("/login/select-password", loginController.HandleSubmitNewPassword()).Methods("POST") + sub.Handle("/login/select-password", loginController.HandleShowSelectNewPassword()).Queries("oobCode", "").Methods("GET") + sub.Handle("/login/select-password", loginController.HandleSubmitNewPassword()).Queries("oobCode", "").Methods("POST") sub.Handle("/session", loginController.HandleCreateSession()).Methods("POST") sub.Handle("/signout", loginController.HandleSignOut()).Methods("GET") diff --git a/internal/firebase/error.go b/internal/firebase/error.go index 62c55dc8d..b12495ffc 100644 --- a/internal/firebase/error.go +++ b/internal/firebase/error.go @@ -14,11 +14,14 @@ package firebase -import "errors" +import ( + "errors" +) var ( ErrEmailNotFound = &ErrorDetails{Err: "EMAIL_NOT_FOUND"} ErrInvalidOOBCode = &ErrorDetails{Err: "INVALID_OOB_CODE"} + ErrExpiredOOBCode = &ErrorDetails{Err: "EXPIRED_OOB_CODE"} ErrCredentialTooOld = &ErrorDetails{Err: "CREDENTIAL_TOO_OLD_LOGIN_AGAIN"} ErrTokenExpired = &ErrorDetails{Err: "TOKEN_EXPIRED"} ErrInvalidToken = &ErrorDetails{Err: "INVALID_ID_TOKEN"} @@ -36,6 +39,13 @@ func (err *ErrorDetails) Error() string { return err.Err } +func (err *ErrorDetails) Is(target error) bool { + if tErr, ok := target.(*ErrorDetails); ok { + return err.Err == tErr.Err + } + return false +} + // ShouldReauthenticate returns true for errors that require a refreshed auth token. func (err *ErrorDetails) ShouldReauthenticate() bool { return errors.Is(err, ErrCredentialTooOld) || diff --git a/internal/firebase/verify_password_reset_code.go b/internal/firebase/verify_password_reset_code.go index db3611d3f..12623cf60 100644 --- a/internal/firebase/verify_password_reset_code.go +++ b/internal/firebase/verify_password_reset_code.go @@ -34,38 +34,56 @@ type verifyPasswordResetCodeRequest struct { // using the code. // // See: https://firebase.google.com/docs/reference/rest/auth#section-send-password-reset-email -func (c *Client) VerifyPasswordResetCode(ctx context.Context, code, newPassword string) error { - r := &verifyPasswordResetCodeRequest{ - Code: code, - NewPassword: newPassword, +func (c *Client) VerifyPasswordResetCode(ctx context.Context, code string) (string, error) { + return c.ChangePasswordWithCode(ctx, code, "") +} + +func (c *Client) ChangePasswordWithCode(ctx context.Context, code, newPassword string) (string, error) { + r := &verifyPasswordResetCodeRequest{Code: code} + if newPassword != "" { + r.NewPassword = newPassword } var body bytes.Buffer if err := json.NewEncoder(&body).Encode(r); err != nil { - return fmt.Errorf("failed to create json body: %w", err) + return "", fmt.Errorf("failed to create json body: %w", err) } u := c.buildURL("/v1/accounts:resetPassword") req, err := http.NewRequestWithContext(ctx, http.MethodPost, u, &body) if err != nil { - return fmt.Errorf("failed to build request: %w", err) + return "", fmt.Errorf("failed to build request: %w", err) } req.Header.Add("Accept", "application/json") req.Header.Add("Content-Type", "application/json") resp, err := c.client.Do(req) if err != nil { - return fmt.Errorf("failed to send password reset email: %w", err) + return "", fmt.Errorf("failed to send password reset email: %w", err) } defer resp.Body.Close() - if status := resp.StatusCode; status != http.StatusOK { - b, err := ioutil.ReadAll(resp.Body) - if err != nil { - return fmt.Errorf("response was %d, but failed to read body: %w", status, err) + status := resp.StatusCode + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", fmt.Errorf("response was %d, but failed to read body: %w", status, err) + } + + if status != http.StatusOK { + // Try to unmarshal the error message. Firebase uses these as enum values to expand on the code. + var m map[string]ErrorDetails + if err := json.Unmarshal(b, &m); err == nil { + d := m["error"] + return "", &d } - return fmt.Errorf("failure %d: %s", status, string(b)) + + return "", fmt.Errorf("failure %d: %s", status, string(b)) + } + + var m map[string]string + if err := json.Unmarshal(b, &m); err == nil { + return m["email"], nil } - return nil + return "", nil } diff --git a/pkg/controller/admin/admin.go b/pkg/controller/admin/admin.go index 20a367843..c3dc2b76e 100644 --- a/pkg/controller/admin/admin.go +++ b/pkg/controller/admin/admin.go @@ -29,21 +29,21 @@ import ( ) type Controller struct { - config *config.ServerConfig - db *database.Database - fbAuth *auth.Client - h *render.Renderer - logger *zap.SugaredLogger + config *config.ServerConfig + db *database.Database + firebaseAuth *auth.Client + h *render.Renderer + logger *zap.SugaredLogger } -func New(ctx context.Context, config *config.ServerConfig, db *database.Database, fbAuth *auth.Client, h *render.Renderer) *Controller { +func New(ctx context.Context, config *config.ServerConfig, db *database.Database, firebaseAuth *auth.Client, h *render.Renderer) *Controller { logger := logging.FromContext(ctx).Named("admin") return &Controller{ - config: config, - db: db, - fbAuth: fbAuth, - h: h, - logger: logger, + config: config, + db: db, + firebaseAuth: firebaseAuth, + h: h, + logger: logger, } } diff --git a/pkg/controller/admin/users.go b/pkg/controller/admin/users.go index f5a39d57e..db7b6a052 100644 --- a/pkg/controller/admin/users.go +++ b/pkg/controller/admin/users.go @@ -98,7 +98,7 @@ func (c *Controller) HandleUsersCreate() http.Handler { return } - created, err := user.CreateFirebaseUser(ctx, c.fbAuth) + created, err := user.CreateFirebaseUser(ctx, c.firebaseAuth) if err != nil { flash.Alert("Failed to create user: %v", err) c.renderNewUser(ctx, w, user) diff --git a/pkg/controller/context.go b/pkg/controller/context.go index 9b8f18ddd..bb908498f 100644 --- a/pkg/controller/context.go +++ b/pkg/controller/context.go @@ -17,6 +17,7 @@ package controller import ( "context" + "firebase.google.com/go/auth" "github.com/google/exposure-notifications-verification-server/pkg/database" "github.com/gorilla/sessions" ) @@ -31,6 +32,7 @@ const ( contextKeySession = contextKey("session") contextKeyTemplate = contextKey("template") contextKeyUser = contextKey("user") + contextKeyFirebaseUser = contextKey("firebaseUser") ) // WithAuthorizedApp stores the authorized app on the context. @@ -150,3 +152,23 @@ func UserFromContext(ctx context.Context) *database.User { } return t } + +// WithFirebaseUser stores the current firebase user on the context. +func WithFirebaseUser(ctx context.Context, u *auth.UserRecord) context.Context { + return context.WithValue(ctx, contextKeyFirebaseUser, u) +} + +// FirebaseUserFromContext retrieves the firebase user from the context. If no value exists, it +// returns nil. +func FirebaseUserFromContext(ctx context.Context) *auth.UserRecord { + v := ctx.Value(contextKeyFirebaseUser) + if v == nil { + return nil + } + + t, ok := v.(*auth.UserRecord) + if !ok { + return nil + } + return t +} diff --git a/pkg/controller/login/reset_password.go b/pkg/controller/login/reset_password.go index 1b5fb2c55..f0c109a2f 100644 --- a/pkg/controller/login/reset_password.go +++ b/pkg/controller/login/reset_password.go @@ -32,9 +32,9 @@ func (c *Controller) HandleShowResetPassword() http.Handler { }) } -func (c *Controller) renderResetPassword(ctx context.Context, w http.ResponseWriter, f *flash.Flash) { +func (c *Controller) renderResetPassword(ctx context.Context, w http.ResponseWriter, flash *flash.Flash) { m := controller.TemplateMapFromContext(ctx) - m["flash"] = f + m["flash"] = flash c.h.RenderHTML(w, "login/reset-password", m) } @@ -45,27 +45,26 @@ func (c *Controller) HandleSubmitResetPassword() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - - // There's no session yet, so make a one-time flash. - f := flash.New(nil) + session := controller.SessionFromContext(ctx) + flash := flash.New(session.Values) var form FormData if err := controller.BindForm(w, r, &form); err != nil { - f.Error("Password failed. %v", err) - c.renderResetPassword(ctx, w, f) + flash.Error("Password reset failed. %v", err) + c.renderResetPassword(ctx, w, flash) return } if err := c.firebaseInternal.SendPasswordResetEmail(ctx, form.Email); err != nil { // Treat not-found like success so we don't leak details. if !errors.Is(err, firebase.ErrEmailNotFound) { - f.Error("Password reset failed.") - c.renderResetPassword(ctx, w, f) + flash.Error("Password reset failed.") + c.renderResetPassword(ctx, w, flash) return } } - f.Alert("Password reset email sent.") - c.renderResetPassword(ctx, w, f) + flash.Alert("Password reset email sent.") + c.renderResetPassword(ctx, w, flash) }) } diff --git a/pkg/controller/login/select_password.go b/pkg/controller/login/select_password.go index f86b5dfad..e63792013 100644 --- a/pkg/controller/login/select_password.go +++ b/pkg/controller/login/select_password.go @@ -16,9 +16,14 @@ package login import ( + "context" + "errors" + "fmt" "net/http" "time" + "unicode" + "github.com/google/exposure-notifications-verification-server/internal/firebase" "github.com/google/exposure-notifications-verification-server/pkg/controller" "github.com/google/exposure-notifications-verification-server/pkg/controller/flash" ) @@ -26,43 +31,125 @@ import ( func (c *Controller) HandleShowSelectNewPassword() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() + session := controller.SessionFromContext(ctx) + flash := flash.New(session.Values) - m := controller.TemplateMapFromContext(ctx) - m["firebase"] = c.config.Firebase - m["requirements"] = &c.config.PasswordRequirements - c.h.RenderHTML(w, "login/select-password", m) + code := r.FormValue("oobCode") + if code == "" { + flash.Error("No oobCode.") + c.renderShowSelectPassword(ctx, w, "", code, flash) + return + } + + email, err := c.firebaseInternal.VerifyPasswordResetCode(ctx, code) + if err != nil { + if errors.Is(err, firebase.ErrInvalidOOBCode) || errors.Is(err, firebase.ErrExpiredOOBCode) { + flash.Error("The action code is invalid. This can happen if the code is malformed, expired, or has already been used.") + } else { + flash.Error("Error checking code. %v", err) + } + c.renderShowSelectPassword(ctx, w, "", code, flash) + return + } + + c.renderShowSelectPassword(ctx, w, email, code, flash) }) } +func (c *Controller) renderShowSelectPassword(ctx context.Context, w http.ResponseWriter, email, code string, flash *flash.Flash) { + m := controller.TemplateMapFromContext(ctx) + m["email"] = email + m["code"] = code + m["flash"] = flash + m["requirements"] = &c.config.PasswordRequirements + c.h.RenderHTML(w, "login/select-password", m) +} + func (c *Controller) HandleSubmitNewPassword() http.Handler { logger := c.logger.Named("login.HandleSubmitNewPassword") type FormData struct { - Email string `form:"email"` + Password string `form:"password"` + Email string `form:"email"` } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() + session := controller.SessionFromContext(ctx) + flash := flash.New(session.Values) + + code := r.FormValue("oobCode") var form FormData if err := controller.BindForm(w, r, &form); err != nil { - logger.Errorw("failed to bind form", "error", err) - controller.InternalError(w, r, c.h, err) + flash.Error("Select password failed: %v", err) + c.renderShowSelectPassword(ctx, w, "", code, flash) + return + } + + if err := c.validateComplexity(form.Password); err != nil { + flash.Error("Select password failed: %v", err) + c.renderShowSelectPassword(ctx, w, form.Email, code, flash) + return + } + + if _, err := c.firebaseInternal.ChangePasswordWithCode(ctx, code, form.Password); err != nil { + if errors.Is(err, firebase.ErrInvalidOOBCode) || errors.Is(err, firebase.ErrExpiredOOBCode) { + flash.Error("The action code is invalid. This can happen if the code is malformed, expired, or has already been used.") + } else { + flash.Error("Select password failed. %v", err) + } + c.renderShowSelectPassword(ctx, w, form.Email, code, flash) return } if err := c.db.PasswordChanged(form.Email, time.Now()); err != nil { logger.Errorw("failed to mark password change time", "error", err) - controller.InternalError(w, r, c.h, err) + c.renderShowSelectPassword(ctx, w, form.Email, code, flash) return } - // There's no session yet, so make a one-time flash. - m := controller.TemplateMapFromContext(ctx) - f := flash.New(nil) - f.Alert("Successfully selected new password.") - m["flash"] = f - + flash.Alert("Successfully selected new password.") c.renderLogin(ctx, w) }) } + +func (c *Controller) validateComplexity(password string) error { + reqs := c.config.PasswordRequirements + if len(password) < reqs.Length { + return fmt.Errorf("password must be at least %d characters long", reqs.Length) + } + + upperCount := 0 + lowerCount := 0 + digitCount := 0 + specialCount := 0 + for _, c := range password { + if unicode.IsLetter(c) { + if unicode.IsUpper(c) { + upperCount++ + } else { + lowerCount++ + } + } else if unicode.IsDigit(c) { + digitCount++ + } else { + specialCount++ + } + } + + if upperCount < reqs.Uppercase { + return fmt.Errorf("password must contain at least %d uppercase characters", reqs.Uppercase) + } + if lowerCount < reqs.Lowercase { + return fmt.Errorf("password must contain at least %d lowercase characters", reqs.Lowercase) + } + if digitCount < reqs.Number { + return fmt.Errorf("password must contain at least %d digits", reqs.Number) + } + if specialCount < reqs.Special { + return fmt.Errorf("password must contain at least %d special characters", reqs.Number) + } + + return nil +} diff --git a/pkg/controller/middleware/auth.go b/pkg/controller/middleware/auth.go index cda8148f8..e8768bf4a 100644 --- a/pkg/controller/middleware/auth.go +++ b/pkg/controller/middleware/auth.go @@ -83,6 +83,14 @@ func RequireAuth(ctx context.Context, cacher cache.Cacher, fbClient *auth.Client controller.Unauthorized(w, r, h) return } + firebaseUser, err := fbClient.GetUserByEmail(ctx, email) + if err != nil { + logger.Debugw("firebase user does not exist") + controller.ClearSessionFirebaseCookie(session) + controller.Unauthorized(w, r, h) + return + } + ctx = controller.WithFirebaseUser(ctx, firebaseUser) // Load the user by using the cache to alleviate pressure on the database // layer. diff --git a/pkg/controller/middleware/emailverified.go b/pkg/controller/middleware/emailverified.go index f58eace9d..40b69d58f 100644 --- a/pkg/controller/middleware/emailverified.go +++ b/pkg/controller/middleware/emailverified.go @@ -58,20 +58,9 @@ func RequireVerified(ctx context.Context, client *auth.Client, db *database.Data return } - m := controller.TemplateMapFromContext(ctx) - - fbUser, err := client.GetUserByEmail(ctx, user.Email) - if err != nil { - delete(m, "currentUser") // Remove user from the template map. - logger.Debugw("firebase user does not exist") - flash.Error("That user does not exist.") - controller.ClearSessionFirebaseCookie(session) - controller.Unauthorized(w, r, h) - return - } - + firebaseUser := controller.FirebaseUserFromContext(ctx) realm := controller.RealmFromContext(ctx) - if NeedsEmailVerification(session, realm, fbUser) { + if needsEmailVerification(session, realm, firebaseUser) { logger.Debugw("user email not verified") http.Redirect(w, r, "/login/verify-email", http.StatusSeeOther) return @@ -82,14 +71,14 @@ func RequireVerified(ctx context.Context, client *auth.Client, db *database.Data } } -func NeedsEmailVerification(session *sessions.Session, realm *database.Realm, fbUser *auth.UserRecord) bool { +func needsEmailVerification(session *sessions.Session, realm *database.Realm, firebaseUser *auth.UserRecord) bool { if realm == nil || realm.EmailVerifiedMode == database.MFARequired { - return !fbUser.EmailVerified + return !firebaseUser.EmailVerified } if realm.EmailVerifiedMode == database.MFAOptionalPrompt && !controller.EmailVerificationPromptedFromSession(session) && - !fbUser.EmailVerified { + !firebaseUser.EmailVerified { return true } diff --git a/pkg/database/user.go b/pkg/database/user.go index 9bcd0c2c2..4b8652e1b 100644 --- a/pkg/database/user.go +++ b/pkg/database/user.go @@ -253,8 +253,8 @@ func (db *Database) TouchUserRevokeCheck(u *User) error { // user. It does nothing if the firebase user already exists. If the firebase // user does not exist, it generates a random password. The returned boolean // indicates if the user was created. -func (u *User) CreateFirebaseUser(ctx context.Context, fbAuth *auth.Client) (bool, error) { - if _, err := fbAuth.GetUserByEmail(ctx, u.Email); err != nil { +func (u *User) CreateFirebaseUser(ctx context.Context, firebaseAuth *auth.Client) (bool, error) { + if _, err := firebaseAuth.GetUserByEmail(ctx, u.Email); err != nil { if auth.IsInvalidEmail(err) { return false, fmt.Errorf("invalid email: %q", u.Email) } @@ -267,11 +267,9 @@ func (u *User) CreateFirebaseUser(ctx context.Context, fbAuth *auth.Client) (boo return false, fmt.Errorf("failed to generate password: %w", err) } - fbUser := &auth.UserToCreate{} - fbUser = fbUser.Email(u.Email) - fbUser = fbUser.Password(pwd) - fbUser = fbUser.DisplayName(u.Name) - if _, err := fbAuth.CreateUser(ctx, fbUser); err != nil { + firebaseUser := &auth.UserToCreate{} + firebaseUser.Email(u.Email).Password(pwd).DisplayName(u.Name) + if _, err := firebaseAuth.CreateUser(ctx, firebaseUser); err != nil { return false, fmt.Errorf("failed to create firebase user: %w", err) } return true, nil diff --git a/tools/seed/main.go b/tools/seed/main.go index 942070f3b..612545e26 100644 --- a/tools/seed/main.go +++ b/tools/seed/main.go @@ -80,7 +80,7 @@ func realMain(ctx context.Context) error { if err != nil { return fmt.Errorf("failed to setup firebase: %w", err) } - fbAuth, err := fb.Auth(ctx) + firebaseAuth, err := fb.Auth(ctx) if err != nil { return fmt.Errorf("failed to configure firebase: %w", err) } @@ -115,7 +115,7 @@ func realMain(ctx context.Context) error { logger.Infow("created user", "user", user) } - if err := createFirebaseUser(ctx, fbAuth, user); err != nil { + if err := createFirebaseUser(ctx, firebaseAuth, user); err != nil { return err } logger.Infow("enabled user", "user", user) @@ -139,7 +139,7 @@ func realMain(ctx context.Context) error { logger.Infow("created admin", "admin", admin) } - if err := createFirebaseUser(ctx, fbAuth, admin); err != nil { + if err := createFirebaseUser(ctx, firebaseAuth, admin); err != nil { return err } logger.Infow("enabled admin", "admin", admin) @@ -152,7 +152,7 @@ func realMain(ctx context.Context) error { logger.Infow("created super", "super", super) } - if err := createFirebaseUser(ctx, fbAuth, super); err != nil { + if err := createFirebaseUser(ctx, firebaseAuth, super); err != nil { return err } logger.Infow("enabled super", "super", super) @@ -180,8 +180,8 @@ func realMain(ctx context.Context) error { return nil } -func createFirebaseUser(ctx context.Context, fbAuth *firebaseauth.Client, user *database.User) error { - existing, err := fbAuth.GetUserByEmail(ctx, user.Email) +func createFirebaseUser(ctx context.Context, firebaseAuth *firebaseauth.Client, user *database.User) error { + existing, err := firebaseAuth.GetUserByEmail(ctx, user.Email) if err != nil && !firebaseauth.IsUserNotFound(err) { return fmt.Errorf("failed to get user by email %v: %w", user.Email, err) } @@ -196,7 +196,7 @@ func createFirebaseUser(ctx context.Context, fbAuth *firebaseauth.Client, user * update := (&firebaseauth.UserToUpdate{}). EmailVerified(true) - if _, err := fbAuth.UpdateUser(ctx, existing.UID, update); err != nil { + if _, err := firebaseAuth.UpdateUser(ctx, existing.UID, update); err != nil { return fmt.Errorf("failed to update user %v: %w", user.Email, err) } @@ -210,7 +210,7 @@ func createFirebaseUser(ctx context.Context, fbAuth *firebaseauth.Client, user * DisplayName(user.Name). Password("password") - if _, err := fbAuth.CreateUser(ctx, create); err != nil { + if _, err := firebaseAuth.CreateUser(ctx, create); err != nil { return fmt.Errorf("failed to create user %v: %w", user.Email, err) }