(app *App, alias, redirectTo string)
| 1404 | } |
| 1405 | |
| 1406 | func loginViaEmail(app *App, alias, redirectTo string) error { |
| 1407 | if !app.cfg.Email.Enabled() { |
| 1408 | return fmt.Errorf("EMAIL ISN'T CONFIGURED on this server") |
| 1409 | } |
| 1410 | |
| 1411 | // Make sure user has added an email |
| 1412 | // TODO: create a new func to just get user's email; "ForAuth" doesn't match here |
| 1413 | u, _ := app.db.GetUserForAuth(alias) |
| 1414 | if u == nil { |
| 1415 | if strings.IndexAny(alias, "@") > 0 { |
| 1416 | return ErrUserNotFoundEmail |
| 1417 | } |
| 1418 | return ErrUserNotFound |
| 1419 | } |
| 1420 | if u.Email.String == "" { |
| 1421 | return impart.HTTPError{http.StatusPreconditionFailed, "User doesn't have an email address. Log in with password, instead."} |
| 1422 | } |
| 1423 | |
| 1424 | // Generate one-time login token |
| 1425 | t, err := app.db.GetTemporaryOneTimeAccessToken(u.ID, 60*15, true) |
| 1426 | if err != nil { |
| 1427 | log.Error("Unable to generate token for email login: %s", err) |
| 1428 | return impart.HTTPError{http.StatusInternalServerError, "Unable to generate token."} |
| 1429 | } |
| 1430 | |
| 1431 | // Send email |
| 1432 | mlr, err := mailer.New(app.cfg.Email) |
| 1433 | if err != nil { |
| 1434 | return err |
| 1435 | } |
| 1436 | toEmail := u.EmailClear(app.keys) |
| 1437 | footerPara := "This link will only work once and expires in 15 minutes. Didn't ask us to log in? You can safely ignore this email." |
| 1438 | |
| 1439 | plainMsg := fmt.Sprintf("Log in to %s here: %s/login?to=%s&with=%s\n\n%s", app.cfg.App.SiteName, app.cfg.App.Host, redirectTo, t, footerPara) |
| 1440 | m, err := mlr.NewMessage(app.cfg.App.SiteName+" <noreply-login@"+app.cfg.Email.Domain+">", "Log in to "+app.cfg.App.SiteName, plainMsg, fmt.Sprintf("<%s>", toEmail)) |
| 1441 | if err != nil { |
| 1442 | return err |
| 1443 | } |
| 1444 | m.AddTag("Email Login") |
| 1445 | |
| 1446 | m.SetHTML(fmt.Sprintf(`<html> |
| 1447 | <body style="font-family:Lora, 'Palatino Linotype', Palatino, Baskerville, 'Book Antiqua', 'New York', 'DejaVu serif', serif; font-size: 100%%; margin:1em 2em;"> |
| 1448 | <div style="margin:0 auto; max-width: 40em; font-size: 1.2em;"> |
| 1449 | <h1 style="font-size:1.75em"><a style="text-decoration:none;color:#000;" href="%s">%s</a></h1> |
| 1450 | <p style="font-size:1.2em;margin-bottom:1.5em;text-align:center"><a href="%s/login?to=%s&with=%s">Log in to %s here</a>.</p> |
| 1451 | <p style="font-size: 0.86em;color:#666;text-align:center;max-width:35em;margin:1em auto">%s</p> |
| 1452 | </div> |
| 1453 | </body> |
| 1454 | </html>`, app.cfg.App.Host, app.cfg.App.SiteName, app.cfg.App.Host, redirectTo, t, app.cfg.App.SiteName, footerPara)) |
| 1455 | return mlr.Send(m) |
| 1456 | } |
| 1457 | |
| 1458 | func saveTempInfo(app *App, key, val string, r *http.Request, w http.ResponseWriter) error { |
| 1459 | session, err := app.sessionStore.Get(r, "t") |
no test coverage detected