satellite/console/consoleweb: send email when account already exists
When a someone tries to create an account with an email that is already associated with a verified account, send them an email with options to sign in, create an account on another satellite, or reset password. Change-Id: I844144d88b7356bd7064c4840c9441347a5368b0
This commit is contained in:
parent
0eb2cc4511
commit
b4ea1bac42
@ -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 {
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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?"
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -243,7 +243,7 @@ export class AuthHttpApi implements UsersApi {
|
||||
* @returns id of created user
|
||||
* @throws Error
|
||||
*/
|
||||
public async register(user: Partial<User>, secret: string, captchaResponse: string): Promise<string> {
|
||||
public async register(user: Partial<User>, secret: string, captchaResponse: string): Promise<void> {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
549
web/satellite/static/emails/AccountAlreadyExists.html
Normal file
549
web/satellite/static/emails/AccountAlreadyExists.html
Normal file
@ -0,0 +1,549 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<!--[if IE]><html xmlns="http://www.w3.org/1999/xhtml" class="ie"><![endif]--><!--[if !IE]><!-->
|
||||
<html style="margin: 0;padding: 0;" xmlns="http://www.w3.org/1999/xhtml"><!--<![endif]--><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title></title>
|
||||
<!--[if !mso]><!--><meta http-equiv="X-UA-Compatible" content="IE=edge" /><!--<![endif]-->
|
||||
<meta name="viewport" content="width=device-width" /><style type="text/css">
|
||||
@media only screen and (min-width: 620px) {
|
||||
.wrapper {
|
||||
min-width: 600px !important
|
||||
}
|
||||
.wrapper h1 {}
|
||||
.wrapper h1 {
|
||||
font-size: 64px !important;
|
||||
line-height: 63px !important
|
||||
}
|
||||
.wrapper h2 {}
|
||||
.wrapper h2 {
|
||||
font-size: 30px !important;
|
||||
line-height: 38px !important
|
||||
}
|
||||
.wrapper h3 {}
|
||||
.wrapper h3 {
|
||||
font-size: 22px !important;
|
||||
line-height: 31px !important
|
||||
}
|
||||
.wrapper .size-10 {
|
||||
font-size: 10px !important;
|
||||
line-height: 18px !important
|
||||
}
|
||||
.wrapper .size-12 {
|
||||
font-size: 12px !important;
|
||||
line-height: 19px !important
|
||||
}
|
||||
.wrapper .size-16 {
|
||||
font-size: 16px !important;
|
||||
line-height: 24px !important
|
||||
}
|
||||
.wrapper .size-20 {
|
||||
font-size: 20px !important;
|
||||
line-height: 28px !important
|
||||
}
|
||||
.wrapper .size-40 {
|
||||
font-size: 40px !important;
|
||||
line-height: 47px !important
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style type="text/css">
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed;
|
||||
}
|
||||
* {
|
||||
line-height: inherit;
|
||||
}
|
||||
[x-apple-data-detectors],
|
||||
[href^="tel"],
|
||||
[href^="sms"] {
|
||||
color: inherit !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
.wrapper .footer__share-button a:hover,
|
||||
.wrapper .footer__share-button a:focus {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
.btn a:hover,
|
||||
.btn a:focus,
|
||||
.footer__share-button a:hover,
|
||||
.footer__share-button a:focus,
|
||||
.email-footer__links a:hover,
|
||||
.email-footer__links a:focus {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.layout,
|
||||
.column {
|
||||
transition: width 0.25s ease-in-out, max-width 0.25s ease-in-out;
|
||||
}
|
||||
.preheader td {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
.layout {
|
||||
max-width: 400px !important;
|
||||
-fallback-width: 95% !important;
|
||||
width: calc(100% - 20px) !important;
|
||||
}
|
||||
.column {
|
||||
max-width: 400px !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
.ie {
|
||||
width: 100%;
|
||||
}
|
||||
[owa] .column div,
|
||||
[owa] .column button {
|
||||
display: block !important;
|
||||
}
|
||||
.ie .column,
|
||||
[owa] .column,
|
||||
.ie {
|
||||
display: table-cell;
|
||||
float: none !important;
|
||||
vertical-align: top;
|
||||
}
|
||||
.ie .layout,
|
||||
[owa] .layout,
|
||||
.ie .one-col .column,
|
||||
[owa] .one-col .column {
|
||||
max-width: 600px !important;
|
||||
width: 600px !important;
|
||||
}
|
||||
.ie .two-col .column,
|
||||
[owa] .two-col .column {
|
||||
max-width: 300px !important;
|
||||
width: 300px !important;
|
||||
}
|
||||
.ie .three-col .column,
|
||||
[owa] .three-col .column {
|
||||
max-width: 200px !important;
|
||||
width: 200px !important;
|
||||
}
|
||||
.ie .two-col.has-gutter .column,
|
||||
[owa] .two-col.x_has-gutter .column {
|
||||
max-width: 290px !important;
|
||||
width: 290px !important;
|
||||
}
|
||||
.ie .three-col.has-gutter .column,
|
||||
[owa] .three-col.x_has-gutter .column {
|
||||
max-width: 188px !important;
|
||||
width: 188px !important;
|
||||
}
|
||||
.ie .has-gutter .wide,
|
||||
[owa] .has-gutter .wide {
|
||||
max-width: 394px !important;
|
||||
width: 394px !important;
|
||||
}
|
||||
.ie .two-col.has-gutter.has-border .column,
|
||||
[owa] .two-col.x_has-gutter.x_has-border .column {
|
||||
max-width: 292px !important;
|
||||
width: 292px !important;
|
||||
}
|
||||
.ie .three-col.has-gutter.has-border .column,
|
||||
[owa] .three-col.x_has-gutter.x_has-border .column,
|
||||
.ie .has-gutter.has-border .narrow,
|
||||
[owa] .has-gutter.x_has-border .narrow {
|
||||
max-width: 190px !important;
|
||||
width: 190px !important;
|
||||
}
|
||||
.ie .has-gutter.has-border .wide,
|
||||
[owa] .has-gutter.x_has-border .wide {
|
||||
max-width: 396px !important;
|
||||
width: 396px !important;
|
||||
}
|
||||
.ie .fixed-width .layout__inner {
|
||||
border-left: 0 none white !important;
|
||||
border-right: 0 none white !important;
|
||||
}
|
||||
.layout-fixed-width,
|
||||
.mso .layout-full-width {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
@media only screen and (min-width: 620px) {
|
||||
.column {
|
||||
display: table-cell;
|
||||
Float: none !important;
|
||||
vertical-align: top;
|
||||
}
|
||||
.layout,
|
||||
.one-col .column {
|
||||
max-width: 600px !important;
|
||||
width: 600px !important;
|
||||
}
|
||||
.two-col .column {
|
||||
max-width: 300px !important;
|
||||
width: 300px !important;
|
||||
}
|
||||
.three-col .column,
|
||||
.column.narrow {
|
||||
max-width: 200px !important;
|
||||
width: 200px !important;
|
||||
}
|
||||
.column.wide {
|
||||
width: 400px !important;
|
||||
}
|
||||
.two-col.has-gutter .column,
|
||||
.two-col.ecxhas-gutter .column {
|
||||
max-width: 290px !important;
|
||||
width: 290px !important;
|
||||
}
|
||||
.three-col.has-gutter .column,
|
||||
.three-col.ecxhas-gutter .column,
|
||||
.has-gutter .narrow {
|
||||
max-width: 188px !important;
|
||||
width: 188px !important;
|
||||
}
|
||||
.has-gutter .wide {
|
||||
max-width: 394px !important;
|
||||
width: 394px !important;
|
||||
}
|
||||
.two-col.has-gutter.has-border .column,
|
||||
.two-col.ecxhas-gutter.ecxhas-border .column {
|
||||
max-width: 292px !important;
|
||||
width: 292px !important;
|
||||
}
|
||||
.three-col.has-gutter.has-border .column,
|
||||
.three-col.ecxhas-gutter.ecxhas-border .column,
|
||||
.has-gutter.has-border .narrow,
|
||||
.has-gutter.ecxhas-border .narrow {
|
||||
max-width: 190px !important;
|
||||
width: 190px !important;
|
||||
}
|
||||
.has-gutter.has-border .wide,
|
||||
.has-gutter.ecxhas-border .wide {
|
||||
max-width: 396px !important;
|
||||
width: 396px !important;
|
||||
}
|
||||
}
|
||||
@media (max-width: 321px) {
|
||||
.fixed-width.has-border .layout__inner {
|
||||
border-width: 1px 0 !important;
|
||||
}
|
||||
.layout,
|
||||
.column {
|
||||
min-width: 320px !important;
|
||||
width: 320px !important;
|
||||
}
|
||||
}
|
||||
.mso div {
|
||||
border: 0 none white !important;
|
||||
}
|
||||
.mso .w560 .divider {
|
||||
Margin-left: 260px !important;
|
||||
Margin-right: 260px !important;
|
||||
}
|
||||
.mso .w360 .divider {
|
||||
Margin-left: 160px !important;
|
||||
Margin-right: 160px !important;
|
||||
}
|
||||
.mso .w260 .divider {
|
||||
Margin-left: 110px !important;
|
||||
Margin-right: 110px !important;
|
||||
}
|
||||
.mso .w160 .divider {
|
||||
Margin-left: 60px !important;
|
||||
Margin-right: 60px !important;
|
||||
}
|
||||
.mso .w354 .divider {
|
||||
Margin-left: 157px !important;
|
||||
Margin-right: 157px !important;
|
||||
}
|
||||
.mso .w250 .divider {
|
||||
Margin-left: 105px !important;
|
||||
Margin-right: 105px !important;
|
||||
}
|
||||
.mso .w148 .divider {
|
||||
Margin-left: 54px !important;
|
||||
Margin-right: 54px !important;
|
||||
}
|
||||
.mso .size-10,
|
||||
.ie .size-10 {
|
||||
font-size: 10px !important;
|
||||
line-height: 18px !important;
|
||||
}
|
||||
.mso .size-12,
|
||||
.ie .size-12 {
|
||||
font-size: 12px !important;
|
||||
line-height: 19px !important;
|
||||
}
|
||||
.mso .size-16,
|
||||
.ie .size-16 {
|
||||
font-size: 16px !important;
|
||||
line-height: 24px !important;
|
||||
}
|
||||
.mso .size-20,
|
||||
.ie .size-20 {
|
||||
font-size: 20px !important;
|
||||
line-height: 28px !important;
|
||||
}
|
||||
.mso .size-40,
|
||||
.ie .size-40 {
|
||||
font-size: 40px !important;
|
||||
line-height: 47px !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--[if !mso]><!-->
|
||||
<style type="text/css">
|
||||
@import url(https://fonts.googleapis.com/css?family=Montserrat:400,700,400italic);
|
||||
</style>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,700,400italic" rel="stylesheet" type="text/css" />
|
||||
<!--<![endif]-->
|
||||
<style type="text/css">
|
||||
body {
|
||||
background-color: #fff
|
||||
}
|
||||
|
||||
.logo a:hover,
|
||||
.logo a:focus {
|
||||
color: #859bb1 !important
|
||||
}
|
||||
|
||||
.mso h1,
|
||||
.ie h1 {}
|
||||
|
||||
.mso h1,
|
||||
.ie h1 {
|
||||
font-size: 64px !important;
|
||||
line-height: 63px !important
|
||||
}
|
||||
|
||||
.mso h2,
|
||||
.ie h2 {}
|
||||
|
||||
.mso h2,
|
||||
.ie h2 {
|
||||
font-size: 30px !important;
|
||||
line-height: 38px !important
|
||||
}
|
||||
|
||||
.mso h3,
|
||||
.ie h3 {}
|
||||
|
||||
.mso h3,
|
||||
.ie h3 {
|
||||
font-size: 22px !important;
|
||||
line-height: 31px !important
|
||||
}
|
||||
|
||||
.mso .footer__share-button p {}
|
||||
|
||||
.mso .footer__share-button p {
|
||||
font-family: sans-serif
|
||||
}
|
||||
</style>
|
||||
<meta name="robots" content="noindex,nofollow" />
|
||||
<meta property="og:title" content="My First Campaign" />
|
||||
</head>
|
||||
<!--[if mso]>
|
||||
<body class="mso">
|
||||
<![endif]-->
|
||||
<!--[if !mso]><!-->
|
||||
<body class="half-padding" style="margin: 0;padding: 0;-webkit-text-size-adjust: 100%;">
|
||||
<!--<![endif]-->
|
||||
<table class="wrapper" style="border-collapse: collapse;table-layout: fixed;min-width: 320px;width: 100%;background-color: #fff;" cellpadding="0" cellspacing="0" role="presentation">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div role="section">
|
||||
<div class="layout one-col fixed-width"
|
||||
style="margin: 0 auto;max-width: 600px;min-width: 320px; width: calc(28000% - 167400px);
|
||||
overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;">
|
||||
<div class="layout__inner"
|
||||
style="border-collapse: collapse;display: table;width: 100%;
|
||||
background-color: #fff;">
|
||||
<!--[if (mso)|(IE)]>
|
||||
<table align="center" cellpadding="0" cellspacing="0" role="presentation">
|
||||
<tr class="layout-fixed-width" style="background-color: #fff;">
|
||||
<td style="width: 600px" class="w560">
|
||||
<![endif]-->
|
||||
<div class="column"
|
||||
style="text-align: left;color: #8e959c;font-size: 14px;line-height: 21px;
|
||||
font-family: sans-serif;max-width: 600px;min-width: 320px;width: calc(28000% - 167400px);">
|
||||
<div style="margin: 12px 20px">
|
||||
<div style="mso-line-height-rule: exactly;mso-text-raise: 4px;">
|
||||
<h1 class="size-40"
|
||||
style="Margin-top: 0;Margin-bottom: 0;font-style: normal;font-weight: normal;
|
||||
color: #000;font-size: 32px;line-height: 40px;
|
||||
font-family: montserrat,dejavu sans,verdana,sans-serif;" lang="x-size-40">
|
||||
<span class="font-montserrat">
|
||||
<strong>Are you trying to sign in?</strong>
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--[if (mso)|(IE)]></td></tr></table><![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
<div style="mso-line-height-rule: exactly;line-height: 20px;font-size: 20px;"> </div>
|
||||
<div class="layout one-col fixed-width"
|
||||
style="Margin: 0 auto;max-width: 600px;min-width: 320px;width: calc(28000% - 167400px);
|
||||
overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;">
|
||||
<div class="layout__inner"
|
||||
style="border-collapse: collapse;display: table;width: 100%; background-color: #fff;">
|
||||
<!--[if (mso)|(IE)]>
|
||||
<table align="center" cellpadding="0" cellspacing="0" role="presentation">
|
||||
<tr class="layout-fixed-width" style="background-color: #fff;">
|
||||
<td style="width: 600px" class="w560">
|
||||
<![endif]-->
|
||||
<div class="column"
|
||||
style="text-align: left;color: #8e959c;font-size: 14px;line-height: 21px;
|
||||
font-family: sans-serif;max-width: 600px;min-width: 320px;width: calc(28000% - 167400px);">
|
||||
<div style="margin: 12px 20px">
|
||||
<div style="mso-line-height-rule: exactly;mso-text-raise: 4px;">
|
||||
<p class="size-20"
|
||||
style="Margin-top: 5px;Margin-bottom: 0;
|
||||
font-family: montserrat,dejavu sans,verdana,sans-serif;font-size: 17px;
|
||||
line-height: 26px;" lang="x-size-20">
|
||||
<span class="font-montserrat">There was an attempt to create an account with this
|
||||
email address on the {{ .SatelliteName }} Storj DCS satellite, but an account
|
||||
was previously created with this email. If this was you, try signing in to the
|
||||
existing account instead.
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--[if (mso)|(IE)]></td></tr></table><![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
<div style="mso-line-height-rule: exactly;line-height: 20px;font-size: 20px;"> </div>
|
||||
<div class="layout one-col fixed-width"
|
||||
style="Margin: 0 auto;max-width: 600px;min-width: 320px;width: calc(28000% - 167400px);
|
||||
overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;">
|
||||
<div class="layout__inner"
|
||||
style="border-collapse: collapse;display: table;width: 100%;background-color: #fff;">
|
||||
<!--[if (mso)|(IE)]>
|
||||
<table align="center" cellpadding="0" cellspacing="0" role="presentation">
|
||||
<tr class="layout-fixed-width" style="background-color: #fff;">
|
||||
<td style="width: 600px" class="w560">
|
||||
<![endif]-->
|
||||
<div class="column"
|
||||
style="text-align: left;color: #8e959c;font-size: 14px;line-height: 21px;
|
||||
font-family: sans-serif;max-width: 600px;min-width: 320px;width: calc(28000% - 167400px);">
|
||||
<div style="margin: 12px 20px">
|
||||
<div class="btn btn--flat btn--large" style="text-align:left;">
|
||||
<a style="border-radius: 8px;display: inline-block;font-size: 14px;font-weight: bold;
|
||||
line-height: 24px;padding: 12px 24px;text-align: center;
|
||||
text-decoration: none !important;transition: opacity 0.1s ease-in;
|
||||
color: #ffffff !important;background-color: #0149FF;
|
||||
font-family: Montserrat, DejaVu Sans, Verdana, sans-serif;"
|
||||
href="{{ .SignInLink }}">Sign In
|
||||
</a>
|
||||
<!--[if mso]>
|
||||
<p style="line-height:0;margin:0;"></p>
|
||||
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
href="{{ .SignInLink }}" style="width:191px" arcsize="9%" fillcolor="#2683FF"
|
||||
stroke="f">
|
||||
<v:textbox style="mso-fit-shape-to-text:t" inset="0px,11px,0px,11px">
|
||||
<center style="font-size:14px;line-height:24px;color:#FFFFFF;
|
||||
font-family:Montserrat,DejaVu Sans,Verdana,sans-serif;font-weight:bold;
|
||||
mso-line-height-rule:exactly;mso-text-raise:4px">Sign In
|
||||
</center>
|
||||
</v:textbox>
|
||||
</v:roundrect>
|
||||
<![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!--[if (mso)|(IE)]></td></tr></table><![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
<div style="mso-line-height-rule: exactly;line-height: 20px;font-size: 20px;"> </div>
|
||||
<div class="layout one-col fixed-width"
|
||||
style="Margin: 0 auto;max-width: 600px;min-width: 320px;width: calc(28000% - 167400px);
|
||||
overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;">
|
||||
<div class="layout__inner"
|
||||
style="border-collapse: collapse;display: table;width: 100%; background-color: #fff;">
|
||||
<!--[if (mso)|(IE)]>
|
||||
<table align="center" cellpadding="0" cellspacing="0" role="presentation">
|
||||
<tr class="layout-fixed-width" style="background-color: #fff;">
|
||||
<td style="width: 600px" class="w560">
|
||||
<![endif]-->
|
||||
<div class="column"
|
||||
style="text-align: left;color: #8e959c;font-size: 14px;line-height: 21px;
|
||||
font-family: sans-serif;max-width: 600px;min-width: 320px;width: calc(28000% - 167400px);">
|
||||
<div style="margin: 12px 20px">
|
||||
<div style="mso-line-height-rule: exactly;mso-text-raise: 4px;">
|
||||
<p class="size-20"
|
||||
style="Margin-top: 5px;Margin-bottom: 0;
|
||||
font-family: montserrat,dejavu sans,verdana,sans-serif;font-size: 17px;
|
||||
line-height: 26px;" lang="x-size-20">
|
||||
<span class="font-montserrat">If this wasn't you, we recommend <a href="{{ .ResetPasswordLink }}" target="_blank" rel="noopener noreferrer">resetting your password</a>.
|
||||
If this activity looks suspicious to you, notify our <a href="https://supportdcs.storj.io/hc/en-us" target="_blank" rel="noopener noreferrer">Support team</a>.
|
||||
<br/><br/>
|
||||
If your intention was to create an account on a different satellite, please select the appropriate satellite abbreviation from the drop down at
|
||||
the top right of the screen when <a href="{{ .CreateAccountLink }}" target="_blank" rel="noopener noreferrer">creating an account</a>.
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--[if (mso)|(IE)]></td></tr></table><![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
<div style="mso-line-height-rule: exactly;line-height: 20px;font-size: 20px;"> </div>
|
||||
<div class="layout one-col fixed-width"
|
||||
style="Margin: 0 auto;max-width: 600px;min-width: 320px;width: calc(28000% - 167400px);
|
||||
overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;">
|
||||
<div class="layout__inner"
|
||||
style="border-collapse: collapse;display: table;width: 100%;background-color: #fff;">
|
||||
<!--[if (mso)|(IE)]>
|
||||
<table align="center" cellpadding="0" cellspacing="0" role="presentation">
|
||||
<tr class="layout-fixed-width" style="background-color: #fff;">
|
||||
<td style="width: 600px" class="w560">
|
||||
<![endif]-->
|
||||
<div class="column"
|
||||
style="text-align: left;color: #8e959c;font-size: 14px;line-height: 21px;
|
||||
font-family: sans-serif;max-width: 600px;min-width: 320px; width: calc(28000% - 167400px);">
|
||||
<div style="Margin-left: 20px;Margin-right: 20px;Margin-top: 12px;">
|
||||
<div class="divider"
|
||||
style="display: block;font-size: 2px;line-height: 1px;Margin-left: auto;
|
||||
Margin-right: auto;width: 100%;background-color: #ccc;Margin-bottom: 20px;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--[if (mso)|(IE)]></td></tr></table><![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
<div style="mso-line-height-rule: exactly;line-height: 20px;font-size: 20px;"> </div>
|
||||
<div class="layout one-col fixed-width"
|
||||
style="Margin: 0 auto;max-width: 600px;min-width: 320px; width: calc(28000% - 167400px);
|
||||
overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;">
|
||||
<div class="layout__inner"
|
||||
style="border-collapse: collapse;display: table;width: 100%;background-color: #fff;">
|
||||
<!--[if (mso)|(IE)]>
|
||||
<table align="center" cellpadding="0" cellspacing="0" role="presentation">
|
||||
<tr class="layout-fixed-width" style="background-color: #fff;">
|
||||
<td style="width: 600px" class="w560">
|
||||
<![endif]-->
|
||||
<div class="column"
|
||||
style="text-align: left;color: #8e959c;font-size: 14px;line-height: 21px;
|
||||
font-family: sans-serif;max-width: 600px;min-width: 320px;width: calc(28000% - 167400px);">
|
||||
<div style="margin: 12px 20px">
|
||||
<div style="mso-line-height-rule: exactly;mso-text-raise: 4px;">
|
||||
<p class="size-12" style="Margin-top: 0;Margin-bottom: 0;font-family: montserrat,dejavu sans,verdana,sans-serif;font-size: 12px;line-height: 19px;" lang="x-size-12">
|
||||
<span class="font-montserrat">Please do not reply to this email.<br />
|
||||
1450 W. Peachtree St. NW #200, PMB 75268, Atlanta, GA 30309-2955, United States
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--[if (mso)|(IE)]></td></tr></table><![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user