From 4db930464405295f6b4a93259f687ec95412885e Mon Sep 17 00:00:00 2001 From: TrafficLight6 Date: Sat, 5 Sep 2026 12:03:45 +0800 Subject: [PATCH 01/10] Remove ./example_config --- .gitignore | 2 +- example_config.json | 16 ---------------- 2 files changed, 1 insertion(+), 17 deletions(-) delete mode 100644 example_config.json diff --git a/.gitignore b/.gitignore index 0b81c55..6a54375 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,4 @@ go.work.sum .vscode/ .trae/ -./config.json \ No newline at end of file +*config.json \ No newline at end of file diff --git a/example_config.json b/example_config.json deleted file mode 100644 index 175c13b..0000000 --- a/example_config.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "port": "8080", - "database_name": "GoAccountHub", - "database_host": "127.0.0.1", - "database_port": "5432", - "database_user": "postgres", - "database_password": "postgres", - - "root_admin_password_hash": "a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3", - "root_admin_uu_hash": "15de633d1f56bbcb1e8e81ccdea6cc8b710f0bcdc24af74f992b9b1ab420a7b3", - - "switch_config": { - "allow_multi_character": true, - "allow_sign_up": true - } -} \ No newline at end of file From 280cb16de49c9cdcd0223549c9f0332d3d32e388 Mon Sep 17 00:00:00 2001 From: TrafficLight6 Date: Sat, 5 Sep 2026 12:10:23 +0800 Subject: [PATCH 02/10] Update todo --- todo/target.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/todo/target.md b/todo/target.md index e37c1d0..e1a69d0 100644 --- a/todo/target.md +++ b/todo/target.md @@ -1,5 +1,4 @@ -# Character & User Model -- login +# Character & User Model - signup # Add Normal User Api \ No newline at end of file From 53c7ef52ee056799c10c6e8ecc038a687aef9016 Mon Sep 17 00:00:00 2001 From: TrafficLight6 Date: Sat, 5 Sep 2026 13:25:08 +0800 Subject: [PATCH 03/10] Add application key,to authorize third-party access to the GoAccountHub --- cliAction/addApplicationKey.go | 54 +++++++++++++++++++++++++++++++ cliAction/deleteApplicationkey.go | 49 ++++++++++++++++++++++++++++ main.go | 3 ++ sql/init.go | 2 ++ sql/key.go | 30 +++++++++++++++++ sqlTable/applicationKey.go | 10 ++++++ 6 files changed, 148 insertions(+) create mode 100644 cliAction/addApplicationKey.go create mode 100644 cliAction/deleteApplicationkey.go create mode 100644 sql/key.go create mode 100644 sqlTable/applicationKey.go diff --git a/cliAction/addApplicationKey.go b/cliAction/addApplicationKey.go new file mode 100644 index 0000000..c4d5297 --- /dev/null +++ b/cliAction/addApplicationKey.go @@ -0,0 +1,54 @@ +package action + +import ( + "fmt" + "time" + + "github.com/TrafficLight6/GoAccountHub/config" + "github.com/TrafficLight6/GoAccountHub/hash" + sqlOperator "github.com/TrafficLight6/GoAccountHub/sql" + "github.com/TrafficLight6/GoAccountHub/sqlTable" + "github.com/urfave/cli/v2" +) + +func AddApplicationKeyAction() *cli.Command { + return &cli.Command{ + Name: "add-key", + Usage: "Add Application Key", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "config", + Aliases: []string{"c"}, + Value: "./config.json", + Usage: "Config File", + }, + &cli.StringFlag{ + Name: "site", + Aliases: []string{"s"}, + Value: "default", + Usage: "Application Site Site", + }, + }, + Action: func(c *cli.Context) error { + appConfig := config.GetConfig(c.String("config")) + db := sqlOperator.ConnectDB(appConfig) + defer func() { + sqlDB, err := db.DB() + if err != nil { + fmt.Println("Error when Close DB:", err) + return + } + sqlDB.Close() + }() + var applicationKey sqlTable.ApplicationKey + applicationKey.ApplicationUsingSite = c.String("site") + applicationKey.Key = hash.SHA256(c.String("site") + time.Now().String()) + err := sqlOperator.AddApplicationKey(db, applicationKey) + if err != nil { + return err + } + fmt.Println("✅ Add Key Success") + return err + }, + } +} diff --git a/cliAction/deleteApplicationkey.go b/cliAction/deleteApplicationkey.go new file mode 100644 index 0000000..80e2251 --- /dev/null +++ b/cliAction/deleteApplicationkey.go @@ -0,0 +1,49 @@ +package action + +import ( + "fmt" + + "github.com/TrafficLight6/GoAccountHub/config" + sqlOperator "github.com/TrafficLight6/GoAccountHub/sql" + "github.com/urfave/cli/v2" +) + +func DeleteApplicationKeyAction() *cli.Command { + return &cli.Command{ + Name: "del-key", + Usage: "Delete Application Key", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "config", + Aliases: []string{"c"}, + Value: "./config.json", + Usage: "Config File", + }, + &cli.StringFlag{ + Name: "key", + Aliases: []string{"k"}, + Value: "default", + Usage: "Application Key", + }, + }, + Action: func(c *cli.Context) error { + appConfig := config.GetConfig(c.String("config")) + db := sqlOperator.ConnectDB(appConfig) + defer func() { + sqlDB, err := db.DB() + if err != nil { + fmt.Println("Error when Close DB:", err) + return + } + sqlDB.Close() + }() + key := c.String("key") + err := sqlOperator.DeleteApplicationKey(db, key) + if err != nil { + return err + } + fmt.Println("✅ Delete Key Success") + return err + }, + } +} diff --git a/main.go b/main.go index fc09498..a9013ba 100644 --- a/main.go +++ b/main.go @@ -17,6 +17,9 @@ func main() { action.EditPasswordAction(), action.GenerateConfigAction(), action.GenerateTestConfigAction(), + + action.AddApplicationKeyAction(), + action.DeleteApplicationKeyAction(), }, } diff --git a/sql/init.go b/sql/init.go index 94a73db..bfacb23 100644 --- a/sql/init.go +++ b/sql/init.go @@ -17,6 +17,8 @@ var ( &sqlTable.UserLoginToken{}, &sqlTable.Character{}, + + &sqlTable.ApplicationKey{}, } ) diff --git a/sql/key.go b/sql/key.go new file mode 100644 index 0000000..40274aa --- /dev/null +++ b/sql/key.go @@ -0,0 +1,30 @@ +package sqlOperator + +import ( + "github.com/TrafficLight6/GoAccountHub/sqlTable" + "gorm.io/gorm" +) + +func AddApplicationKey(db *gorm.DB, keyRow sqlTable.ApplicationKey) error { + return db.Create(&keyRow).Error +} + +func GetApplicationKey(db *gorm.DB, keyRow string) (sqlTable.ApplicationKey, error) { + var key sqlTable.ApplicationKey + if err := db.Where("key = ?", keyRow).First(&key).Error; err != nil { + return key, err + } + return key, nil +} + +func CheckApplicationKey(db *gorm.DB, keyRow string) bool { + var key sqlTable.ApplicationKey + if err := db.Where("key = ?", keyRow).First(&key).Error; err != nil { + return false + } + return true +} + +func DeleteApplicationKey(db *gorm.DB, key string) error { + return db.Where("key = ?", key).Delete(&sqlTable.ApplicationKey{}).Error +} diff --git a/sqlTable/applicationKey.go b/sqlTable/applicationKey.go new file mode 100644 index 0000000..6b6245b --- /dev/null +++ b/sqlTable/applicationKey.go @@ -0,0 +1,10 @@ +package sqlTable + +import "gorm.io/gorm" + +type ApplicationKey struct { + gorm.Model + ID int64 `gorm:"primaryKey"` + ApplicationUsingSite string `gorm:"column:application_using_site"` + Key string `gorm:"column:key"` +} From 0be681f0221a141b991e38b8e5c8c62a9192cd21 Mon Sep 17 00:00:00 2001 From: TrafficLight6 Date: Sat, 5 Sep 2026 13:31:13 +0800 Subject: [PATCH 04/10] Add application key check --- middleware/applicationKeyCheck.go | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 middleware/applicationKeyCheck.go diff --git a/middleware/applicationKeyCheck.go b/middleware/applicationKeyCheck.go new file mode 100644 index 0000000..fbfc0dd --- /dev/null +++ b/middleware/applicationKeyCheck.go @@ -0,0 +1,33 @@ +package middleware + +import ( + "net/http" + + sqlOperator "github.com/TrafficLight6/GoAccountHub/sql" + "github.com/gin-gonic/gin" + "gorm.io/gorm" +) + +func ApplicationKeyCheckMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + key, err := c.Cookie("app_key") + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "code": http.StatusBadRequest, + "error": "app_key cookie is required", + }) + c.Abort() + return + } + db := c.Value("db").(*gorm.DB) + if !sqlOperator.CheckApplicationKey(db, key) { + c.JSON(http.StatusBadRequest, gin.H{ + "code": http.StatusBadRequest, + "error": "app_key cookie is invalid", + }) + c.Abort() + return + } + c.Next() + } +} From e7bfb5f2aacf5606a689ddeb839b9c487b94e67d Mon Sep 17 00:00:00 2001 From: TrafficLight6 Date: Sat, 5 Sep 2026 13:36:03 +0800 Subject: [PATCH 05/10] Remove set cookie --- userControllor/login.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/userControllor/login.go b/userControllor/login.go index 8838a77..9382982 100644 --- a/userControllor/login.go +++ b/userControllor/login.go @@ -94,12 +94,6 @@ func Login(c *gin.Context) { 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 From ffa72526d33877394dd5949817f7e82a0f5e33c3 Mon Sep 17 00:00:00 2001 From: TrafficLight6 Date: Sat, 5 Sep 2026 13:36:48 +0800 Subject: [PATCH 06/10] Change Package Name --- {userControllor => appControllor}/login.go | 2 +- {userControllor => appControllor}/logout.go | 2 +- router/router.go | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) rename {userControllor => appControllor}/login.go (99%) rename {userControllor => appControllor}/logout.go (97%) diff --git a/userControllor/login.go b/appControllor/login.go similarity index 99% rename from userControllor/login.go rename to appControllor/login.go index 9382982..0068a63 100644 --- a/userControllor/login.go +++ b/appControllor/login.go @@ -1,4 +1,4 @@ -package userControllor +package appControllor import ( "errors" diff --git a/userControllor/logout.go b/appControllor/logout.go similarity index 97% rename from userControllor/logout.go rename to appControllor/logout.go index c632df0..b41be2a 100644 --- a/userControllor/logout.go +++ b/appControllor/logout.go @@ -1,4 +1,4 @@ -package userControllor +package appControllor import ( "net/http" diff --git a/router/router.go b/router/router.go index d351d20..ddc40e5 100644 --- a/router/router.go +++ b/router/router.go @@ -2,10 +2,10 @@ package router import ( "github.com/TrafficLight6/GoAccountHub/adminControllor" + "github.com/TrafficLight6/GoAccountHub/appControllor" "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" ) @@ -64,8 +64,8 @@ func ReturnRouter(config config.Config) (*gin.Engine, *gorm.DB) { //USER ONLY export := v1.Group("/export") //Login & Logout - export.POST("/user/login", userControllor.Login) - export.DELETE("/user/logout", userControllor.Logout) + export.POST("/user/login", appControllor.Login) + export.DELETE("/user/logout", appControllor.Logout) } return router, db } From ffe0b7afeb7592400237182bd6e629eafda062af Mon Sep 17 00:00:00 2001 From: TrafficLight6 Date: Sat, 5 Sep 2026 13:49:16 +0800 Subject: [PATCH 07/10] Change router name, and use middleware --- router/router.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/router/router.go b/router/router.go index ddc40e5..2be7bda 100644 --- a/router/router.go +++ b/router/router.go @@ -62,10 +62,10 @@ func ReturnRouter(config config.Config) (*gin.Engine, *gorm.DB) { { //USER ONLY - export := v1.Group("/export") + export := v1.Group("/app") //Login & Logout - export.POST("/user/login", appControllor.Login) - export.DELETE("/user/logout", appControllor.Logout) + export.POST("/user/login", middleware.ApplicationKeyCheckMiddleware(), appControllor.Login) + export.DELETE("/user/logout", middleware.ApplicationKeyCheckMiddleware(), appControllor.Logout) } return router, db } From dc44aa7820297f575fb6b21e89ef6efff8e01795 Mon Sep 17 00:00:00 2001 From: TrafficLight6 Date: Mon, 7 Sep 2026 10:51:37 +0800 Subject: [PATCH 08/10] Change value name of app router --- router/router.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/router/router.go b/router/router.go index 2be7bda..4682118 100644 --- a/router/router.go +++ b/router/router.go @@ -62,10 +62,13 @@ func ReturnRouter(config config.Config) (*gin.Engine, *gorm.DB) { { //USER ONLY - export := v1.Group("/app") + app := v1.Group("/app") //Login & Logout - export.POST("/user/login", middleware.ApplicationKeyCheckMiddleware(), appControllor.Login) - export.DELETE("/user/logout", middleware.ApplicationKeyCheckMiddleware(), appControllor.Logout) + app.POST("/user/login", middleware.ApplicationKeyCheckMiddleware(), appControllor.Login) + app.DELETE("/user/logout", middleware.ApplicationKeyCheckMiddleware(), appControllor.Logout) + //Get Metadata + app.GET("/user/get/metadata", appControllor.GetUserMetaData) + app.GET("/character/get/metadata", appControllor.GetCharacterMetaData) } return router, db } From 290409a8c216bb6649118f5bca289139092fd253 Mon Sep 17 00:00:00 2001 From: TrafficLight6 Date: Mon, 7 Sep 2026 10:52:15 +0800 Subject: [PATCH 09/10] Add app api: Get user & character metadata --- appControllor/getCharacterMetaData.go | 29 ++++++++++++++++++++++++++ appControllor/getUserMetaData.go | 30 +++++++++++++++++++++++++++ sql/getCharacterByToken.go | 18 ++++++++++++++++ sql/getUserByToken.go | 18 ++++++++++++++++ 4 files changed, 95 insertions(+) create mode 100644 appControllor/getCharacterMetaData.go create mode 100644 appControllor/getUserMetaData.go create mode 100644 sql/getCharacterByToken.go create mode 100644 sql/getUserByToken.go diff --git a/appControllor/getCharacterMetaData.go b/appControllor/getCharacterMetaData.go new file mode 100644 index 0000000..dd7874c --- /dev/null +++ b/appControllor/getCharacterMetaData.go @@ -0,0 +1,29 @@ +package appControllor + +import ( + "net/http" + + sqlOperator "github.com/TrafficLight6/GoAccountHub/sql" + "github.com/gin-gonic/gin" + "gorm.io/gorm" +) + +type GetCharacterMetaDataRequestBody struct { + Token string `json:"token"` +} + +func GetCharacterMetaData(c *gin.Context) { + var body GetCharacterMetaDataRequestBody + if err := c.ShouldBindJSON(&body); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "error": "invalid request"}) + return + } + //Get db + db := c.Value("db").(*gorm.DB) + character, err := sqlOperator.GetCharacterByToken(db, body.Token) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"code": http.StatusOK, "message": "success", "meta_data": character.MetaData}) +} diff --git a/appControllor/getUserMetaData.go b/appControllor/getUserMetaData.go new file mode 100644 index 0000000..18041aa --- /dev/null +++ b/appControllor/getUserMetaData.go @@ -0,0 +1,30 @@ +package appControllor + +import ( + "net/http" + + sqlOperator "github.com/TrafficLight6/GoAccountHub/sql" + "github.com/gin-gonic/gin" + "gorm.io/gorm" +) + +type GetUserMetaDataRequestBody struct { + Token string `json:"token"` +} + +func GetUserMetaData(c *gin.Context) { + var body GetUserMetaDataRequestBody + if err := c.ShouldBindJSON(&body); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "message": "Invalid body"}) + return + } + //Get db + db := c.Value("db").(*gorm.DB) + //Get user by token + user, err := sqlOperator.GetUserByToken(db, body.Token) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"code": http.StatusInternalServerError, "message": "Internal server error"}) + return + } + c.JSON(http.StatusOK, gin.H{"code": http.StatusOK, "message": "Success", "meta_data": user.MetaData}) +} diff --git a/sql/getCharacterByToken.go b/sql/getCharacterByToken.go new file mode 100644 index 0000000..899798e --- /dev/null +++ b/sql/getCharacterByToken.go @@ -0,0 +1,18 @@ +package sqlOperator + +import ( + "github.com/TrafficLight6/GoAccountHub/sqlTable" + "gorm.io/gorm" +) + +func GetCharacterByToken(db *gorm.DB, token string) (sqlTable.Character, error) { + var userLoginToken sqlTable.UserLoginToken + if err := db.Where("token = ?", token).First(&userLoginToken).Error; err != nil { + return sqlTable.Character{}, err + } + var character sqlTable.Character + if err := db.Where("uu_hash = ? AND user_uu_hash = ?", userLoginToken.CharacterUUHash, userLoginToken.UUHash).First(&character).Error; err != nil { + return sqlTable.Character{}, err + } + return character, nil +} diff --git a/sql/getUserByToken.go b/sql/getUserByToken.go new file mode 100644 index 0000000..382aebf --- /dev/null +++ b/sql/getUserByToken.go @@ -0,0 +1,18 @@ +package sqlOperator + +import ( + "github.com/TrafficLight6/GoAccountHub/sqlTable" + "gorm.io/gorm" +) + +func GetUserByToken(db *gorm.DB, token string) (sqlTable.User, error) { + var userLoginToken sqlTable.UserLoginToken + if err := db.Where("token = ?", token).First(&userLoginToken).Error; err != nil { + return sqlTable.User{}, err + } + var user sqlTable.User + if err := db.Where("uu_hash = ?", userLoginToken.UUHash).First(&user).Error; err != nil { + return sqlTable.User{}, err + } + return user, nil +} From dfc8ea6366cb514b44cbcb0e292ddbd0815a92c4 Mon Sep 17 00:00:00 2001 From: TrafficLight6 Date: Mon, 7 Sep 2026 10:58:48 +0800 Subject: [PATCH 10/10] Add all user & character operation in app router, need `ApplicationKey.Key` (from ./sqlTable/applicationKey.go) --- router/router.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/router/router.go b/router/router.go index 4682118..669c351 100644 --- a/router/router.go +++ b/router/router.go @@ -66,6 +66,18 @@ func ReturnRouter(config config.Config) (*gin.Engine, *gorm.DB) { //Login & Logout app.POST("/user/login", middleware.ApplicationKeyCheckMiddleware(), appControllor.Login) app.DELETE("/user/logout", middleware.ApplicationKeyCheckMiddleware(), appControllor.Logout) + //User Operation + app.POST("/user/add", middleware.ApplicationKeyCheckMiddleware(), adminControllor.UserAdd) + app.DELETE("/user/delete", middleware.ApplicationKeyCheckMiddleware(), adminControllor.UserDelete) + app.PUT("/user/edit", middleware.ApplicationKeyCheckMiddleware(), adminControllor.UserEdit) + app.GET("/user/get", middleware.ApplicationKeyCheckMiddleware(), adminControllor.UserGet) + app.GET("/user/range", middleware.ApplicationKeyCheckMiddleware(), adminControllor.UserRange) + //Character Operation + app.POST("/character/add", middleware.ApplicationKeyCheckMiddleware(), adminControllor.CharacterAdd) + app.DELETE("/character/delete", middleware.ApplicationKeyCheckMiddleware(), adminControllor.CharacterDelete) + app.PUT("/character/edit", middleware.ApplicationKeyCheckMiddleware(), adminControllor.CharacterEdit) + app.GET("/character/get", middleware.ApplicationKeyCheckMiddleware(), adminControllor.CharacterGet) + app.GET("/character/range", middleware.ApplicationKeyCheckMiddleware(), adminControllor.CharacterRange) //Get Metadata app.GET("/user/get/metadata", appControllor.GetUserMetaData) app.GET("/character/get/metadata", appControllor.GetCharacterMetaData)