aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--charakterin.go179
-rw-r--r--user.go13
2 files changed, 157 insertions, 35 deletions
diff --git a/charakterin.go b/charakterin.go
index abf9627..142484c 100644
--- a/charakterin.go
+++ b/charakterin.go
@@ -12,10 +12,19 @@ import (
12 _ "github.com/lib/pq" 12 _ "github.com/lib/pq"
13) 13)
14 14
15const (
16 NoSuchUser = "pq: no_such_user"
17 InvalidPassword = "pq: invalid_password"
18 UsernameTaken = "pq: username_taken"
19 EmailAlreadyRegistered = "pq: email_already_registered"
20)
21
15// Renderer wird verwendet, um die Routen (bspw. Login-Route) zu rendern. Damit bleibt Charakterin selbst ohne Template. 22// Renderer wird verwendet, um die Routen (bspw. Login-Route) zu rendern. Damit bleibt Charakterin selbst ohne Template.
16type Renderer interface { 23type Renderer interface {
17 // RenderLoginPage zeigt die Login-Seite an. 24 // RenderLoginPage zeigt die Login-Seite an.
18 RenderLoginPage(w http.ResponseWriter, data map[string]interface{}) 25 RenderLoginPage(w http.ResponseWriter, data map[string]interface{})
26 // RenderRegistrationPage zeigt die Registrations-Seite an.
27 RenderRegistrationPage(w http.ResponseWriter, data map[string]interface{})
19} 28}
20 29
21// Charakterin ist das tolle Login- und Accountmanagementsystem. 30// Charakterin ist das tolle Login- und Accountmanagementsystem.
@@ -70,33 +79,35 @@ func (c *Charakterin) DisplayLogin(w http.ResponseWriter, r *http.Request) {
70 c.DisplayLoginWithData(w, r, make(map[string]interface{})) 79 c.DisplayLoginWithData(w, r, make(map[string]interface{}))
71} 80}
72 81
73// Login versucht einen User einzuloggen. 82// LoginRequest versucht, einen Benutzer mit den gegebenen Daten einzuloggen.
83func (c *Charakterin) LoginRequest(username, password string) (string, error) {
84 var result string
85 err := c.Database.QueryRow("SELECT * FROM login.new_session($1, $2)", username, password).Scan(&result)
86 if err != nil {
87 return "", err
88 }
89 return result, nil
90}
91
92// Login versucht einen User durch einen Request einzuloggen.
74func (c *Charakterin) Login(w http.ResponseWriter, r *http.Request) { 93func (c *Charakterin) Login(w http.ResponseWriter, r *http.Request) {
75 if r.Method != "POST" { 94 if r.Method != "POST" {
76 return 95 return
77 } 96 }
78 97
79 // POST-Data lesen 98 // POST-Data lesen
80 defer r.Body.Close() 99 values, err := readBody(r)
81 data, err := ioutil.ReadAll(r.Body)
82 if err != nil {
83 http.Error(w, err.Error(), http.StatusInternalServerError)
84 return
85 }
86
87 values, err := url.ParseQuery(string(data))
88 if err != nil { 100 if err != nil {
89 http.Error(w, err.Error(), http.StatusInternalServerError) 101 http.Error(w, err.Error(), http.StatusInternalServerError)
90 return 102 return
91 } 103 }
92 104
93 username := values.Get("username") 105 username := values.Get("username")
94 var result string 106 session, err := c.LoginRequest(username, values.Get("password"))
95 err = c.Database.QueryRow("SELECT * FROM login.new_session($1, $2)", username, values.Get("password")).Scan(&result)
96 if err != nil { 107 if err != nil {
97 errStr := err.Error() 108 errStr := err.Error()
98 109
99 if errStr == "pq: no_such_user" || errStr == "pq: invalid_password" { 110 if errStr == NoSuchUser || errStr == InvalidPassword {
100 log.Printf("invalid login attempt by '%s': %s\n", username, errStr[4:]) 111 log.Printf("invalid login attempt by '%s': %s\n", username, errStr[4:])
101 data := make(map[string]interface{}) 112 data := make(map[string]interface{})
102 data["previous_user"] = username 113 data["previous_user"] = username
@@ -111,7 +122,7 @@ func (c *Charakterin) Login(w http.ResponseWriter, r *http.Request) {
111 122
112 http.SetCookie(w, &http.Cookie{ 123 http.SetCookie(w, &http.Cookie{
113 Name: "session", 124 Name: "session",
114 Value: result, 125 Value: session,
115 Expires: time.Now().AddDate(1, 0, 0), 126 Expires: time.Now().AddDate(1, 0, 0),
116 }) 127 })
117 http.Redirect(w, r, c.FallbackRoute, 302) 128 http.Redirect(w, r, c.FallbackRoute, 302)
@@ -119,32 +130,37 @@ func (c *Charakterin) Login(w http.ResponseWriter, r *http.Request) {
119 130
120// Logout loggt einen Charakter aus. Wird direkt über den Request gehandlet. 131// Logout loggt einen Charakter aus. Wird direkt über den Request gehandlet.
121func (c *Charakterin) Logout(w http.ResponseWriter, r *http.Request) { 132func (c *Charakterin) Logout(w http.ResponseWriter, r *http.Request) {
122 user, err := c.GetUserFromRequest(r) 133 cookie, err := r.Cookie("session")
123 if err != nil { 134 if err != nil {
124 http.Redirect(w, r, c.FallbackRoute, 302) 135 http.Redirect(w, r, c.FallbackRoute, 302)
125 return 136 return
126 } 137 }
127 138
128 stmt, err := c.Database.Prepare("DELETE FROM login.sessions WHERE id=$1") 139 stmt, err := c.Database.Prepare("DELETE FROM login.sessions WHERE id=$1")
129 if err != nil { 140 if err != nil {
130 http.Error(w, "500", http.StatusInternalServerError) 141 http.Error(w, "500", http.StatusInternalServerError)
131 return 142 return
132 } 143 }
133 144
134 result, err := stmt.Exec(user.SessionID) 145 result, err := stmt.Exec(cookie.Value)
135 if err != nil { 146 if err != nil {
136 log.Println(err) 147 log.Println(err)
137 http.Error(w, "500", http.StatusInternalServerError) 148 http.Error(w, "500", http.StatusInternalServerError)
138 return 149 return
139 } 150 }
140 151
141 if val, err := result.RowsAffected(); err != nil || val == 0 { 152 if val, err := result.RowsAffected(); err != nil || val == 0 {
142 log.Println("could not remove session",user.SessionID,err) 153 log.Println("could not remove session", cookie.Value, err)
143 http.Redirect(w, r, c.FallbackRoute, 302) 154 http.Redirect(w, r, c.FallbackRoute, 302)
144 return 155 return
145 } 156 }
146 157
147 user.Logout(w) 158 http.SetCookie(w, &http.Cookie{
159 Name: "session",
160 Value: "benis",
161 Expires: time.Now(),
162 MaxAge: 0,
163 })
148 http.Redirect(w, r, c.FallbackRoute, 302) 164 http.Redirect(w, r, c.FallbackRoute, 302)
149} 165}
150 166
@@ -165,6 +181,96 @@ func (c *Charakterin) IsLoggedIn(r *http.Request) bool {
165 return true 181 return true
166} 182}
167 183
184// DisplayRegistrationWithData rendert die Registration mit Daten (vorheriger Benutzer, Fehlermeldung)
185func (c *Charakterin) DisplayRegistrationWithData(w http.ResponseWriter, r *http.Request, data map[string]interface{}) {
186 if c.IsLoggedIn(r) {
187 http.Redirect(w, r, c.FallbackRoute, 302)
188 return
189 }
190
191 if c.renderer == nil {
192 log.Println("charakterin: no renderer set")
193 return
194 }
195
196 if _, ok := data["previous_user"]; !ok {
197 data["previous_user"] = ""
198 }
199 if _, ok := data["previous_email"]; !ok {
200 data["previous_email"] = ""
201 }
202 if _, ok := data["error"]; !ok {
203 data["error"] = ""
204 }
205
206 c.renderer.RenderRegistrationPage(w, data)
207}
208
209// DisplayRegistration zeigt die Route für die Registration an, wenn der User nicht bereits eingeloggt ist.
210func (c *Charakterin) DisplayRegistration(w http.ResponseWriter, r *http.Request) {
211 c.DisplayRegistrationWithData(w, r, make(map[string]interface{}))
212}
213
214// Register versucht einen Benutzer zu registrieren.
215func (c *Charakterin) Register(w http.ResponseWriter, r *http.Request) {
216 if r.Method != "POST" {
217 return
218 }
219
220 // POST-Data lesen
221 values, err := readBody(r)
222 if err != nil {
223 http.Error(w, err.Error(), http.StatusInternalServerError)
224 return
225 }
226
227 username := values.Get("username")
228 password := values.Get("password")
229 email := values.Get("email")
230 var result string
231 err = c.Database.QueryRow("SELECT * FROM login.register_user($1, $2, $3)", username, password, email).Scan(&result)
232 if err != nil {
233 errStr := err.Error()
234
235 if errStr == UsernameTaken {
236 data := make(map[string]interface{})
237 data["error"] = "Der Benutzername wird bereits verwendet."
238 data["previous_email"] = email
239 c.DisplayLoginWithData(w, r, data)
240 return
241 } else if errStr == EmailAlreadyRegistered {
242 data := make(map[string]interface{})
243 data["error"] = "Diese E-Mail wird bereits verwendet."
244 data["previous_user"] = username
245 c.DisplayLoginWithData(w, r, data)
246 return
247 }
248
249 http.Error(w, errStr, http.StatusInternalServerError)
250 return
251 }
252
253 log.Printf("user '%s' has been registered.\n", username)
254 if err := c.ConfirmEmail(result); err != nil {
255 log.Println("could not activate user", err)
256 http.Error(w, "user created, could not activate", http.StatusInternalServerError)
257 return
258 }
259 session, err := c.LoginRequest(username, password)
260 if err != nil {
261 log.Println("failed auto-login for", username, err)
262 http.Redirect(w, r, c.FallbackRoute, 302)
263 return
264 }
265
266 http.SetCookie(w, &http.Cookie{
267 Name: "session",
268 Value: session,
269 Expires: time.Now().AddDate(1, 0, 0),
270 })
271 http.Redirect(w, r, c.FallbackRoute, 302)
272}
273
168func (c *Charakterin) GetUserFromRequest(r *http.Request) (*User, error) { 274func (c *Charakterin) GetUserFromRequest(r *http.Request) (*User, error) {
169 cookie, err := r.Cookie("session") 275 cookie, err := r.Cookie("session")
170 if err != nil { 276 if err != nil {
@@ -176,7 +282,8 @@ func (c *Charakterin) GetUserFromRequest(r *http.Request) (*User, error) {
176 var password []byte 282 var password []byte
177 var id int 283 var id int
178 var lastActivity time.Time 284 var lastActivity time.Time
179 err = c.Database.QueryRow(`SELECT * FROM login.get_user_by_session($1)`, cookie.Value).Scan(&id, &email, &name, &password, &displayName, &lastActivity) 285 var isActive bool
286 err = c.Database.QueryRow(`SELECT id, email, name, password, display_name, last_activity, is_active FROM login.get_user_by_session($1)`, cookie.Value).Scan(&id, &email, &name, &password, &displayName, &lastActivity, &isActive)
180 if err != nil { 287 if err != nil {
181 return nil, err 288 return nil, err
182 } 289 }
@@ -193,8 +300,34 @@ func (c *Charakterin) GetUserFromRequest(r *http.Request) (*User, error) {
193 password, 300 password,
194 dspName, 301 dspName,
195 lastActivity, 302 lastActivity,
196 cookie.Value, 303 isActive,
197 } 304 }
198 305
199 return user, nil 306 return user, nil
200} 307}
308
309// ConfirmEmail konfirmiert die email addresse mit der gegebenen confirm id.
310func (c *Charakterin) ConfirmEmail(confirmId string) error {
311 var result string
312 err := c.Database.QueryRow(`SELECT * FROM login.confirm_user_email($1)`, confirmId).Scan(&result)
313 if err != nil {
314 return err
315 }
316
317 return nil
318}
319
320func readBody(r *http.Request) (url.Values, error) {
321 defer r.Body.Close()
322 data, err := ioutil.ReadAll(r.Body)
323 if err != nil {
324 return nil, err
325 }
326
327 values, err := url.ParseQuery(string(data))
328 if err != nil {
329 return nil, err
330 }
331
332 return values, nil
333}
diff --git a/user.go b/user.go
index 1546c6b..909859e 100644
--- a/user.go
+++ b/user.go
@@ -2,7 +2,6 @@ package charakterin
2 2
3import ( 3import (
4 "time" 4 "time"
5 "net/http"
6) 5)
7 6
8// Ein User ist ein ganz toller Benutzer. 7// Ein User ist ein ganz toller Benutzer.
@@ -13,7 +12,7 @@ type User struct {
13 Password []byte 12 Password []byte
14 DisplayName string 13 DisplayName string
15 LastActivity time.Time 14 LastActivity time.Time
16 SessionID string 15 IsActive bool
17} 16}
18 17
19// GetName gibt den Anzeigenamen oder wenn dieser nicht gesetzt ist den Benutzernamen zurück. 18// GetName gibt den Anzeigenamen oder wenn dieser nicht gesetzt ist den Benutzernamen zurück.
@@ -23,13 +22,3 @@ func (u *User) GetName() string {
23 } 22 }
24 return u.Name 23 return u.Name
25} 24}
26
27func (u *User) Logout(w http.ResponseWriter) {
28 http.SetCookie(w, &http.Cookie{
29 Name: "session",
30 Value: "benis",
31 Expires: time.Now(),
32 MaxAge: 0,
33 })
34 return
35} \ No newline at end of file