package main import ( "time" "strings" "log" "encoding/json" "crypto/rand" "golang.org/x/crypto/bcrypt" "github.com/gomodule/redigo/redis" ) var globalPool *redis.Pool const userPrefix string = "user:" const devPrefix string = "dev:" 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"` MyDevs string `json:"my_devs"` } type Dev struct { Deveui string `json:"deveui"` Alias string `json:"alias"` } 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 globalPool (redis.Conn) conn := pool.Get() defer conn.Close() globalPool = pool // wir machen einen Connection Test ping(conn) // 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() { globalPool.Close() } func checkUserAvailable(username string) bool { logit("checkUserAvailable: User: "+username) conn := globalPool.Get() defer conn.Close() _, err := redis.String(conn.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 getMyDevs(username string) []string { res := []string{} if username == "" { return res } conn := globalPool.Get() defer conn.Close() logit("getMyDevs: User: "+username) mydevs, err := redis.String(conn.Do("HGET", userPrefix+username, "my_devs")) if err == nil { logit("getMyDevs: mydevs: "+mydevs) res = strings.Split(mydevs, ",") } else { log.Print(err) } return res } func getDevAlias(deveui string) string { res := deveui if deveui == "" { return res } conn := globalPool.Get() defer conn.Close() logit("getDevAlias: Deveui: "+deveui) alias, err := redis.String(conn.Do("HGET", devPrefix+deveui, "alias")) if err == nil { logit("getDevAlias: alias: "+alias) res = alias } else { log.Print(err) } return res } 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) { conn := globalPool.Get() defer conn.Close() 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 = conn.Do("HMSET", userPrefix+username, "password", string(hashedPassword), "new_password", string(hashedPassword), "confirm_id", confirm_id, "last_login", "", "my_devs","") if err != nil { logit("insertUser: Error inserting User: "+username) return } } func updateUser(username,password string) { conn := globalPool.Get() defer conn.Close() 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 = conn.Do("HMSET", userPrefix+username, "new_password", string(hashedPassword), "confirm_id", confirm_id) if err != nil { logit("updateUser: Error updateing User: "+username) return } _, err = conn.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 { conn := globalPool.Get() defer conn.Close() logit("checkLoginCredentials: called with username,password: "+username+","+password) pwd, err := redis.String(conn.Do("HGET", userPrefix+username, "password")) if err == nil { logit("checkLoginCredentials: pwd: "+pwd+" CMD: HGET "+userPrefix+username+userPrefix+username+" confirm_id") cid, err := redis.String(conn.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 } } } } else { log.Print(err) return false } hashedPassword := []byte(pwd) err = bcrypt.CompareHashAndPassword(hashedPassword, []byte(password)) return err == nil } func updateLoginTime(username string) { conn := globalPool.Get() defer conn.Close() _, err := conn.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) { conn := globalPool.Get() defer conn.Close() u, err := redis.String(conn.Do("GET", confirmPrefix+confirm_id)) if err != nil { logit("confirmUser: Error with searching confirm_id: "+confirm_id) return } new_password, err := redis.String(conn.Do("HGET", userPrefix+u, "new_password")) if err != nil { logit("confirmUser: Error with getting new_password: "+u) return } _, err = conn.Do("HMSET", userPrefix+u, "confirm_id", "", "password", new_password) if err != nil { logit("confirmUser: Error updateing User: "+u) return } _, err = conn.Do("DEL", confirmPrefix+confirm_id) if err != nil { logit("confirmUser: Error deleting confirm_id: "+confirm_id) return } }