|
|
@@ -7,6 +7,7 @@ import (
|
|
|
"strconv"
|
|
|
"git.mmnx.de/Moe/databaseutils"
|
|
|
"git.mmnx.de/Moe/configutils"
|
|
|
+ "git.mmnx.de/Moe/templatehelpers"
|
|
|
"github.com/dgrijalva/jwt-go"
|
|
|
"github.com/kataras/iris"
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
@@ -23,6 +24,8 @@ const ( // Error constants
|
|
|
ERR_SESSION_TIMED_OUT = "ERR_SESSION_TIMED_OUT"
|
|
|
ERR_INVALID_TOKEN = "ERR_INVALID_TOKEN"
|
|
|
ERR_USERNAME_TAKEN = "ERR_USERNAME_TAKEN"
|
|
|
+ ERR_INVALID_PARAM = "ERR_INVALID_PARAM"
|
|
|
+ ERR_NO_CHANGES = "ERR_NO_CHANGES"
|
|
|
)
|
|
|
|
|
|
type User struct { // User
|
|
|
@@ -104,6 +107,33 @@ func (user *User) Login(username string, password string) (string, error) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+func (user *User) Logout(userID string) {
|
|
|
+ userArrayID := SearchUser(userID) // get logged in users list index
|
|
|
+
|
|
|
+ user.ID = "" // empty
|
|
|
+ user.Username = ""
|
|
|
+ user.Password = ""
|
|
|
+ user.Admin = ""
|
|
|
+ user.TokenUsed = ""
|
|
|
+
|
|
|
+ (*Users)[userArrayID] = *user
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+func LogoutHandler(ctx *iris.Context) {
|
|
|
+ userID := ctx.GetString("userID")
|
|
|
+
|
|
|
+ user, err := GetUserFromDB(userID)
|
|
|
+ if err != nil {
|
|
|
+ templatehelpers.ShowError(err.Error(), ctx, "account")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ user.Logout(userID);
|
|
|
+ ctx.SetCookieKV("token", "")
|
|
|
+ ctx.Redirect("/")
|
|
|
+}
|
|
|
+
|
|
|
func (user *User) Update() error {
|
|
|
colsVals := make([][]string, 2)
|
|
|
colsVals[0] = []string{"username", user.Username}
|
|
|
@@ -119,21 +149,21 @@ func (user *User) Update() error {
|
|
|
}
|
|
|
|
|
|
func SearchUser(userID string) int {
|
|
|
- for i := range *Users {
|
|
|
- if (*Users)[i].ID == userID {
|
|
|
- return i
|
|
|
- }
|
|
|
+ for i := range *Users {
|
|
|
+ if (*Users)[i].ID == userID {
|
|
|
+ return i
|
|
|
}
|
|
|
- return -1
|
|
|
+ }
|
|
|
+ return -1
|
|
|
}
|
|
|
|
|
|
func SearchUserByUsername(username string) int {
|
|
|
- for i := range *Users {
|
|
|
- if (*Users)[i].Username == username {
|
|
|
- return i
|
|
|
- }
|
|
|
+ for i := range *Users {
|
|
|
+ if (*Users)[i].Username == username {
|
|
|
+ return i
|
|
|
}
|
|
|
- return -1
|
|
|
+ }
|
|
|
+ return -1
|
|
|
}
|
|
|
|
|
|
func VerifyUserLoggedIn(tokenString string) (bool, string, error) { // TODO renew JWT from time to time preventing expiry
|
|
|
@@ -173,13 +203,13 @@ func AuthHandler(ctx *iris.Context) {
|
|
|
ctx.Set("userID", userID) // save userID for in-context use
|
|
|
|
|
|
if err != nil {
|
|
|
- fmt.Println("Auth error: ", err.Error())
|
|
|
+ // fmt.Println("Auth error: ", err.Error())
|
|
|
}
|
|
|
|
|
|
if isAuthed {
|
|
|
ctx.Next() // successfully authed, next handler
|
|
|
} else {
|
|
|
- if err := ctx.Render("login_box.html", PageParams{"1", err.Error(), "login", "0"}); err != nil {
|
|
|
+ if err := ctx.Render("login_box.html", PageUserParams{"1", err.Error(), "login", "", "0", []string{}}); err != nil {
|
|
|
println(err.Error())
|
|
|
} // failed to auth
|
|
|
|
|
|
@@ -252,6 +282,16 @@ func GetUser(userID string) (User, error) {
|
|
|
return user, nil
|
|
|
}
|
|
|
|
|
|
+func GetUserFromDB(userID string) (User, error) {
|
|
|
+ row, err := databaseutils.DBUtil.GetRow("*", "users", "id", userID) // get user from db
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ return User{}, err
|
|
|
+ }
|
|
|
+
|
|
|
+ return User{row[0], row[1], string(row[2]), string(row[3]), string(row[4])}, nil
|
|
|
+}
|
|
|
+
|
|
|
func SearchUserByUsernameInDB(username string) int {
|
|
|
user, err := databaseutils.DBUtil.GetRow("*", "users", "username", username)
|
|
|
if err != nil {
|
|
|
@@ -269,6 +309,20 @@ func SearchUserByUsernameInDB(username string) int {
|
|
|
return userID
|
|
|
}
|
|
|
|
|
|
+func SearchUserByTokenInDB(token string) (int, error) {
|
|
|
+ user, err := databaseutils.DBUtil.GetRowsDoubleCond("users", "tokens", "`token-id` = `tokens`.`id`", "`tokens`.`value` = '" + token + "'")
|
|
|
+ if err != nil {
|
|
|
+ return -1, err
|
|
|
+ }
|
|
|
+
|
|
|
+ userID, err := strconv.Atoi(user[0][0])
|
|
|
+ if err != nil {
|
|
|
+ return -1, err
|
|
|
+ }
|
|
|
+
|
|
|
+ return userID, nil
|
|
|
+}
|
|
|
+
|
|
|
func RegisterUserWithToken(username string, password string, token string) error {
|
|
|
tokenID := databaseutils.DBUtil.GetString("id", "tokens", "value", token)
|
|
|
|
|
|
@@ -285,5 +339,66 @@ func RegisterUserWithToken(username string, password string, token string) error
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func VerifyUserUpdate(username string, password string, userID string) error {
|
|
|
+ tmpUser, err := GetUserFromDB(userID)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ if SearchUserByUsernameInDB(username) != -1 && username != tmpUser.Username { // username can't be changed as there already exists a user with that name or it's the old name
|
|
|
+ return errors.New(ERR_USERNAME_TAKEN)
|
|
|
+ }
|
|
|
+
|
|
|
+ if username == "" { // if not left empty change
|
|
|
+ return errors.New(ERR_INVALID_PARAM)
|
|
|
+ }
|
|
|
+
|
|
|
+ if password == "" { // if not left empty we change it
|
|
|
+ return errors.New(ERR_INVALID_PARAM)
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// Processes the update of an user, username and password are the new "wanted" values, can also be empty string ("")
|
|
|
+func UserUpdateProcessor(username string, password string, userID string) error {
|
|
|
+ user, err := GetUserFromDB(userID)
|
|
|
+ hashedPassword := ""
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ if username == "" {
|
|
|
+ username = user.Username
|
|
|
+ }
|
|
|
+
|
|
|
+ if password == "" {
|
|
|
+ password = user.Password
|
|
|
+ hashedPassword = user.Password // we dont need to / _can't_ re-hash the hash
|
|
|
+ }
|
|
|
+
|
|
|
+ if err = VerifyUserUpdate(username, password, userID); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ if hashedPassword == "" {
|
|
|
+ hashedPassword, err = func (hashedPassword []byte, err error) (string, error) { // hash password, we use an anonymous function to convert int to string
|
|
|
+ if err != nil { // should never happen
|
|
|
+ return "", err
|
|
|
+ }
|
|
|
+ return string(hashedPassword), nil
|
|
|
+ }(bcrypt.GenerateFromPassword([]byte(password), 15)) // this is the actual hashing call
|
|
|
+ }
|
|
|
+
|
|
|
+ user.Username = username
|
|
|
+ user.Password = hashedPassword
|
|
|
+
|
|
|
+ if err = user.Update(); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
return nil
|
|
|
}
|