This repository has been archived by the owner on May 24, 2022. It is now read-only.
forked from harness/gitness
-
Notifications
You must be signed in to change notification settings - Fork 1
/
app.go
226 lines (184 loc) · 6.51 KB
/
app.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
package handler
import (
"crypto/rand"
"io"
"log"
"net/http"
"time"
"github.com/dchest/authcookie"
"github.com/dchest/passwordreset"
"github.com/drone/drone/pkg/database"
"github.com/drone/drone/pkg/mail"
. "github.com/drone/drone/pkg/model"
)
var (
// Secret key used to sign auth cookies,
// password reset tokens, etc.
secret = generateRandomKey(256)
)
// GenerateRandomKey creates a random key of size length bytes
func generateRandomKey(strength int) []byte {
k := make([]byte, strength)
if _, err := io.ReadFull(rand.Reader, k); err != nil {
return nil
}
return k
}
// Returns an HTML index.html page if the user is
// not currently authenticated, otherwise redirects
// the user to their personal dashboard screen
func Index(w http.ResponseWriter, r *http.Request) error {
// is the user already authenticated then
// redirect to the dashboard page
if _, err := r.Cookie("_sess"); err == nil {
http.Redirect(w, r, "/dashboard", http.StatusSeeOther)
return nil
}
// otherwise redirect to the login page
http.Redirect(w, r, "/login", http.StatusSeeOther)
return nil
}
// Return an HTML form for the User to login.
func Login(w http.ResponseWriter, r *http.Request) error {
var settings, _ = database.GetSettings()
data := struct {
Settings *Settings
}{settings}
return RenderTemplate(w, "login.html", &data)
}
// Terminate the User session.
func Logout(w http.ResponseWriter, r *http.Request) error {
DelCookie(w, r, "_sess")
http.Redirect(w, r, "/login", http.StatusSeeOther)
return nil
}
// Return an HTML form for the User to request a password reset.
func Forgot(w http.ResponseWriter, r *http.Request) error {
return RenderTemplate(w, "forgot.html", nil)
}
// Return an HTML form for the User to perform a password reset.
// This page must be visited from a Password Reset email that
// contains a hash to verify the User's identity.
func Reset(w http.ResponseWriter, r *http.Request) error {
return RenderTemplate(w, "reset.html", &struct{ Error string }{""})
}
// Return an HTML form for the User to signup.
func SignUp(w http.ResponseWriter, r *http.Request) error {
var settings, _ = database.GetSettings()
if settings == nil || !settings.OpenInvitations {
http.Redirect(w, r, "/login", http.StatusSeeOther)
return nil
}
return RenderTemplate(w, "signup.html", nil)
}
// Return an HTML form to register for a new account. This
// page must be visited from a Signup email that contains
// a hash to verify the Email address is correct.
func Register(w http.ResponseWriter, r *http.Request) error {
return RenderTemplate(w, "register.html", &struct{ Error string }{""})
}
func ForgotPost(w http.ResponseWriter, r *http.Request) error {
email := r.FormValue("email")
// attempt to retrieve the user by email address
user, err := database.GetUserEmail(email)
if err != nil {
log.Printf("could not find user %s to reset password. %s", email, err)
// if we can't find the email, we still display
// the template to the user. This prevents someone
// from trying to guess passwords through trial & error
return RenderTemplate(w, "forgot_sent.html", nil)
}
// hostname from settings
hostname := database.SettingsMust().URL().String()
// generate the password reset token
token := passwordreset.NewToken(user.Email, 12*time.Hour, []byte(user.Password), secret)
data := struct {
Host string
User *User
Token string
}{hostname, user, token}
// send the email message async
go func() {
if err := mail.SendPassword(email, data); err != nil {
log.Printf("error sending password reset email to %s. %s", email, err)
}
}()
// render the template indicating a success
return RenderTemplate(w, "forgot_sent.html", nil)
}
func ResetPost(w http.ResponseWriter, r *http.Request) error {
// verify the token and extract the username
token := r.FormValue("token")
email, err := passwordreset.VerifyToken(token, database.GetPassEmail, secret)
if err != nil {
return RenderTemplate(w, "reset.html", &struct{ Error string }{"Your password reset request is expired."})
}
// get the user from the database
user, err := database.GetUserEmail(email)
if err != nil {
return RenderTemplate(w, "reset.html", &struct{ Error string }{"Unable to locate user account."})
}
// get the new password
password := r.FormValue("password")
if err := user.SetPassword(password); err != nil {
return RenderTemplate(w, "reset.html", &struct{ Error string }{err.Error()})
}
// save to the database
if err := database.SaveUser(user); err != nil {
return RenderTemplate(w, "reset.html", &struct{ Error string }{"Unable to update password. Please try again"})
}
// add the user to the session object
SetCookie(w, r, "_sess", user.Email)
http.Redirect(w, r, "/dashboard", http.StatusSeeOther)
return nil
}
func SignUpPost(w http.ResponseWriter, r *http.Request) error {
// if self-registration is disabled we should display an
// error message to the user.
if !database.SettingsMust().OpenInvitations {
http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
return nil
}
// generate the password reset token
email := r.FormValue("email")
token := authcookie.New(email, time.Now().Add(12*time.Hour), secret)
// get the hostname from the database for use in the email
hostname := database.SettingsMust().URL().String()
// data used to generate the email template
data := struct {
Host string
Email string
Token string
}{hostname, email, token}
// send the email message async
go mail.SendActivation(email, data)
return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK)
}
func RegisterPost(w http.ResponseWriter, r *http.Request) error {
// verify the token and extract the username
token := r.FormValue("token")
email := authcookie.Login(token, secret)
if len(email) == 0 {
return RenderTemplate(w, "register.html", &struct{ Error string }{"Your registration email is expired."})
}
// set the email and name
user := NewUser(r.FormValue("name"), email)
// set the new password
password := r.FormValue("password")
if err := user.SetPassword(password); err != nil {
return RenderTemplate(w, "register.html", &struct{ Error string }{err.Error()})
}
// verify fields are correct
if err := user.Validate(); err != nil {
return RenderTemplate(w, "register.html", &struct{ Error string }{err.Error()})
}
// save to the database
if err := database.SaveUser(user); err != nil {
return err
}
// add the user to the session object
SetCookie(w, r, "_sess", user.Email)
// redirect the user to their dashboard
http.Redirect(w, r, "/dashboard", http.StatusSeeOther)
return nil
}