Mercurial > gemma
comparison controllers/pwreset.go @ 302:0777aa6de45b
Password reset. Part I
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Wed, 01 Aug 2018 12:29:55 +0200 |
parents | |
children | 69e291f26bbd |
comparison
equal
deleted
inserted
replaced
301:1781e5d7cb5a | 302:0777aa6de45b |
---|---|
1 package controllers | |
2 | |
3 import ( | |
4 "database/sql" | |
5 "encoding/hex" | |
6 "fmt" | |
7 "log" | |
8 "net/http" | |
9 "strings" | |
10 | |
11 "gemma.intevation.de/gemma/auth" | |
12 "gemma.intevation.de/gemma/config" | |
13 gomail "gopkg.in/gomail.v2" | |
14 ) | |
15 | |
16 const ( | |
17 userExistsSQL = `SELECT email_address | |
18 FROM users.list_users WHERE username = $1 | |
19 LIMIT 1` | |
20 ) | |
21 | |
22 const ( | |
23 mailTmpl = `You have requested a password change for your account on | |
24 %s://%s | |
25 | |
26 Please follow this link to get to the page where you can change your password. | |
27 | |
28 %s://%s/#/users/passwordreset/%s | |
29 | |
30 The link is only valid for one hour. | |
31 | |
32 Best regards | |
33 Your service team` | |
34 ) | |
35 | |
36 func messageBody(https bool, hash, serverName string) string { | |
37 | |
38 var proto string | |
39 | |
40 if https { | |
41 proto = "https" | |
42 } else { | |
43 proto = "http" | |
44 } | |
45 | |
46 return fmt.Sprintf(mailTmpl, | |
47 proto, serverName, | |
48 proto, serverName, | |
49 hash) | |
50 } | |
51 | |
52 const hashLength = 32 | |
53 | |
54 func generateHash() string { | |
55 return hex.EncodeToString(auth.GenerateRandomKey(hashLength)) | |
56 } | |
57 | |
58 func passwordReset( | |
59 input interface{}, | |
60 req *http.Request, | |
61 db *sql.DB, | |
62 ) (jr JSONResult, err error) { | |
63 | |
64 log.Println("passwordreset") | |
65 | |
66 user := input.(*PWResetUser) | |
67 | |
68 if user.User == "" { | |
69 err = JSONError{http.StatusBadRequest, "Invalid user name"} | |
70 return | |
71 } | |
72 | |
73 cfg := &config.Config | |
74 | |
75 if db, err = auth.OpenDB(cfg.ServiceUser, cfg.ServicePassword); err != nil { | |
76 return | |
77 } | |
78 defer db.Close() | |
79 | |
80 var email string | |
81 err = db.QueryRow(userExistsSQL, user.User).Scan(&email) | |
82 | |
83 switch { | |
84 case err == sql.ErrNoRows: | |
85 err = JSONError{http.StatusNotFound, "User does not exist."} | |
86 return | |
87 case err != nil: | |
88 return | |
89 } | |
90 | |
91 hash := generateHash() | |
92 | |
93 serverName := req.Host | |
94 useHTTPS := strings.ToLower(req.URL.Scheme) == "https" | |
95 | |
96 body := messageBody(useHTTPS, hash, serverName) | |
97 | |
98 m := gomail.NewMessage() | |
99 m.SetHeader("From", cfg.MailFrom) | |
100 m.SetHeader("To", email) | |
101 m.SetHeader("Subject", "Password Reset Link") | |
102 m.SetBody("text/plain", body) | |
103 | |
104 d := gomail.Dialer{ | |
105 Host: cfg.MailHost, | |
106 Port: int(cfg.MailPort), | |
107 Username: cfg.MailUser, | |
108 Password: cfg.MailPassword, | |
109 LocalName: cfg.MailHelo, | |
110 SSL: cfg.MailPort == 465, | |
111 } | |
112 | |
113 if err = d.DialAndSend(m); err != nil { | |
114 return | |
115 } | |
116 | |
117 // TODO: Keep hash/user for one hour or till resolved. | |
118 | |
119 jr.Result = &struct { | |
120 SendTo string `json:"send-to"` | |
121 }{ | |
122 SendTo: email, | |
123 } | |
124 return | |
125 } |