Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions adminControllor/adminLogin.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,23 @@ func AdminLogin(c *gin.Context) {
//Root Admin Login
if "root" == body.Username && config.RootAdminPasswordHash == hash.SHA256(body.Password) {
token := hash.SHA256(body.Username + body.Password + time.Now().String())
c.JSON(http.StatusOK, gin.H{"code": http.StatusOK, "message": "login success", "token": token})
var err error
if body.IsRemember {
c.SetCookie("admin_token", token, 30*24*60*60, "/", "", false, true)
err = sqlOperator.AddAdminToken(db, config.RootAdminUUHash, token, time.Now().Add(30*24*time.Hour))
} else {
c.SetCookie("admin_token", token, 0, "/", "", false, true)
err = sqlOperator.AddAdminToken(db, config.RootAdminUUHash, token, time.Now().Add(1*time.Hour))
}
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": http.StatusInternalServerError, "message": "insert admin token failed"})
return
}
//Set cookie (must be before c.JSON, otherwise headers are already flushed)
if body.IsRemember {
c.SetCookie("admin_token", token, 30*24*60*60, "/", "", false, true)
} else {
c.SetCookie("admin_token", token, 0, "/", "", false, true)
}
c.JSON(http.StatusOK, gin.H{"code": http.StatusOK, "message": "login success", "token": token})
return
}
//Normal Admin Login
Expand All @@ -57,16 +61,20 @@ func AdminLogin(c *gin.Context) {
return
}
token := hash.SHA256(body.Username + body.Password + time.Now().String())
c.JSON(http.StatusOK, gin.H{"code": http.StatusOK, "message": "login success", "token": token})
if body.IsRemember {
c.SetCookie("admin_token", token, 30*24*60*60, "/", "", false, true)
err = sqlOperator.AddAdminToken(db, admin.UUHash, token, time.Now().Add(30*24*time.Hour))
} else {
c.SetCookie("admin_token", token, 0, "/", "", false, true)
err = sqlOperator.AddAdminToken(db, admin.UUHash, token, time.Now().Add(1*time.Hour))
}
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": http.StatusInternalServerError, "message": "insert admin token failed"})
return
}
//Set cookie (must be before c.JSON, otherwise headers are already flushed)
if body.IsRemember {
c.SetCookie("admin_token", token, 30*24*60*60, "/", "", false, true)
} else {
c.SetCookie("admin_token", token, 0, "/", "", false, true)
}
c.JSON(http.StatusOK, gin.H{"code": http.StatusOK, "message": "login success", "token": token})
}
2 changes: 0 additions & 2 deletions adminControllor/adminLogout.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import (
"gorm.io/gorm"
)

//db := sqlOperator.GetDB()

