diff --git a/satellite/console/consoleweb/consoleapi/auth.go b/satellite/console/consoleweb/consoleapi/auth.go index 684a741e9..ec24511a7 100644 --- a/satellite/console/consoleweb/consoleapi/auth.go +++ b/satellite/console/consoleweb/consoleapi/auth.go @@ -170,17 +170,6 @@ func (a *Auth) Register(w http.ResponseWriter, r *http.Request) { return } - var userID uuid.UUID - defer func() { - if err == nil { - w.Header().Set("Content-Type", "application/json") - err = json.NewEncoder(w).Encode(userID) - if err != nil { - a.log.Error("registration handler could not encode userID", zap.Error(ErrAuthAPI.Wrap(err))) - } - } - }() - var registerData struct { FullName string `json:"fullName"` ShortName string `json:"shortName"` @@ -226,31 +215,21 @@ func (a *Auth) Register(w http.ResponseWriter, r *http.Request) { } if verified != nil { - recoveryToken, err := a.service.GeneratePasswordRecoveryToken(ctx, verified.ID) - if err != nil { - a.serveJSONError(w, err) - return + satelliteAddress := a.ExternalAddress + if !strings.HasSuffix(satelliteAddress, "/") { + satelliteAddress += "/" } - - userName := verified.ShortName - if verified.ShortName == "" { - userName = verified.FullName - } - a.mailService.SendRenderedAsync( ctx, - []post.Address{{Address: verified.Email, Name: userName}}, - &consoleql.ForgotPasswordEmail{ - Origin: a.ExternalAddress, - UserName: userName, - ResetLink: a.PasswordRecoveryURL + "?token=" + recoveryToken, - CancelPasswordRecoveryLink: a.CancelPasswordRecoveryURL + "?token=" + recoveryToken, - LetUsKnowURL: a.LetUsKnowURL, - ContactInfoURL: a.ContactInfoURL, - TermsAndConditionsURL: a.TermsAndConditionsURL, + []post.Address{{Address: verified.Email}}, + &consoleql.AccountAlreadyExistsEmail{ + Origin: satelliteAddress, + SatelliteName: a.SatelliteName, + SignInLink: satelliteAddress + "login", + ResetPasswordLink: satelliteAddress + "forgot-password", + CreateAccountLink: satelliteAddress + "signup", }, ) - userID = verified.ID return } @@ -334,7 +313,6 @@ func (a *Auth) Register(w http.ResponseWriter, r *http.Request) { } a.analytics.TrackCreateUser(trackCreateUserFields) } - userID = user.ID token, err := a.service.GenerateActivationToken(ctx, user.ID, user.Email) if err != nil { diff --git a/satellite/console/consoleweb/consoleapi/auth_test.go b/satellite/console/consoleweb/consoleapi/auth_test.go index 21e79d529..0225c7aa3 100644 --- a/satellite/console/consoleweb/consoleapi/auth_test.go +++ b/satellite/console/consoleweb/consoleapi/auth_test.go @@ -26,7 +26,6 @@ import ( "go.uber.org/zap" "storj.io/common/testcontext" - "storj.io/common/uuid" "storj.io/storj/private/post" "storj.io/storj/private/testplanet" "storj.io/storj/satellite" @@ -97,16 +96,9 @@ func TestAuth_Register(t *testing.T) { }() require.Equal(t, http.StatusOK, result.StatusCode) - body, err := ioutil.ReadAll(result.Body) + _, users, err := planet.Satellites[0].API.Console.Service.GetUserByEmailWithUnverified(ctx, registerData.Email) require.NoError(t, err) - - var userID uuid.UUID - err = json.Unmarshal(body, &userID) - require.NoError(t, err) - - user, err := planet.Satellites[0].API.Console.Service.GetUser(ctx, userID) - require.NoError(t, err) - require.Equal(t, []byte(test.Partner), user.UserAgent) + require.Equal(t, []byte(test.Partner), users[0].UserAgent) }() } }) @@ -122,8 +114,9 @@ func TestAuth_Register_CORS(t *testing.T) { }, }, }, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) { - jsonBody := []byte(`{"email":"user@test.com","fullName":"testuser","password":"abc123","shortName":"test"}`) - + email := "user@test.com" + fullName := "testuser" + jsonBody := []byte(fmt.Sprintf(`{"email":"%s","fullName":"%s","password":"abc123","shortName":"test"}`, email, fullName)) url := planet.Satellites[0].ConsoleURL() + "/api/v0/auth/register" req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBuffer(jsonBody)) require.NoError(t, err) @@ -198,15 +191,9 @@ func TestAuth_Register_CORS(t *testing.T) { "Authorization", }) - body, err := ioutil.ReadAll(resp.Body) - require.NoError(t, err) - - var userID uuid.UUID - err = json.Unmarshal(body, &userID) - require.NoError(t, err) - - _, err = planet.Satellites[0].API.Console.Service.GetUser(ctx, userID) + _, users, err := planet.Satellites[0].API.Console.Service.GetUserByEmailWithUnverified(ctx, email) require.NoError(t, err) + require.Equal(t, fullName, users[0].FullName) }) } @@ -647,16 +634,16 @@ func TestRegistrationEmail(t *testing.T) { SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 0, }, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) { sat := planet.Satellites[0] - + email := "test@mail.test" jsonBody, err := json.Marshal(map[string]interface{}{ "fullName": "Test User", "shortName": "Test", - "email": "test@mail.test", + "email": email, "password": "123a123", }) require.NoError(t, err) - register := func() string { + register := func() { url := planet.Satellites[0].ConsoleURL() + "/api/v0/auth/register" req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBuffer(jsonBody)) require.NoError(t, err) @@ -665,46 +652,39 @@ func TestRegistrationEmail(t *testing.T) { result, err := http.DefaultClient.Do(req) require.NoError(t, err) require.Equal(t, http.StatusOK, result.StatusCode) - - var userID string - require.NoError(t, json.NewDecoder(result.Body).Decode(&userID)) require.NoError(t, result.Body.Close()) - - return userID } sender := &EmailVerifier{Context: ctx} sat.API.Mail.Service.Sender = sender // Registration attempts using new e-mail address should send activation e-mail. - userID := register() + register() body, err := sender.Data.Get(ctx) require.NoError(t, err) require.Contains(t, body, "/activation") // Registration attempts using existing but unverified e-mail address should send activation e-mail. - newUserID := register() - require.Equal(t, userID, newUserID) + register() body, err = sender.Data.Get(ctx) require.NoError(t, err) require.Contains(t, body, "/activation") - // Registration attempts using existing and verified e-mail address should send password reset e-mail. - userUUID, err := uuid.FromString(userID) - require.NoError(t, err) - user, err := sat.DB.Console().Users().Get(ctx, userUUID) + // Registration attempts using existing and verified e-mail address should send account already exists e-mail. + _, users, err := sat.DB.Console().Users().GetByEmailWithUnverified(ctx, email) require.NoError(t, err) - user.Status = console.Active - require.NoError(t, sat.DB.Console().Users().Update(ctx, user.ID, console.UpdateUserRequest{ - Status: &user.Status, + users[0].Status = console.Active + require.NoError(t, sat.DB.Console().Users().Update(ctx, users[0].ID, console.UpdateUserRequest{ + Status: &users[0].Status, })) - newUserID = register() - require.Equal(t, userID, newUserID) + register() body, err = sender.Data.Get(ctx) require.NoError(t, err) - require.Contains(t, body, "/password-recovery") + require.Contains(t, body, "/login") + require.Contains(t, body, "/forgot-password") + require.Contains(t, body, "/signup") }) } @@ -760,7 +740,7 @@ func TestAuth_Register_NameSpecialChars(t *testing.T) { }, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) { inputName := "The website has been changed to https://evil.com/login.html - Enter Login Details," filteredName := "The website has been changed to https---evil-com-login-html - Enter Login Details," - + email := "user@mail.test" registerData := struct { FullName string `json:"fullName"` ShortName string `json:"shortName"` @@ -769,7 +749,7 @@ func TestAuth_Register_NameSpecialChars(t *testing.T) { }{ FullName: inputName, ShortName: inputName, - Email: "user@mail.test", + Email: email, Password: "abc123", } @@ -788,17 +768,10 @@ func TestAuth_Register_NameSpecialChars(t *testing.T) { }() require.Equal(t, http.StatusOK, result.StatusCode) - body, err := ioutil.ReadAll(result.Body) + _, users, err := planet.Satellites[0].API.Console.Service.GetUserByEmailWithUnverified(ctx, email) require.NoError(t, err) - - var userID uuid.UUID - err = json.Unmarshal(body, &userID) - require.NoError(t, err) - - user, err := planet.Satellites[0].API.Console.Service.GetUser(ctx, userID) - require.NoError(t, err) - require.Equal(t, filteredName, user.FullName) - require.Equal(t, filteredName, user.ShortName) + require.Equal(t, filteredName, users[0].FullName) + require.Equal(t, filteredName, users[0].ShortName) }) } diff --git a/satellite/console/consoleweb/consoleql/mail.go b/satellite/console/consoleweb/consoleql/mail.go index 16d12515f..d1658e3fe 100644 --- a/satellite/console/consoleweb/consoleql/mail.go +++ b/satellite/console/consoleweb/consoleql/mail.go @@ -88,3 +88,20 @@ func (*UnknownResetPasswordEmail) Template() string { return "UnknownReset" } func (*UnknownResetPasswordEmail) Subject() string { return "You have requested to reset your password, but..." } + +// AccountAlreadyExistsEmail is mailservice template for email where user tries to create account, but one already exists. +type AccountAlreadyExistsEmail struct { + Origin string + SatelliteName string + SignInLink string + ResetPasswordLink string + CreateAccountLink string +} + +// Template returns email template name. +func (*AccountAlreadyExistsEmail) Template() string { return "AccountAlreadyExists" } + +// Subject gets email subject. +func (*AccountAlreadyExistsEmail) Subject() string { + return "Are you trying to sign in?" +} diff --git a/satellite/console/consoleweb/endpoints_test.go b/satellite/console/consoleweb/endpoints_test.go index 5e201fc2c..dd54af6f8 100644 --- a/satellite/console/consoleweb/endpoints_test.go +++ b/satellite/console/consoleweb/endpoints_test.go @@ -872,7 +872,6 @@ func (test *test) registerUser(email, password string) registeredUser { })) require.Equal(test.t, http.StatusOK, resp.StatusCode) - require.NotEmpty(test.t, body) time.Sleep(time.Second) // TODO: hack-fix, register activates account asynchronously diff --git a/web/satellite/src/api/auth.ts b/web/satellite/src/api/auth.ts index 616825644..83f00210f 100644 --- a/web/satellite/src/api/auth.ts +++ b/web/satellite/src/api/auth.ts @@ -243,7 +243,7 @@ export class AuthHttpApi implements UsersApi { * @returns id of created user * @throws Error */ - public async register(user: Partial, secret: string, captchaResponse: string): Promise { + public async register(user: Partial, secret: string, captchaResponse: string): Promise { const path = `${this.ROOT_PATH}/register`; const body = { secret: secret, @@ -263,8 +263,8 @@ export class AuthHttpApi implements UsersApi { }; const response = await this.http.post(path, JSON.stringify(body)); - const result = await response.json(); if (!response.ok) { + const result = await response.json(); const errMsg = result.error || 'Cannot register user'; switch (response.status) { case 400: @@ -277,7 +277,6 @@ export class AuthHttpApi implements UsersApi { throw new Error(errMsg); } } - return result; } /** diff --git a/web/satellite/static/emails/AccountAlreadyExists.html b/web/satellite/static/emails/AccountAlreadyExists.html new file mode 100644 index 000000000..f9309a1b3 --- /dev/null +++ b/web/satellite/static/emails/AccountAlreadyExists.html @@ -0,0 +1,549 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +