Skip to content

Commit

Permalink
Allow to resend the activation email (#4357)
Browse files Browse the repository at this point in the history
  • Loading branch information
nono committed Mar 25, 2024
2 parents 1bf90cc + 2e002fc commit 35bef8d
Show file tree
Hide file tree
Showing 14 changed files with 1,106 additions and 948 deletions.
14 changes: 14 additions & 0 deletions assets/locales/de.po
Original file line number Diff line number Diff line change
Expand Up @@ -981,3 +981,17 @@ msgstr "Continue"

msgid "Share by link Password Invalid"
msgstr "Invalid password"

msgid "Onboarding Resend activation mail"
msgstr "Send again the activation email"

msgid "Onboarding Resend activation Title"
msgstr "Check your emails!"

msgid "Onboarding Resend activation Body"
msgstr ""
"We just sent you an activation link by email."

msgid "Onboarding Resend activation Detail"
msgstr ""
"We prefer to warn you, this mail can be found in Spam, Notification or Social folders. Do not hesitate to take a look at these folders to find it."
14 changes: 14 additions & 0 deletions assets/locales/en.po
Original file line number Diff line number Diff line change
Expand Up @@ -1266,3 +1266,17 @@ msgstr "Continue"

msgid "Share by link Password Invalid"
msgstr "Invalid password"

msgid "Onboarding Resend activation mail"
msgstr "Send again the activation email"

msgid "Onboarding Resend activation Title"
msgstr "Check your emails!"

msgid "Onboarding Resend activation Body"
msgstr ""
"We just sent you an activation link by email."

msgid "Onboarding Resend activation Detail"
msgstr ""
"We prefer to warn you, this mail can be found in Spam, Notification or Social folders. Do not hesitate to take a look at these folders to find it."
14 changes: 14 additions & 0 deletions assets/locales/es.po
Original file line number Diff line number Diff line change
Expand Up @@ -992,3 +992,17 @@ msgstr "Continue"

msgid "Share by link Password Invalid"
msgstr "Invalid password"

msgid "Onboarding Resend activation mail"
msgstr "Send again the activation email"

msgid "Onboarding Resend activation Title"
msgstr "Check your emails!"

msgid "Onboarding Resend activation Body"
msgstr ""
"We just sent you an activation link by email."

msgid "Onboarding Resend activation Detail"
msgstr ""
"We prefer to warn you, this mail can be found in Spam, Notification or Social folders. Do not hesitate to take a look at these folders to find it."
16 changes: 16 additions & 0 deletions assets/locales/fr.po
Original file line number Diff line number Diff line change
Expand Up @@ -1382,3 +1382,19 @@ msgstr "Continuer"

msgid "Share by link Password Invalid"
msgstr "Mot de passe incorrect"

msgid "Onboarding Resend activation mail"
msgstr "Envoyer à nouveau l'email de finalisation d'inscription"

msgid "Onboarding Resend activation Title"
msgstr "Consultez vos e-mails !"

msgid "Onboarding Resend activation Body"
msgstr ""
"Nous vous avons envoyé par email un lien d'activation."

msgid "Onboarding Resend activation Detail"
msgstr ""
"Nous préférons vous prévenir : cet e-mail peut s'avérer un brin joueur et se"
" faufiler dans les dossiers Spam, Notifications ou Réseaux Sociaux. "
"N'hésitez donc pas à jeter un œil à tous vos dossiers pour le retrouver. "
14 changes: 14 additions & 0 deletions assets/locales/ja.po
Original file line number Diff line number Diff line change
Expand Up @@ -796,3 +796,17 @@ msgstr "Continue"

msgid "Share by link Password Invalid"
msgstr "Invalid password"

msgid "Onboarding Resend activation mail"
msgstr "Send again the activation email"

msgid "Onboarding Resend activation Title"
msgstr "Check your emails!"

msgid "Onboarding Resend activation Body"
msgstr ""
"We just sent you an activation link by email."

msgid "Onboarding Resend activation Detail"
msgstr ""
"We prefer to warn you, this mail can be found in Spam, Notification or Social folders. Do not hesitate to take a look at these folders to find it."
14 changes: 14 additions & 0 deletions assets/locales/nl_NL.po
Original file line number Diff line number Diff line change
Expand Up @@ -1177,3 +1177,17 @@ msgstr "Continue"

msgid "Share by link Password Invalid"
msgstr "Invalid password"

msgid "Onboarding Resend activation mail"
msgstr "Send again the activation email"

msgid "Onboarding Resend activation Title"
msgstr "Check your emails!"

msgid "Onboarding Resend activation Body"
msgstr ""
"We just sent you an activation link by email."

msgid "Onboarding Resend activation Detail"
msgstr ""
"We prefer to warn you, this mail can be found in Spam, Notification or Social folders. Do not hesitate to take a look at these folders to find it."
7 changes: 7 additions & 0 deletions assets/templates/need_onboarding.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ <h1 class="h4 h2-md mb-3 text-center">{{t "Onboarding Not activated Title"}}</h1
<p class="text-center mb-3">
<strong>{{t "Error Contact us" }} <a href="mailto:{{.SupportEmail}}">{{.SupportEmail}}</a>.</strong>
</p>
{{if .UUID}}
<form id="resend-activate-form" method="POST" action="/auth/onboarding/resend" class="d-contents">
<button class="btn btn-primary btn-md-lg w-100 my-3 mt-md-5" type="submit">
{{t "Onboarding Resend activation mail"}}
</button>
</form>
{{end}}
</footer>
</main>
<script src="{{asset .Domain "/scripts/cirrus.js"}}"></script>
Expand Down
9 changes: 9 additions & 0 deletions docs/auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,15 @@ POST /auth/hint HTTP/1.1
Host: cozy.example.org
```

### POST /auth/onboarding/resend

Resend the activation link by email to finalize the onboarding.

```http
POST /auth/onboarding/resend HTTP/1.1
Host: cozy.example.org
```

### POST /auth/passphrase_reset

After the user has clicked on the reset button of the passphrase reset form, it
Expand Down
8 changes: 8 additions & 0 deletions pkg/limits/rate_limiting.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ const (
// MagicLinkType is used when sending emails with a magic link that can
// authenticate the user into a Cozy
MagicLinkType
// ResendOnboardingMailType is used for resending the onboarding link by email
ResendOnboardingMailType
)

type counterConfig struct {
Expand Down Expand Up @@ -222,6 +224,12 @@ var configs = []counterConfig{
Limit: 30,
Period: 1 * time.Hour,
},
// ResendOnboardingMailType
{
Prefix: "resend-onboarding-mail",
Limit: 2,
Period: 1 * time.Hour,
},
}

// Counter is an interface for counting number of attempts that can be used to
Expand Down
16 changes: 16 additions & 0 deletions pkg/manager/client.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package manager is used for interacting with the cloudery.
package manager

import (
Expand Down Expand Up @@ -72,6 +73,21 @@ func (c *APIClient) Get(url string) (map[string]interface{}, error) {
return data, nil
}

// Post makes a POST request to the manager API
func (c *APIClient) Post(url string, body io.Reader) error {
res, err := c.Do(http.MethodPost, url, body)
if err != nil {
return err
}
if err := res.Body.Close(); err != nil {
return err
}
if res.StatusCode >= 400 {
return errors.New(res.Status)
}
return nil
}

// Put makes a PUT request to the manager API
func (c *APIClient) Put(url string, params map[string]interface{}) error {
body, err := json.Marshal(params)
Expand Down
40 changes: 32 additions & 8 deletions web/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
package auth

import (
"errors"
"fmt"
"net/http"
"net/url"
"strconv"
Expand Down Expand Up @@ -59,14 +61,7 @@ func Home(c echo.Context) error {

if len(instance.RegisterToken) > 0 && !instance.OnboardingFinished {
if !middlewares.CheckRegisterToken(c, instance) {
return c.Render(http.StatusOK, "need_onboarding.html", echo.Map{
"Domain": instance.ContextualDomain(),
"ContextName": instance.ContextName,
"Locale": instance.Locale,
"Title": instance.TemplateTitle(),
"Favicon": middlewares.Favicon(instance),
"SupportEmail": instance.SupportEmailAddress(),
})
return middlewares.RenderNeedOnboarding(c, instance)
}
return c.Redirect(http.StatusSeeOther, instance.PageURL("/auth/passphrase", c.QueryParams()))
}
Expand Down Expand Up @@ -575,6 +570,34 @@ func AppRedirection(inst *instance.Instance, redirect string) (*url.URL, error)
return u, nil
}

func resendActivationMail(c echo.Context) error {
inst := middlewares.GetInstance(c)
rate := config.GetRateLimiter()
if err := rate.CheckRateLimit(inst, limits.ResendOnboardingMailType); err == nil {
client := instance.APIManagerClient(inst)
if len(inst.RegisterToken) == 0 || inst.UUID == "" || client == nil {
return errors.New("cannot resend activation link")
}
url := fmt.Sprintf("/api/v1/instances/%s/resend", url.PathEscape(inst.UUID))
if err := client.Post(url, nil); err != nil {
return errors.New("cannot resend activation link")
}
}
return c.Render(http.StatusOK, "error.html", echo.Map{
"Domain": inst.ContextualDomain(),
"ContextName": inst.ContextName,
"Locale": inst.Locale,
"Title": inst.TemplateTitle(),
"Favicon": middlewares.Favicon(inst),
"Inverted": true,
"Illustration": "/images/mail-sent.svg",
"ErrorTitle": "Onboarding Resend activation Title",
"Error": "Onboarding Resend activation Body",
"ErrorDetail": "Onboarding Resend activation Detail",
"SupportEmail": inst.SupportEmailAddress(),
})
}

// Routes sets the routing for the status service
func Routes(router *echo.Group) {
noCSRF := middlewares.CSRFWithConfig(middlewares.CSRFConfig{
Expand Down Expand Up @@ -608,6 +631,7 @@ func Routes(router *echo.Group) {
router.POST("/passphrase_renew", passphraseRenew, noCSRF)
router.GET("/passphrase", passphraseForm, noCSRF)
router.POST("/hint", sendHint)
router.POST("/onboarding/resend", resendActivationMail)

// Confirmation by typing
router.GET("/confirm", confirmForm, noCSRF)
Expand Down
18 changes: 2 additions & 16 deletions web/auth/passphrase.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,7 @@ import (
func passphraseResetForm(c echo.Context) error {
instance := middlewares.GetInstance(c)
if !instance.OnboardingFinished {
return c.Render(http.StatusOK, "need_onboarding.html", echo.Map{
"Domain": instance.ContextualDomain(),
"ContextName": instance.ContextName,
"Locale": instance.Locale,
"Title": instance.TemplateTitle(),
"Favicon": middlewares.Favicon(instance),
"SupportEmail": instance.SupportEmailAddress(),
})
return middlewares.RenderNeedOnboarding(c, instance)
}

hasHint := false
Expand Down Expand Up @@ -75,14 +68,7 @@ func passphraseForm(c echo.Context) error {
}

if registerToken == "" || !middlewares.CheckRegisterToken(c, inst) {
return c.Render(http.StatusOK, "need_onboarding.html", echo.Map{
"Domain": inst.ContextualDomain(),
"ContextName": inst.ContextName,
"Locale": inst.Locale,
"Title": inst.TemplateTitle(),
"Favicon": middlewares.Favicon(inst),
"SupportEmail": inst.SupportEmailAddress(),
})
return middlewares.RenderNeedOnboarding(c, inst)
}

cryptoPolyfill := middlewares.CryptoPolyfill(c)
Expand Down
23 changes: 15 additions & 8 deletions web/middlewares/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,19 +183,26 @@ func CheckOnboardingNotFinished(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
i := GetInstance(c)
if !i.OnboardingFinished {
return c.Render(http.StatusOK, "need_onboarding.html", echo.Map{
"Domain": i.ContextualDomain(),
"ContextName": i.ContextName,
"Locale": i.Locale,
"Title": i.TemplateTitle(),
"Favicon": Favicon(i),
"SupportEmail": i.SupportEmailAddress(),
})
return RenderNeedOnboarding(c, i)
}
return next(c)
}
}

// RenderNeedOnboarding renders the page that tells the user that they have to
// confirm their email address and choose a password before using their Cozy.
func RenderNeedOnboarding(c echo.Context, inst *instance.Instance) error {
return c.Render(http.StatusOK, "need_onboarding.html", echo.Map{
"Domain": inst.ContextualDomain(),
"ContextName": inst.ContextName,
"Locale": inst.Locale,
"Title": inst.TemplateTitle(),
"Favicon": Favicon(inst),
"SupportEmail": inst.SupportEmailAddress(),
"UUID": inst.UUID,
})
}

// CheckTOSDeadlineExpired checks if there is not signed ToS and the deadline is
// exceeded
func CheckTOSDeadlineExpired(next echo.HandlerFunc) echo.HandlerFunc {
Expand Down
Loading

0 comments on commit 35bef8d

Please sign in to comment.