type AdminLogoutRequest struct {
Token string `json:"token"`
}
Expand Down
1 change: 1 addition & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Config struct {

type SwitchConfig struct {
AllowMultiCharacter bool `json:"allow_multi_character"`
AllowAdminLogout bool `json:"allow_admin_logout"`
}

func GetConfig(path string) Config {
Expand Down
3 changes: 2 additions & 1 deletion example_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"root_admin_uu_hash": "15de633d1f56bbcb1e8e81ccdea6cc8b710f0bcdc24af74f992b9b1ab420a7b3",

"switch_config": {
"allow_multi_character": true
"allow_multi_character": true,
"allow_sign_up": true
}
}
7 changes: 7 additions & 0 deletions middleware/adminCheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package middleware

import (
"net/http"
"time"

sqlOperator "github.com/TrafficLight6/GoAccountHub/sql"
"github.com/gin-gonic/gin"
Expand All @@ -22,6 +23,12 @@ func AdminCheckMiddleware() gin.HandlerFunc {
c.Abort()
return
}
//Check token expiration
if !adminToken.DeadTime.After(time.Now()) {
c.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "error": "admin_token expired"})
c.Abort()
return
}
c.Set("adminToken", adminToken)
c.Next()
}
Expand Down
10 changes: 9 additions & 1 deletion router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/TrafficLight6/GoAccountHub/config"
"github.com/TrafficLight6/GoAccountHub/middleware"
sqlOperator "github.com/TrafficLight6/GoAccountHub/sql"
"github.com/TrafficLight6/GoAccountHub/userControllor"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
Expand All @@ -31,7 +32,7 @@ func ReturnRouter(config config.Config) (*gin.Engine, *gorm.DB) {

//Admin Api
//Login & Logout
v1.GET("/admin/login", adminControllor.AdminLogin)
v1.POST("/admin/login", adminControllor.AdminLogin)
v1.DELETE("/admin/logout", adminControllor.AdminLogout)

//Admin Operation
Expand Down Expand Up @@ -59,5 +60,12 @@ func ReturnRouter(config config.Config) (*gin.Engine, *gorm.DB) {
v1.GET("/character/range", middleware.AdminCheckMiddleware(), middleware.AdminPermissionCheckMiddleware("can_operate_character_range"), adminControllor.CharacterRange)
}

{
//USER ONLY
export := v1.Group("/export")
//Login & Logout
export.POST("/user/login", userControllor.Login)
export.DELETE("/user/logout", userControllor.Logout)
}
return router, db
}
14 changes: 14 additions & 0 deletions sql/checkUserToken.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package sqlOperator

import (
"github.com/TrafficLight6/GoAccountHub/sqlTable"
"gorm.io/gorm"
)

func CheckUserToken(db *gorm.DB, token string) bool {
var tokenRecord sqlTable.UserLoginToken
if err := db.Where("token = ?", token).First(&tokenRecord).Error; err != nil {
return false
}
return true
}
13 changes: 13 additions & 0 deletions sql/deleteUserToken.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package sqlOperator

import (
"github.com/TrafficLight6/GoAccountHub/sqlTable"
"gorm.io/gorm"
)

func DeleteUserToken(db *gorm.DB, token string) error {
if err := db.Where("token = ?", token).Delete(&sqlTable.UserLoginToken{}).Error; err != nil {
return err
}
return nil
}
18 changes: 18 additions & 0 deletions sql/getCharacterByUUHash.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package sqlOperator

import (
"github.com/TrafficLight6/GoAccountHub/sqlTable"
"gorm.io/gorm"
)

func GetCharacterByCharacterUUHash(db *gorm.DB, characterUUHash string) (sqlTable.Character, error) {
var character sqlTable.Character
err := db.Where("uu_hash = ?", characterUUHash).First(&character).Error
return character, err
}

func GetCharacterByUserUUHash(db *gorm.DB, userUUHash string) ([]sqlTable.Character, error) {
var characters []sqlTable.Character
err := db.Where("user_uu_hash = ?", userUUHash).Find(&characters).Error
return characters, err
}
12 changes: 12 additions & 0 deletions sql/getUesrUUHash.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package sqlOperator

import (
"github.com/TrafficLight6/GoAccountHub/sqlTable"
"gorm.io/gorm"
)

func GetUserUUHash(db *gorm.DB, userID uint) (string, error) {
var user sqlTable.User
err := db.Where("id = ?", userID).First(&user).Error
return user.UUHash, err
}
12 changes: 12 additions & 0 deletions sql/getUser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package sqlOperator

import (
"github.com/TrafficLight6/GoAccountHub/sqlTable"
"gorm.io/gorm"
)

func GetUserByUsernameAndPassword(db *gorm.DB, username string, passwordHash string) (sqlTable.User, error) {
var user sqlTable.User
err := db.Where("username = ? AND password_hash = ?", username, passwordHash).First(&user).Error
return user, err
}
2 changes: 1 addition & 1 deletion todo/target.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
- login
- signup

# Rows Range to Admin, User & Character(Admin Only)
# Add Normal User Api
106 changes: 106 additions & 0 deletions userControllor/login.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package userControllor

