From 4688c105850bf8c1268f2f23042bd4c899d6cd45 Mon Sep 17 00:00:00 2001 From: nightnai Date: Fri, 4 Sep 2026 23:03:50 +0800 Subject: [PATCH] add user routes --- db/db.go | 21 +++ master/master.go | 9 +- pbutil/pbutil.go | 4 +- routes/api/multiroom/create/param_userid.go | 21 +++ routes/api/user/heart/param_userid.go | 21 +++ routes/api/user/index.go | 141 ++++++++++++++++++++ routes/api/user/login.go | 131 ++++++++++++++++++ routes/api/user/param_userid.go | 59 ++++++++ routes/api/user/param_userid/auth.go | 70 ++++++++++ routes/api/user/param_userid/fcm.go | 21 +++ routes/api/user/param_userid/index.go | 87 ++++++++++++ routes/helper.go | 5 +- 12 files changed, 579 insertions(+), 11 deletions(-) create mode 100644 routes/api/multiroom/create/param_userid.go create mode 100644 routes/api/user/heart/param_userid.go create mode 100644 routes/api/user/index.go create mode 100644 routes/api/user/login.go create mode 100644 routes/api/user/param_userid.go create mode 100644 routes/api/user/param_userid/auth.go create mode 100644 routes/api/user/param_userid/fcm.go create mode 100644 routes/api/user/param_userid/index.go diff --git a/db/db.go b/db/db.go index cb55600..f16c16f 100644 --- a/db/db.go +++ b/db/db.go @@ -2,6 +2,7 @@ package db import ( "encoding/json" + "fmt" "os" "sync" ) @@ -10,6 +11,13 @@ type Database struct { Users map[string][]map[string]any `json:"Users"` } +type UserIdType string + +const ( + UserId UserIdType = "userId" + Bid UserIdType = "bid" +) + var ( DB Database mu sync.Mutex @@ -45,3 +53,16 @@ func Save() { os.WriteFile(tmp, data, 0644) os.Rename(tmp, path) } + +func FindUser(id string, idType ...UserIdType) map[string]any { + key := UserId + if len(idType) > 0 { + key = idType[0] + } + for _, user := range DB.Users[os.Getenv("SERVER")] { + if fmt.Sprintf("%v", user[string(key)]) == id { + return user + } + } + return nil +} diff --git a/master/master.go b/master/master.go index 8b7d07e..4426fc2 100644 --- a/master/master.go +++ b/master/master.go @@ -40,19 +40,12 @@ func ReloadMaster() map[string]any { return cache } - // bzip2 解壓 decompressed, err := io.ReadAll(bzip2.NewReader(bytes.NewReader(decrypted))) if err != nil { return cache } - // protobuf decode → JSON map - msg, err := pbutil.Decode("SuiteMasterGetResponse", decompressed) - if err != nil { - return cache - } - - result, err := pbutil.ToMap(msg) + result, err := pbutil.Decode("SuiteMasterGetResponse", decompressed) if err != nil { return cache } diff --git a/pbutil/pbutil.go b/pbutil/pbutil.go index c5fe126..b151b6a 100644 --- a/pbutil/pbutil.go +++ b/pbutil/pbutil.go @@ -23,7 +23,7 @@ func fullName(message string) protoreflect.FullName { return protoreflect.FullName(fmt.Sprintf("%sdori.proto.ce.%s", server, message)) } -func Decode(message string, data []byte) (proto.Message, error) { +func Decode(message string, data []byte) (map[string]any, error) { mt, err := protoregistry.GlobalTypes.FindMessageByName(fullName(message)) if err != nil { return nil, fmt.Errorf("message %s not found", message) @@ -34,7 +34,7 @@ func Decode(message string, data []byte) (proto.Message, error) { return nil, err } - return msg, nil + return ToMap(msg) } func Encode(message string, data map[string]any) ([]byte, error) { diff --git a/routes/api/multiroom/create/param_userid.go b/routes/api/multiroom/create/param_userid.go new file mode 100644 index 0000000..6ec6583 --- /dev/null +++ b/routes/api/multiroom/create/param_userid.go @@ -0,0 +1,21 @@ +package create + +import ( + "fmt" + + "bdgrp_go/routes" + + "github.com/gofiber/fiber/v2" +) + +func init() { + path := routes.PathOf() + routes.Register(func(app *fiber.App) { + app.Post(path, multiroom) + fmt.Println("Loaded:", path) + }) +} + +func multiroom(c *fiber.Ctx) error { + return c.SendString("") +} diff --git a/routes/api/user/heart/param_userid.go b/routes/api/user/heart/param_userid.go new file mode 100644 index 0000000..e4a6317 --- /dev/null +++ b/routes/api/user/heart/param_userid.go @@ -0,0 +1,21 @@ +package heart + +import ( + "fmt" + + "bdgrp_go/routes" + + "github.com/gofiber/fiber/v2" +) + +func init() { + path := routes.PathOf() + routes.Register(func(app *fiber.App) { + app.Get(path, heart) + fmt.Println("Loaded:", path) + }) +} + +func heart(c *fiber.Ctx) error { + return c.SendString("") +} diff --git a/routes/api/user/index.go b/routes/api/user/index.go new file mode 100644 index 0000000..6a1dbc0 --- /dev/null +++ b/routes/api/user/index.go @@ -0,0 +1,141 @@ +package user + +import ( + "bdgrp_go/db" + "bdgrp_go/pbutil" + "bdgrp_go/routes" + "bdgrp_go/utils" + "fmt" + "maps" + "os" + "time" + + "github.com/google/uuid" + + "github.com/gofiber/fiber/v2" +) + +func init() { + path := routes.PathOf() + routes.Register(func(app *fiber.App) { + app.Post(path, postUser) + fmt.Println("Loaded:", path) + }) +} + +func postUser(c *fiber.Ctx) error { + server := os.Getenv("SERVER") + decrypted, err := utils.Decrypt(c.Body()) + if err != nil { + fmt.Println(err) + } + decoded, err := pbutil.Decode("UserPostRequest", decrypted) + if err != nil { + fmt.Println(err) + } + + var ( + userName string + introduction string + ) + + switch server { + case "TW": + userName = "新人工作人員" + introduction = "你好!" + case "JP": + userName = "新人スタッフ" + introduction = "よろしくお願いします!" + case "GL": + userName = "New Staff" + introduction = "Nice to meet you!" + } + + hash := uuid.New().String() + + users := db.DB.Users[server] + + nextId := 1001 + if len(users) > 0 { + last := users[len(users)-1] + if id, ok := last["userId"].(float64); ok { + nextId = int(id) + 1 + } + } + + newUser := map[string]any{ + "userId": nextId, + "hash": hash, + "userName": userName, + "clientVersion": decoded["clientVersion"].(string), + "platform": decoded["platform"].(string), + "deviceModel": decoded["deviceModel"].(string), + "operatingSystem": decoded["operatingSystem"].(string), + "birthMonth": "199001", + "tutorialStatus": "end", + "introduction": introduction, + "unknownString": "standard", + "tutorialEndedAt": time.Now().UnixMilli(), + } + + newGamedata := map[string]any{ + "rank": 114, + "exp": 67, + "coin": 114514, + "mainDeck": 1, + "paidStar": 0, + "freeStar": 514, + "seal": 0, + "degree": []any{100, nil}, + "publishTotalDeckPowerFlg": false, + "publishBandRankFlg": false, + "publishMusicClearedFlg": false, + "publishMusicFullComboFlg": false, + "publishHighScoreRatingFlg": false, + "pooledExp": 0, + "totalExp": 0, + "nextExp": 0, + "publishUpdatedAtFlg": true, + "startDashLoginBonusReceiveFlg": false, + "publishMusicAllPerfectFlg": false, + "publishDeckRankFlg": false, + "publishStageAchievementConditionsFlg": false, + "publishStageFriendRankingFlg": true, + "publishCharacterRankFlg": false, + "loginDays": 0, + "useProfileSettingDegree": true, + "useProfileSettingSituation": true, + "selectedCharacterType": "character_situation", + } + + maps.Copy(newUser, newGamedata) + + db.DB.Users[server] = append(db.DB.Users[server], newUser) + db.Save() + + data := map[string]any{ + "userId": fmt.Sprintf("%v", newUser["userId"]), + "hash": newUser["hash"], + "userName": newUser["userName"], + "clientVersion": newUser["clientVersion"], + "platform": newUser["platform"], + "deviceModel": newUser["deviceModel"], + "operatingSystem": newUser["operatingSystem"], + "tutorialStatus": newUser["tutorialStatus"], + "introduction": newUser["introduction"], + "unknownString": newUser["unknownString"], + "tutorialEndedAt": fmt.Sprintf("%v", newUser["tutorialEndedAt"]), + } + + encoded, err := pbutil.Encode("UserRegistration", data) + if err != nil { + fmt.Println(err) + } + + encrypted, err := utils.Encrypt(encoded) + if err != nil { + fmt.Println(err) + } + + return c.Send(encrypted) +} diff --git a/routes/api/user/login.go b/routes/api/user/login.go new file mode 100644 index 0000000..2b55ffc --- /dev/null +++ b/routes/api/user/login.go @@ -0,0 +1,131 @@ +package user + +import ( + "bdgrp_go/db" + "bdgrp_go/pbutil" + "bdgrp_go/routes" + "bdgrp_go/utils" + "fmt" + "maps" + "os" + "time" + + "github.com/google/uuid" + + "github.com/gofiber/fiber/v2" +) + +func init() { + path := routes.PathOf() + routes.Register(func(app *fiber.App) { + app.Post(path, login) + fmt.Println("Loaded:", path) + }) +} + +func login(c *fiber.Ctx) error { + server := os.Getenv("SERVER") + decrypted, err := utils.Decrypt(c.Body()) + if err != nil { + fmt.Println(err) + } + decoded, err := pbutil.Decode("UserLogin", decrypted) + if err != nil { + fmt.Println(err) + } + + user := db.FindUser(fmt.Sprintf("%v", decoded["bid"]), db.Bid) + + if user == nil { + hash := uuid.New().String() + + users := db.DB.Users[server] + + nextId := 1001 + if len(users) > 0 { + last := users[len(users)-1] + if id, ok := last["userId"].(float64); ok { + nextId = int(id) + 1 + } + } + + newUser := map[string]any{ + "bid": decoded["bid"].(string), + "userId": nextId, + "hash": hash, + "userName": "新手工作人员", + "clientVersion": decoded["clientVersion"].(string), + "platform": decoded["platform"].(string), + "deviceModel": decoded["deviceModel"].(string), + "operatingSystem": decoded["operatingSystem"].(string), + "birthMonth": "199001", + "tutorialStatus": "end", + "introduction": "请多多关照!", + "unknownString": "standard", + "tutorialEndedAt": time.Now().UnixMilli(), + } + + newGamedata := map[string]any{ + "rank": 114, + "exp": 67, + "coin": 114514, + "mainDeck": 1, + "paidStar": 0, + "freeStar": 514, + "seal": 0, + "degree": []any{100, nil}, + "publishTotalDeckPowerFlg": false, + "publishBandRankFlg": false, + "publishMusicClearedFlg": false, + "publishMusicFullComboFlg": false, + "publishHighScoreRatingFlg": false, + "pooledExp": 0, + "totalExp": 0, + "nextExp": 0, + "publishUpdatedAtFlg": true, + "startDashLoginBonusReceiveFlg": false, + "publishMusicAllPerfectFlg": false, + "publishDeckRankFlg": false, + "publishStageAchievementConditionsFlg": false, + "publishStageFriendRankingFlg": true, + "publishCharacterRankFlg": false, + "loginDays": 0, + "useProfileSettingDegree": true, + "useProfileSettingSituation": true, + "selectedCharacterType": "character_situation", + } + + maps.Copy(newUser, newGamedata) + + db.DB.Users[server] = append(db.DB.Users[server], newUser) + db.Save() + + user = newUser + } + + data := map[string]any{ + "userId": fmt.Sprintf("%v", user["userId"]), + "hash": user["hash"], + "userName": user["userName"], + "clientVersion": user["clientVersion"], + "platform": user["platform"], + "deviceModel": user["deviceModel"], + "operatingSystem": user["operatingSystem"], + "tutorialStatus": user["tutorialStatus"], + "introduction": user["introduction"], + "unknownString": user["unknownString"], + "tutorialEndedAt": fmt.Sprintf("%v", user["tutorialEndedAt"]), + } + + encoded, err := pbutil.Encode("UserRegistration", data) + if err != nil { + fmt.Println(err) + } + + encrypted, err := utils.Encrypt(encoded) + if err != nil { + fmt.Println(err) + } + + return c.Send(encrypted) +} diff --git a/routes/api/user/param_userid.go b/routes/api/user/param_userid.go new file mode 100644 index 0000000..f0b4bba --- /dev/null +++ b/routes/api/user/param_userid.go @@ -0,0 +1,59 @@ +package user + +import ( + "bdgrp_go/db" + "bdgrp_go/pbutil" + "bdgrp_go/routes" + "bdgrp_go/utils" + "fmt" + + "github.com/gofiber/fiber/v2" +) + +func init() { + path := routes.PathOf() + routes.Register(func(app *fiber.App) { + app.Get(path, get) + app.Put(path, putUser) + fmt.Println("Loaded:", path) + }) +} + +func get(c *fiber.Ctx) error { + return c.SendString("") +} + +func putUser(c *fiber.Ctx) error { + decrypted, _ := utils.Decrypt(c.Body()) + + decoded, err := pbutil.Decode("UserPutRequest", decrypted) + if err != nil { + fmt.Println(err) + } + + userId := c.Params("userid") + + user := db.FindUser(userId) + + if v, ok := decoded["userName"].(string); ok && v != "" { + user["userName"] = v + } + if v, ok := decoded["birthMonth"].(string); ok && v != "" { + user["birthMonth"] = v + } + if v, ok := decoded["introduction"].(string); ok && v != "" { + user["introduction"] = v + } + if v, ok := decoded["tutorialStatus"].(string); ok && v != "" { + user["tutorialStatus"] = v + } + if v, ok := decoded["mainDeck"].(float64); ok && v != 0 { + user["mainDeck"] = uint64(v) + } + if v, ok := decoded["degree"].(float64); ok && v != 0 { + user["degree"] = uint32(v) + } + + db.Save() + return c.SendString("") +} diff --git a/routes/api/user/param_userid/auth.go b/routes/api/user/param_userid/auth.go new file mode 100644 index 0000000..8033269 --- /dev/null +++ b/routes/api/user/param_userid/auth.go @@ -0,0 +1,70 @@ +package param_userid + +import ( + "bdgrp_go/db" + "bdgrp_go/pbutil" + "bdgrp_go/routes" + "bdgrp_go/utils" + "crypto/sha1" + "fmt" + "os" + + "github.com/gofiber/fiber/v2" +) + +func init() { + path := routes.PathOf() + routes.Register(func(app *fiber.App) { + app.Put(path, Auth) + fmt.Println("Loaded:", path) + }) +} + +func Auth(c *fiber.Ctx) error { + server := os.Getenv("SERVER") + userid := c.Params("userid") + + decrypted, err := utils.Decrypt(c.Body()) + if err != nil { + return c.Status(500).SendString("") + } + + decoded, err := pbutil.Decode("UserAuthRequest", decrypted) + if err != nil { + return c.Status(500).SendString("") + } + + hash := fmt.Sprintf("%x", sha1.Sum([]byte(userid+":"))) + + errData := map[string]any{ + "httpStatus": 403, + "errorCode": "", + "errorMessage": "signature invalid.", + } + + sendErr := func() error { + encoded, _ := pbutil.Encode("ClientErrorResponse", errData) + encrypted, _ := utils.Encrypt(encoded) + return c.Status(403).Send(encrypted) + } + + user := db.FindUser(userid) + if hash != decoded["hash1"] || user == nil { + return sendErr() + } + + if c.Get("x-signature") != user["hash"] { + return sendErr() + } + + // 更新 clientVersion + for i, u := range db.DB.Users[server] { + if fmt.Sprintf("%v", u["userId"]) == userid { + db.DB.Users[server][i]["clientVersion"] = c.Get("x-clientversion") + break + } + } + db.Save() + + return c.Send(nil) +} diff --git a/routes/api/user/param_userid/fcm.go b/routes/api/user/param_userid/fcm.go new file mode 100644 index 0000000..c475344 --- /dev/null +++ b/routes/api/user/param_userid/fcm.go @@ -0,0 +1,21 @@ +package param_userid + +import ( + "fmt" + + "bdgrp_go/routes" + + "github.com/gofiber/fiber/v2" +) + +func init() { + path := routes.PathOf() + routes.Register(func(app *fiber.App) { + app.Put(path, fcm) + fmt.Println("Loaded:", path) + }) +} + +func fcm(c *fiber.Ctx) error { + return c.SendString("") +} diff --git a/routes/api/user/param_userid/index.go b/routes/api/user/param_userid/index.go new file mode 100644 index 0000000..ec3c284 --- /dev/null +++ b/routes/api/user/param_userid/index.go @@ -0,0 +1,87 @@ +package param_userid + +import ( + "bdgrp_go/db" + "bdgrp_go/pbutil" + "bdgrp_go/routes" + "bdgrp_go/utils" + "fmt" + + "github.com/gofiber/fiber/v2" +) + +func init() { + path := routes.PathOf() + routes.Register(func(app *fiber.App) { + app.Get(path, GetUser) + fmt.Println("Loaded:", path) + }) +} + +func GetUser(c *fiber.Ctx) error { + userid := c.Params("userid") + + user := db.FindUser(userid) + + if user == nil { + return c.Status(404).SendString("") + } + + userId := fmt.Sprintf("%v", user["userId"]) + + data := map[string]any{ + "userRegistration": map[string]any{ + "userId": userId, + "hash": user["hash"], + "userName": user["userName"], + "clientVersion": user["clientVersion"], + "platform": user["platform"], + "deviceModel": user["deviceModel"], + "operatingSystem": user["operatingSystem"], + "birthMonth": user["birthMonth"], + "tutorialStatus": user["tutorialStatus"], + "introduction": user["introduction"], + "tutorialEndedAt": fmt.Sprintf("%v", user["tutorialEndedAt"]), + }, + "userGamedata": map[string]any{ + "userId": userId, + "rank": user["rank"], + "exp": user["exp"], + "coin": fmt.Sprintf("%v", user["coin"]), + "mainDeck": user["mainDeck"], + "paidStar": user["paidStar"], + "freeStar": user["freeStar"], + "seal": user["seal"], + "degree": user["degree"].([]any)[0], + "publishTotalDeckPowerFlg": user["publishTotalDeckPowerFlg"], + "publishBandRankFlg": user["publishBandRankFlg"], + "publishMusicClearedFlg": user["publishMusicClearedFlg"], + "publishMusicFullComboFlg": user["publishMusicFullComboFlg"], + "publishHighScoreRatingFlg": user["publishHighScoreRatingFlg"], + "pooledExp": fmt.Sprintf("%v", user["pooledExp"]), + "totalExp": fmt.Sprintf("%v", user["totalExp"]), + "nextExp": user["nextExp"], + "publishUpdatedAtFlg": user["publishUpdatedAtFlg"], + "userPaidStarRecallResponse": nil, + "startDashLoginBonusReceiveFlg": user["startDashLoginBonusReceiveFlg"], + "publishMusicAllPerfectFlg": user["publishMusicAllPerfectFlg"], + "publishDeckRankFlg": user["publishDeckRankFlg"], + "publishStageAchievementConditionsFlg": user["publishStageAchievementConditionsFlg"], + "publishStageFriendRankingFlg": user["publishStageFriendRankingFlg"], + "publishCharacterRankFlg": user["publishCharacterRankFlg"], + "loginDays": user["loginDays"], + }, + } + + encoded, err := pbutil.Encode("UserGetResponse", data) + if err != nil { + fmt.Println(err) + } + + encrypted, err := utils.Encrypt(encoded) + if err != nil { + fmt.Println(err) + } + + return c.Send(encrypted) +} diff --git a/routes/helper.go b/routes/helper.go index 19ec9bc..53c7e1d 100644 --- a/routes/helper.go +++ b/routes/helper.go @@ -8,11 +8,14 @@ import ( func PathOf() string { _, file, _, _ := runtime.Caller(1) - idx := strings.Index(file, "routes/") path := file[idx+len("routes"):] path = strings.TrimSuffix(path, ".go") + if strings.HasSuffix(path, "/index") { + path = strings.TrimSuffix(path, "index") + } + re := regexp.MustCompile(`param_(\w+)`) path = re.ReplaceAllString(path, ":$1")