[server]: add one click verify button for verification email (#5654)
OG (ott.html): <img width="701" height="590" alt="image" src="https://github.com/user-attachments/assets/80b926d1-c65f-44a8-9de4-7b591258bf3c" /> New (ott_mobile.html): <img width="642" height="811" alt="image" src="https://github.com/user-attachments/assets/aa18a778-1161-4b4e-ad82-cf472da06ff7" />
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
package ente
|
||||
|
||||
const (
|
||||
OTTTemplate = "ott.html"
|
||||
OTTTemplate = "ott.html"
|
||||
OTTMobileTemplate = "ott_mobile.html"
|
||||
|
||||
ChangeEmailOTTTemplate = "ott_change_email.html"
|
||||
EmailChangedTemplate = "email_changed.html"
|
||||
@@ -31,6 +32,8 @@ type SendOTTRequest struct {
|
||||
Email string `json:"email"`
|
||||
Client string `json:"client"`
|
||||
Purpose string `json:"purpose"`
|
||||
// Mobile indicates whether the request is coming from a mobile client`
|
||||
Mobile bool `json:"mobile"`
|
||||
}
|
||||
|
||||
// EmailVerificationRequest represents an email verification request
|
||||
|
||||
226
server/mail-templates/ott_mobile.html
Normal file
226
server/mail-templates/ott_mobile.html
Normal file
@@ -0,0 +1,226 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta content="text/html; charset=utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, minimum-scale=1"
|
||||
/>
|
||||
<style>
|
||||
body {
|
||||
background-color: #f0f1f3;
|
||||
font-family: "Helvetica Neue", "Segoe UI", Helvetica, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 27px;
|
||||
margin: 0;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #f4f4f4f4;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
table td {
|
||||
border-color: #ddd;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
background-color: #fff;
|
||||
padding: 30px;
|
||||
max-width: auto;
|
||||
margin: 0 auto;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.button {
|
||||
background: #0055d4;
|
||||
border-radius: 3px;
|
||||
text-decoration: none !important;
|
||||
color: #fff !important;
|
||||
font-weight: bold;
|
||||
padding: 10px 30px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background: #111;
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.footer a {
|
||||
color: #888;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.gutter {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0055d4;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #111;
|
||||
}
|
||||
|
||||
.footer-icons {
|
||||
padding: 4px !important;
|
||||
width: 24px !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<div class="gutter" style="padding: 4px"> </div>
|
||||
<div
|
||||
class="wrap"
|
||||
style="
|
||||
background-color: rgb(255, 255, 255);
|
||||
padding: 30px;
|
||||
max-width: 525px;
|
||||
margin: 0 auto;
|
||||
border-radius: 5px;
|
||||
font-size: 16px;
|
||||
"
|
||||
>
|
||||
<h2 style="text-align: center; margin-bottom: 16px">
|
||||
Verify your email address
|
||||
</h2>
|
||||
<hr style="margin: 32px 0; border: none; border-top: 1px solid #ddd" />
|
||||
<div>
|
||||
<p style="text-align: center">
|
||||
Click on the button to verify your email.
|
||||
</p>
|
||||
<center style="margin: 24px 0">
|
||||
<a
|
||||
href="https://verify.ente.io/?ott={{.VerificationCode}}"
|
||||
style="
|
||||
background-color: #00b33c;
|
||||
border-radius: 3px;
|
||||
text-decoration: none !important;
|
||||
color: #fff !important;
|
||||
font-weight: bold;
|
||||
padding: 8px 30px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
"
|
||||
target="_blank"
|
||||
>
|
||||
Verify email
|
||||
</a>
|
||||
</center>
|
||||
<div
|
||||
style="
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-top: 32px;
|
||||
margin-bottom: 32px;
|
||||
"
|
||||
>
|
||||
<p> or enter the code manually </p>
|
||||
<center>
|
||||
<div
|
||||
style="
|
||||
background-color: #f6f6f6;
|
||||
border-radius: 6px;
|
||||
color: #787878;
|
||||
display: inline-block;
|
||||
letter-spacing: 3px;
|
||||
padding: 8px 14px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
"
|
||||
target="_blank"
|
||||
>
|
||||
{{.VerificationCode}}
|
||||
</div>
|
||||
</center>
|
||||
</div>
|
||||
</div>
|
||||
<hr
|
||||
style="
|
||||
margin-top: 32px;
|
||||
margin-bottom: 32px;
|
||||
border: none;
|
||||
border-top: 1px solid #ddd;
|
||||
"
|
||||
/>
|
||||
<p style="text-align: center; font-size: 14px; color: #666">
|
||||
If you need help, just hit the reply button!
|
||||
</p>
|
||||
</div>
|
||||
<br />
|
||||
<div
|
||||
class="footer"
|
||||
style="text-align: center; font-size: 12px; color: rgb(136, 136, 136)"
|
||||
>
|
||||
<div>
|
||||
<a href="https://ente.io" target="_blank"
|
||||
><img
|
||||
src="https://email-assets.ente.io/ente-green.png"
|
||||
style="width: 100px; padding: 24px"
|
||||
title="Ente"
|
||||
alt="Ente"
|
||||
/></a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://fosstodon.org/@ente" target="_blank"
|
||||
><img
|
||||
src="https://email-assets.ente.io/mastodon-icon.png"
|
||||
class="footer-icons"
|
||||
style="width: 24px; padding: 4px"
|
||||
title="Mastodon"
|
||||
alt="Mastodon"
|
||||
/></a>
|
||||
<a href="https://twitter.com/enteio" target="_blank"
|
||||
><img
|
||||
src="https://email-assets.ente.io/twitter-icon.png"
|
||||
class="footer-icons"
|
||||
style="width: 24px; padding: 4px"
|
||||
title="Twitter"
|
||||
alt="Twitter"
|
||||
/></a>
|
||||
<a href="https://discord.ente.io" target="_blank"
|
||||
><img
|
||||
src="https://email-assets.ente.io/discord-icon.png"
|
||||
class="footer-icons"
|
||||
style="width: 24px; padding: 4px"
|
||||
title="Discord"
|
||||
alt="Discord"
|
||||
/></a>
|
||||
<a href="https://github.com/ente-io" target="_blank"
|
||||
><img
|
||||
src="https://email-assets.ente.io/github-icon.png"
|
||||
class="footer-icons"
|
||||
style="width: 24px; padding: 4px"
|
||||
title="GitHub"
|
||||
alt="GitHub"
|
||||
/></a>
|
||||
</div>
|
||||
<p>
|
||||
Ente Technologies, Inc.
|
||||
<br />
|
||||
1111B S Governors Ave 6032 Dover, DE 19904
|
||||
</p>
|
||||
<br />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -40,7 +40,7 @@ func (h *UserHandler) SendOTT(c *gin.Context) {
|
||||
handler.Error(c, stacktrace.Propagate(ente.ErrBadRequest, "Email id is missing"))
|
||||
return
|
||||
}
|
||||
err := h.UserController.SendEmailOTT(c, email, request.Purpose)
|
||||
err := h.UserController.SendEmailOTT(c, email, request.Purpose, request.Mobile)
|
||||
if err != nil {
|
||||
handler.Error(c, stacktrace.Propagate(err, ""))
|
||||
return
|
||||
|
||||
@@ -82,7 +82,7 @@ func hardcodedOTTForEmail(hardCodedOTT HardCodedOTT, email string) string {
|
||||
}
|
||||
|
||||
// SendEmailOTT generates and sends an OTT to the provided email address
|
||||
func (c *UserController) SendEmailOTT(context *gin.Context, email string, purpose string) error {
|
||||
func (c *UserController) SendEmailOTT(context *gin.Context, email string, purpose string, mobile bool) error {
|
||||
if err := c.validateSendOTT(context, email, purpose); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -105,7 +105,8 @@ func (c *UserController) SendEmailOTT(context *gin.Context, email string, purpos
|
||||
return stacktrace.Propagate(err, "")
|
||||
}
|
||||
// check if user has already requested for more than 10 codes in last 10mins
|
||||
otts, _ := c.UserAuthRepo.GetValidOTTs(emailHash, auth.GetApp(context))
|
||||
app := auth.GetApp(context)
|
||||
otts, _ := c.UserAuthRepo.GetValidOTTs(emailHash, app)
|
||||
if len(otts) >= OTTActiveCodeLimit {
|
||||
msg := "Too many ott requests in a short duration"
|
||||
go c.DiscordController.NotifyPotentialAbuse(msg)
|
||||
@@ -119,7 +120,7 @@ func (c *UserController) SendEmailOTT(context *gin.Context, email string, purpos
|
||||
return stacktrace.Propagate(err, "")
|
||||
}
|
||||
log.Info("Added ott for " + emailHash + ": " + ott)
|
||||
err = emailOTT(email, ott, purpose)
|
||||
err = emailOTT(app, email, ott, purpose, mobile)
|
||||
if err != nil {
|
||||
return stacktrace.Propagate(err, "")
|
||||
}
|
||||
@@ -383,12 +384,16 @@ func (c *UserController) TerminateSession(userID int64, token string) error {
|
||||
return stacktrace.Propagate(c.UserAuthRepo.RemoveToken(userID, token), "")
|
||||
}
|
||||
|
||||
func emailOTT(to string, ott string, purpose string) error {
|
||||
func emailOTT(app ente.App, to string, ott string, purpose string, mobile bool) error {
|
||||
var templateName string
|
||||
if purpose == ente.ChangeEmailOTTPurpose {
|
||||
templateName = ente.ChangeEmailOTTTemplate
|
||||
} else {
|
||||
templateName = ente.OTTTemplate
|
||||
if mobile && app == ente.Photos {
|
||||
templateName = ente.OTTMobileTemplate
|
||||
} else {
|
||||
templateName = ente.OTTTemplate
|
||||
}
|
||||
}
|
||||
subject := fmt.Sprintf("Verification code: %s", ott)
|
||||
err := emailUtil.SendTemplatedEmail([]string{to}, "Ente", "verify@ente.io",
|
||||
|
||||
Reference in New Issue
Block a user