|
|
@@ -3,11 +3,12 @@ package usermanager
|
|
|
import (
|
|
|
"errors"
|
|
|
"time"
|
|
|
- "strconv"
|
|
|
+ "math/rand"
|
|
|
"git.mmnx.de/Moe/databaseutils"
|
|
|
"git.mmnx.de/Moe/configutils"
|
|
|
"github.com/dgrijalva/jwt-go"
|
|
|
"github.com/kataras/iris"
|
|
|
+ "golang.org/x/crypto/bcrypt"
|
|
|
"fmt"
|
|
|
)
|
|
|
|
|
|
@@ -23,18 +24,38 @@ const ( // Error constants
|
|
|
)
|
|
|
|
|
|
type User struct { // User
|
|
|
- ID int
|
|
|
+ ID string
|
|
|
Username string
|
|
|
Password string
|
|
|
Mail string
|
|
|
- Admin bool
|
|
|
+ Admin string
|
|
|
}
|
|
|
|
|
|
-type pageParams struct{
|
|
|
+type PageParams struct{
|
|
|
HasError string
|
|
|
Error string
|
|
|
ReqDir string
|
|
|
- } // {Error: ""} // TODO: OUTSOURCE
|
|
|
+ Admin string
|
|
|
+ } // {Error: ""} // TODO: OUTSOURCE : is outsourced here now
|
|
|
+
|
|
|
+type PageUserParams struct{
|
|
|
+ HasError string
|
|
|
+ Error string
|
|
|
+ ReqDir string
|
|
|
+ Username string
|
|
|
+ Email string
|
|
|
+ Admin string
|
|
|
+ } // {Error: ""}
|
|
|
+
|
|
|
+type PageUserParamsMessage struct{
|
|
|
+ HasError string
|
|
|
+ Error string
|
|
|
+ ReqDir string
|
|
|
+ Username string
|
|
|
+ Email string
|
|
|
+ Admin string
|
|
|
+ Message string
|
|
|
+ } // {Error: ""}
|
|
|
|
|
|
func (user *User) Login(username string, password string) (string, error) {
|
|
|
hmacSampleSecret := []byte(configutils.Conf.CryptoKey) // crypto key for JWT encryption
|
|
|
@@ -48,7 +69,9 @@ func (user *User) Login(username string, password string) (string, error) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if password == row[2] { // if sent pw == stored pw // TODO md5/crypto
|
|
|
+ err = bcrypt.CompareHashAndPassword([]byte(row[2]), []byte(password))
|
|
|
+
|
|
|
+ if err == nil { // if sent' pw hash == stored pw hash
|
|
|
expire, _ := time.ParseDuration("168h") // 7 days
|
|
|
|
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
|
|
@@ -61,10 +84,11 @@ func (user *User) Login(username string, password string) (string, error) {
|
|
|
|
|
|
tokenString, _ := token.SignedString(hmacSampleSecret)
|
|
|
|
|
|
- user.ID, _ = strconv.Atoi(row[0])
|
|
|
+ user.ID = row[0]
|
|
|
user.Username = row[1]
|
|
|
+ user.Password = string(row[2])
|
|
|
user.Mail = row[3]
|
|
|
- user.Admin, err = strconv.ParseBool(row[4])
|
|
|
+ user.Admin = string(row[4])
|
|
|
|
|
|
if err != nil {
|
|
|
fmt.Printf("Error: ", err.Error())
|
|
|
@@ -72,15 +96,27 @@ func (user *User) Login(username string, password string) (string, error) {
|
|
|
|
|
|
*Users = append(*Users, *user) // store user in logged-in-users list
|
|
|
|
|
|
- //fmt.Printf("%v\n", *Users) // DEBUG
|
|
|
-
|
|
|
return tokenString, nil // return tokenString (Cookie)
|
|
|
} else {
|
|
|
return "", errors.New(ERR_PASSWORD_MISMATCH) // wrong password
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func searchUser(userID int) int {
|
|
|
+func (user *User) Update() error {
|
|
|
+ colsVals := make([][]string, 2)
|
|
|
+ colsVals[0] = []string{"username", user.Username}
|
|
|
+ colsVals[1] = []string{"password", user.Password}
|
|
|
+
|
|
|
+ err := databaseutils.DBUtil.UpdateRow("users", "id", string(user.ID), colsVals)
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println("ERROOR UPDATING: " + err.Error())
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func SearchUser(userID string) int {
|
|
|
for i := range *Users {
|
|
|
if (*Users)[i].ID == userID {
|
|
|
return i
|
|
|
@@ -89,9 +125,18 @@ func searchUser(userID int) int {
|
|
|
return -1
|
|
|
}
|
|
|
|
|
|
-func VerifyUserLoggedIn(tokenString string) (bool, int, error) { // TODO renew JWT from time to time preventing expiry
|
|
|
+func SearchUserByUsername(username string) int {
|
|
|
+ for i := range *Users {
|
|
|
+ if (*Users)[i].Username == username {
|
|
|
+ return i
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return -1
|
|
|
+}
|
|
|
+
|
|
|
+func VerifyUserLoggedIn(tokenString string) (bool, string, error) { // TODO renew JWT from time to time preventing expiry
|
|
|
if tokenString == "" { // if no tokenString("Cookie") exists fail
|
|
|
- return false, -1, errors.New(ERR_INVALID_TOKEN)
|
|
|
+ return false, "-1", errors.New(ERR_INVALID_TOKEN)
|
|
|
}
|
|
|
|
|
|
hmacSampleSecret := []byte(configutils.Conf.CryptoKey) // crypto key for JWT encryption
|
|
|
@@ -105,18 +150,17 @@ func VerifyUserLoggedIn(tokenString string) (bool, int, error) { // TODO renew J
|
|
|
|
|
|
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { // if token is valid
|
|
|
if userID, ok := claims["userid"].(string); ok { // extract userID
|
|
|
- intUserID, _ := strconv.Atoi(userID) // convert to int ... god i love scripting languages
|
|
|
- sliceID := searchUser(intUserID) // verify that user has a session on the server
|
|
|
+ sliceID := SearchUser(userID) // verify that user has a session on the server
|
|
|
if sliceID != -1 { // searchUser returns -1 if there's no such user
|
|
|
- return true, intUserID, nil // logged in, TODO: "0" template comparision dynamic
|
|
|
+ return true, userID, nil // logged in, TODO: "0" template comparision dynamic
|
|
|
} else {
|
|
|
- return false, -1, errors.New(ERR_SESSION_TIMED_OUT) // Session probably expired - may also be faked? TODO more checks?
|
|
|
+ return false, "-1", errors.New(ERR_SESSION_TIMED_OUT) // Session probably expired - may also be faked? TODO more checks?
|
|
|
}
|
|
|
} else {
|
|
|
- return false, -1, errors.New("Unknown error") // This should never happen, prolly can't convert something in claims then..
|
|
|
+ return false, "-1", errors.New("Unknown error") // This should never happen, prolly can't convert something in claims then..
|
|
|
}
|
|
|
} else {
|
|
|
- return false, -1, errors.New(ERR_INVALID_TOKEN) // Token is invalid, expired or whatever, TODO switch with ERR_SESSION_TIMED_OUT when database based session system
|
|
|
+ return false, "-1", errors.New(ERR_INVALID_TOKEN) // Token is invalid, expired or whatever, TODO switch with ERR_SESSION_TIMED_OUT when database based session system
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -133,9 +177,41 @@ func AuthHandler(ctx *iris.Context) {
|
|
|
if isAuthed {
|
|
|
ctx.Next() // successfully authed, next handler
|
|
|
} else {
|
|
|
- if err := ctx.Render("login.html", pageParams{"1", err.Error(), "login"}); err != nil {
|
|
|
+ if err := ctx.Render("login.html", PageParams{"1", err.Error(), "login", "0"}); err != nil {
|
|
|
println(err.Error())
|
|
|
} // failed to auth
|
|
|
|
|
|
}
|
|
|
+}
|
|
|
+
|
|
|
+func GenerateTokens(numTokens int) []string {
|
|
|
+ const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
+ tokens := make([]string, 0)
|
|
|
+ dbTokens := make([][]string, 0)
|
|
|
+
|
|
|
+ for i := 0; i < numTokens; i++ {
|
|
|
+ b := make([]byte, 16) // 16 char long tokens
|
|
|
+ for i := range b {
|
|
|
+ b[i] = letterBytes[rand.Intn(len(letterBytes))]
|
|
|
+ }
|
|
|
+ tokens = append(tokens, string(b))
|
|
|
+ //dbTokens = append(dbTokens, []string{string(b), "0"})
|
|
|
+ dbTokens = [][]string{[]string{"value", string(b)}, []string{"used", "0"}}
|
|
|
+ err := databaseutils.DBUtil.InsertRow("tokens", dbTokens)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println(err.Error())
|
|
|
+ return []string{""}
|
|
|
+ }
|
|
|
+ // dbTokens[i] :=
|
|
|
+ }
|
|
|
+
|
|
|
+ // err := databaseutils.DBUtil.InsertRow("tokens", dbTokens)
|
|
|
+
|
|
|
+ /*if err != nil {
|
|
|
+ fmt.Println(err.Error())
|
|
|
+ return []string{""}
|
|
|
+ }*/
|
|
|
+
|
|
|
+ return tokens
|
|
|
+
|
|
|
}
|