import (
"errors"
"net/http"
"time"

"github.com/TrafficLight6/GoAccountHub/hash"
sqlOperator "github.com/TrafficLight6/GoAccountHub/sql"
sqlTable "github.com/TrafficLight6/GoAccountHub/sqlTable"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)

type UserLoginRequestBody struct {
Username string `json:"username"`
CharacterName string `json:"character_name"`
Password string `json:"password"`
IsRemember bool `json:"is_remember"`
}

func Login(c *gin.Context) {
var body UserLoginRequestBody
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "message": "Invalid body"})
return
}
//Check request body
if body.Username == "" || body.CharacterName == "" || body.Password == "" {
c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "message": "Username, character name or password is empty"})
return
}
//Get db
db := c.MustGet("db").(*gorm.DB)
_ = db
//Is user exist
user, err := sqlOperator.GetUserByUsernameAndPassword(db, body.Username, hash.SHA256(body.Password))
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
c.JSON(http.StatusInternalServerError, gin.H{"code": http.StatusInternalServerError, "message": "Get user failed"})
return
}
if user.ID == 0 {
c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "message": "Invalid credentials"})
return
}
//Get user UUhash
userUUHash, err := sqlOperator.GetUserUUHash(db, user.ID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": http.StatusInternalServerError, "message": "Get user UUhash failed"})
return
}
//Get characters by user UUhash
characters, err := sqlOperator.GetCharacterByUserUUHash(db, userUUHash)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": http.StatusInternalServerError, "message": "Get characters failed"})
return
}
//Check character name exist
isCharacterExist := false
characterUUHash := ""
for _, character := range characters {
if character.CharacterName == body.CharacterName {
isCharacterExist = true
characterUUHash = character.UUHash
break
}
}
if !isCharacterExist {
c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "message": "Character name not exist"})
return
}
//Generate token
token := hash.SHA256(body.Username + body.CharacterName + body.Password + time.Now().String())
//Add token to db
var userToken sqlTable.UserLoginToken
if body.IsRemember {
userToken = sqlTable.UserLoginToken{
UUHash: userUUHash,
CharacterUUHash: characterUUHash,
Token: token,
DeadTime: time.Now().Add(30 * 24 * time.Hour),
}
} else {
userToken = sqlTable.UserLoginToken{
UUHash: userUUHash,
CharacterUUHash: characterUUHash,
Token: token,
DeadTime: time.Now().Add(1 * time.Hour),
}
}
//Add token to db
err = db.Create(&userToken).Error
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": http.StatusInternalServerError, "message": "Add token failed"})
return
}
//Set cookie (must be before c.JSON, otherwise headers are already flushed)
if body.IsRemember {
c.SetCookie("user_token", token, 30*24*60*60, "/", "", false, true)
} else {
c.SetCookie("user_token", token, 0, "/", "", false, true)
}
//Return token
c.JSON(http.StatusOK, gin.H{"code": http.StatusOK, "message": "Login success", "token": token})
return
}
40 changes: 40 additions & 0 deletions userControllor/logout.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package userControllor

import (
"net/http"

sqlOperator "github.com/TrafficLight6/GoAccountHub/sql"
"github.com/gin-gonic/gin"

"gorm.io/gorm"
)

type UserLogoutRequest struct {
Token string `json:"token"`
}

func Logout(c *gin.Context) {
var body UserLogoutRequest
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "error": "Invalid request body"})
return
}
//Validate Token
if body.Token == "" {
c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "error": "Token is empty"})
return
}
//Get db
db := c.Value("db").(*gorm.DB)
//Check Token Exist
if !sqlOperator.CheckUserToken(db, body.Token) {
c.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "error": "Token not found"})
return
}
//Delete Token From Database(Logout)
if err := sqlOperator.DeleteUserToken(db, body.Token); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": http.StatusInternalServerError, "error": "Internal server error"})
return
}
c.JSON(http.StatusOK, gin.H{"code": http.StatusOK, "message": "Logout success"})
}
Loading