|
@@ -1,12 +1,18 @@
|
1
|
1
|
package main
|
2
|
2
|
|
3
|
3
|
import (
|
|
4
|
+ "bytes"
|
4
|
5
|
"container/heap"
|
5
|
6
|
"crypto/rand"
|
|
7
|
+ "crypto/sha1"
|
|
8
|
+ "database/sql"
|
6
|
9
|
"encoding/base64"
|
7
|
10
|
"errors"
|
|
11
|
+ _ "github.com/lib/pq"
|
|
12
|
+ "golang.org/x/crypto/pbkdf2"
|
8
|
13
|
"log"
|
9
|
14
|
"net/http"
|
|
15
|
+ "strings"
|
10
|
16
|
"time"
|
11
|
17
|
)
|
12
|
18
|
|
|
@@ -52,6 +58,7 @@ func (pq *SessionQueue) Pop() interface{} {
|
52
|
58
|
var (
|
53
|
59
|
sessions = make(map[string]*SessionData)
|
54
|
60
|
sessionQueue = make(SessionQueue, 0)
|
|
61
|
+ db *sql.DB
|
55
|
62
|
)
|
56
|
63
|
|
57
|
64
|
func sessionExpirer() {
|
|
@@ -66,6 +73,17 @@ func sessionExpirer() {
|
66
|
73
|
|
67
|
74
|
func init() {
|
68
|
75
|
go sessionExpirer()
|
|
76
|
+
|
|
77
|
+ connStr := "user=levyraati password=levyraati dbname=levyraati sslmode=disable"
|
|
78
|
+ var err error
|
|
79
|
+ db, err = sql.Open("postgres", connStr)
|
|
80
|
+ if err != nil {
|
|
81
|
+ log.Fatal(err)
|
|
82
|
+ }
|
|
83
|
+ _, err = db.Query("SELECT 1")
|
|
84
|
+ if err != nil {
|
|
85
|
+ log.Fatal(err)
|
|
86
|
+ }
|
69
|
87
|
}
|
70
|
88
|
|
71
|
89
|
func addSession(data *SessionData) {
|
|
@@ -73,12 +91,70 @@ func addSession(data *SessionData) {
|
73
|
91
|
heap.Push(&sessionQueue, data)
|
74
|
92
|
}
|
75
|
93
|
|
76
|
|
-func userOk(username, password string) bool {
|
77
|
|
- return (username == "Lamperi" && password == "paskaa")
|
|
94
|
+func generateHash(password string) (string, error) {
|
|
95
|
+ salt := make([]byte, 11)
|
|
96
|
+
|
|
97
|
+ if _, err := rand.Read(salt); err != nil {
|
|
98
|
+ log.Println(err)
|
|
99
|
+ return "", errors.New("Couldn't generate random string")
|
|
100
|
+ }
|
|
101
|
+
|
|
102
|
+ passwordBytes := []byte(password)
|
|
103
|
+ key := hashPasswordSalt(passwordBytes, salt)
|
|
104
|
+
|
|
105
|
+ saltStr := base64.StdEncoding.EncodeToString(salt)
|
|
106
|
+ keyStr := base64.StdEncoding.EncodeToString(key)
|
|
107
|
+ return saltStr + "$" + keyStr, nil
|
|
108
|
+}
|
|
109
|
+
|
|
110
|
+func hashOk(password, hashed string) (bool, error) {
|
|
111
|
+ parts := strings.Split(hashed, "$")
|
|
112
|
+ if len(parts) != 2 {
|
|
113
|
+ return false, errors.New("Invalid data stored in database for password")
|
|
114
|
+ }
|
|
115
|
+ salt, err := base64.StdEncoding.DecodeString(parts[0])
|
|
116
|
+ if err != nil {
|
|
117
|
+ return false, err
|
|
118
|
+ }
|
|
119
|
+ passwordHash, err := base64.StdEncoding.DecodeString(parts[1])
|
|
120
|
+ if err != nil {
|
|
121
|
+ return false, err
|
|
122
|
+ }
|
|
123
|
+ if len(passwordHash) != 32 {
|
|
124
|
+ return false, errors.New("Password hash was not 32 bytes long")
|
|
125
|
+ }
|
|
126
|
+
|
|
127
|
+ key := hashPasswordSalt([]byte(password), salt)
|
|
128
|
+ return bytes.Equal(key, passwordHash), nil
|
|
129
|
+}
|
|
130
|
+
|
|
131
|
+func hashPasswordSalt(password, salt []byte) []byte {
|
|
132
|
+ return pbkdf2.Key(password, salt, 4096, 32, sha1.New)
|
|
133
|
+}
|
|
134
|
+
|
|
135
|
+func userOk(username, password string) (bool, error) {
|
|
136
|
+ var hash string
|
|
137
|
+ err := db.QueryRow("SELECT u.password FROM public.user u WHERE lower(u.username) = lower($1)", username).Scan(&hash)
|
|
138
|
+ if err != nil {
|
|
139
|
+ if err.Error() == "sql: no rows in result set" {
|
|
140
|
+ return false, nil
|
|
141
|
+ } else {
|
|
142
|
+ return false, err
|
|
143
|
+ }
|
|
144
|
+ }
|
|
145
|
+
|
|
146
|
+ ok, err := hashOk(password, hash)
|
|
147
|
+ if err != nil {
|
|
148
|
+ return false, err
|
|
149
|
+ }
|
|
150
|
+ return ok, nil
|
78
|
151
|
}
|
79
|
152
|
|
80
|
153
|
func tryLogin(username, password string, longerTime bool) (http.Cookie, error) {
|
81
|
|
- if exists := userOk(username, password); !exists {
|
|
154
|
+ if exists, err := userOk(username, password); !exists {
|
|
155
|
+ if err != nil {
|
|
156
|
+ return http.Cookie{}, err
|
|
157
|
+ }
|
82
|
158
|
return http.Cookie{},
|
83
|
159
|
errors.New("The username or password you entered isn't correct.")
|
84
|
160
|
}
|