package main import ( "time" "encoding/json" "crypto/rand" "golang.org/x/crypto/bcrypt" "github.com/gomodule/redigo/redis" ) var globalPool *redis.Pool var globalConn redis.Conn const userPrefix string = "user:" const confirmPrefix string = "confirm:" func newPool() *redis.Pool { return &redis.Pool{ // Maximum number of idle connections in the pool. MaxIdle: 80, // max number of connections MaxActive: 12000, // Dial is an application supplied function for creating and // configuring a connection. Dial: func() (redis.Conn, error) { c, err := redis.Dial("tcp", ":6379") if err != nil { panic(err.Error()) } return c, err }, } } // ping tests connectivity for redis (PONG should be returned) func ping(c redis.Conn) error { // Send PING command to Redis // PING command returns a Redis "Simple String" // Use redis.String to convert the interface type to string s, err := redis.String(c.Do("PING")) if err != nil { return err } logit("PING Response = "+s) // Output: PONG return nil } // User is a simple user struct for this example type User struct { Email string `json:"email"` Password string `json:"password"` NewPassword string `json:"new_password"` ConfirmId string `json:"confirm_id"` LastLogin string `json:"last_login"` } func setStruct(c redis.Conn, usr User) error { // serialize User object to JSON json, err := json.Marshal(usr) if err != nil { return err } // SET object _, err = c.Do("SET", userPrefix+usr.Email, json) if err != nil { return err } return nil } func getStruct(c redis.Conn, username string) (User, error) { usr := User{} s, err := redis.String(c.Do("GET", userPrefix+username)) if err == redis.ErrNil { logit("User does not exist:"+username) } else if err != nil { return usr, err } err = json.Unmarshal([]byte(s), &usr) return usr, nil } func initDB() { // newPool returns a pointer to a redis.Pool pool := newPool() // get a connection from the pool (redis.Conn) conn := pool.Get() globalPool = pool globalConn = conn // wir machen einen Connection Test ping(globalConn) // Wir legen einen initialen Admin User an, falls es diesen noch nicht gibt if checkUserAvailable("joerg.lehmann@nbit.ch") { insertUser("joerg.lehmann@nbit.ch","changeme123","Y"); } } func closeDB() { globalConn.Close() globalPool.Close() } func checkUserAvailable(username string) bool { logit("checkUserAvailable: User: "+username) _, err := redis.String(globalConn.Do("GET", userPrefix+username)) if (err == redis.ErrNil) { logit("User does not exist and is therefore available:"+username) return true } else if err != nil { logit("checkUserAvailable: Error to query Key Value Store") return false } return false } func randString(n int) string { const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" var bytes = make([]byte, n) rand.Read(bytes) for i, b := range bytes { bytes[i] = alphanum[b % byte(len(alphanum))] } return string(bytes) } func insertUser(username,password,is_admin string) { logit("insertUser: "+username) pwd := []byte(password) hashedPassword,err := bcrypt.GenerateFromPassword(pwd, bcrypt.DefaultCost) if err != nil { logit("insertUser: Error with bcrypt.GenerateFromPassword, User: "+username) return } confirm_id := "" _, err = globalConn.Do("HMSET", userPrefix+username, "password", string(hashedPassword), "new_password", string(hashedPassword), "confirm_id", confirm_id, "last_login", "") if err != nil { logit("insertUser: Error inserting User: "+username) return } } func updateUser(username,password string) { logit("updateUser: "+username) pwd := []byte(password) hashedPassword,err := bcrypt.GenerateFromPassword(pwd, bcrypt.DefaultCost) if err != nil { logit("updateUser: Error with bcrypt.GenerateFromPassword, User: "+username) return } confirm_id := randString(30) _, err = globalConn.Do("HMSET", userPrefix+username, "new_password", string(hashedPassword), "confirm_id", confirm_id) if err != nil { logit("updateUser: Error updateing User: "+username) return } _, err = globalConn.Do("SET", confirmPrefix+confirm_id,username) if err != nil { logit("updateUser: Error inserting confirm_id: "+confirm_id+": "+username) return } sendEmail(username,confirm_id) } func checkLoginCredentials(username,password string) bool { logit("checkLoginCredentials: called with username,password: "+username+","+password) pwd, err := redis.String(globalConn.Do("HGET", userPrefix+username, "password")) if err == nil { cid, err := redis.String(globalConn.Do("HGET", userPrefix+username, "confirm_id")) if err == nil { logit("checkLoginCredentials: cid: "+cid) if !(err != nil && cid != "") { logit("checkLoginCredentials: pwd: "+pwd) if err != nil { return false } } } } hashedPassword := []byte(pwd) err = bcrypt.CompareHashAndPassword(hashedPassword, []byte(password)) return err == nil } func updateLoginTime(username string) { _, err := globalConn.Do("HSET", userPrefix+username, "last_login", time.Now().UTC().Format("2006-01-02 15:04:05")) if err != nil { logit("updateUser: Error updateing User: "+username) return } } func confirmUser(confirm_id string) { u, err := redis.String(globalConn.Do("GET", confirmPrefix+confirm_id)) if err != nil { logit("confirmUser: Error with searching confirm_id: "+confirm_id) return } new_password, err := redis.String(globalConn.Do("HGET", userPrefix+u, "new_password")) if err != nil { logit("confirmUser: Error with getting new_password: "+u) return } _, err = globalConn.Do("HMSET", userPrefix+u, "confirm_id", "", "password", new_password) if err != nil { logit("confirmUser: Error updateing User: "+u) return } _, err = globalConn.Do("DEL", confirmPrefix+confirm_id) if err != nil { logit("confirmUser: Error deleting confirm_id: "+confirm_id) return } }