Overhaul [1/n]

Signed-off-by: Sean Du <do4suki@gmail.com>
This commit is contained in:
2026-01-29 02:42:28 +08:00
parent 989acd6ff1
commit c77241a883
2267 changed files with 7158 additions and 5583 deletions
+27
View File
@@ -0,0 +1,27 @@
package account
import (
"honoka-chan/internal/router"
"honoka-chan/internal/schema/ghome"
"honoka-chan/internal/session"
"github.com/gin-gonic/gin"
)
func active(ctx *gin.Context) {
ss := session.New(ctx)
defer ss.Finalize()
ss.Respond(ghome.ActiveResp{
Code: 0,
Msg: "ok",
Data: ghome.ActiveData{
Message: "ok",
Result: 0,
},
})
}
func init() {
router.AddHandler("v1", "POST", "/account/active", active)
}
@@ -0,0 +1,50 @@
package account
import (
"encoding/base64"
"encoding/json"
"honoka-chan/internal/router"
"honoka-chan/internal/schema/ghome"
"honoka-chan/internal/session"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-think/openssl"
)
func initialize(ctx *gin.Context) {
ss := session.New(ctx)
defer ss.Finalize()
initData := ghome.InitializeData{
BrandLogo: "http://gskd.sdo.com/ghome/ztc/logo/og/logo_xhdpi.png",
BrandName: "盛趣游戏",
ForceShowAgreement: 1,
GreportLogLevel: "off",
LogLevel: "off",
LoginButton: []string{"official"},
LoginIcon: []any{},
NeedFloatWindowPermission: 1,
NewDeviceIDServer: strings.ToUpper(openssl.Md5ToString(ss.GetDeviceID())),
ShowGuestConfirm: 1,
VoicetipButton: 1,
}
data, err := json.Marshal(initData)
if ss.CheckErr(err) {
return
}
encryptedData, err := openssl.Des3ECBEncrypt([]byte(data), ss.GetRandKey()[0:24], openssl.PKCS7_PADDING)
if ss.CheckErr(err) {
return
}
ss.Respond(ghome.InitializeResp{
Code: 0,
Msg: "ok",
Data: base64.StdEncoding.EncodeToString(encryptedData),
})
}
func init() {
router.AddHandler("v1", "POST", "/account/initialize", initialize)
}
+248
View File
@@ -0,0 +1,248 @@
package account
import (
"encoding/base64"
"encoding/json"
"fmt"
"honoka-chan/internal/model/user"
"honoka-chan/internal/router"
"honoka-chan/internal/schema/api/profile"
"honoka-chan/internal/schema/api/unit"
ghomeschema "honoka-chan/internal/schema/ghome"
"honoka-chan/internal/session"
honokautils "honoka-chan/pkg/utils"
"net/url"
"strconv"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/go-think/openssl"
)
func login(ctx *gin.Context) {
ss := session.New(ctx)
defer ss.Finalize()
data, err := ctx.GetRawData()
if ss.CheckErr(err) {
return
}
data, err = base64.StdEncoding.DecodeString(string(data))
if ss.CheckErr(err) {
return
}
randKey := ss.GetRandKey()
decryptedData, err := openssl.Des3ECBDecrypt(data, randKey[0:24], openssl.PKCS7_PADDING)
if ss.CheckErr(err) {
return
}
queryStr, _ := url.QueryUnescape(string(decryptedData))
params, _ := url.ParseQuery(queryStr)
phone, password := params.Get("phone"), params.Get("password")
var userID int
var pass, autoKey, ticket string
_, err = ss.UserEng.Table("users").Cols("password,autokey,ticket,user_id").
Where("phone = ?", phone).Get(&pass, &autoKey, &ticket, &userID)
if ss.CheckErr(err) {
return
}
loginData := ghomeschema.LoginData{}
loginCode := 0
loginMsg := "ok"
loginTime := time.Now().Unix()
if pass == "" {
// 未注册 - 自动注册
// 检查是否 userID 已经注册
userID, _ = checkUserID(ss, int(loginTime))
pass = openssl.Md5ToString(password)
autoKey = "AUTO" + strings.ToUpper(honokautils.RandomStr(32))
ticket = fmt.Sprintf("9999999%d%d", userID, userID)
userData := user.Users{
Phone: phone,
Password: pass,
Autokey: autoKey,
Ticket: ticket,
UserID: userID,
LastLoginTime: loginTime,
}
_, err = ss.UserEng.Table("users").Insert(&userData)
if ss.CheckErr(err) {
return
}
// 方便起见初始化 userid 和 key 一样
// 注意:user_key 表中的 key 是上文生成的用于登录的 userid,而 userid 则是用于 Authorize Token 生成用的
userKey := user.UserKey{
UserID: userID,
Key: userID,
}
_, err = ss.UserEng.Table("user_key").Insert(&userKey)
if ss.CheckErr(err) {
return
}
// 检查用户配置
exists, err := ss.UserEng.Table("user_pref").Where("user_id = ?", userID).Exist()
if ss.CheckErr(err) {
return
}
if !exists {
// 默认中心成员
var unitOwningUserID int
_, err = ss.MainEng.Table("common_unit_m").Cols("unit_owning_user_id").Where("unit_id = ?", 31).Get(&unitOwningUserID)
if ss.CheckErr(err) {
return
}
userPref := user.UserPref{
UserID: userID,
AwardID: 1, // 音乃木坂学生
BackgroundID: 1, // 初始背景
UnitOwningUserID: unitOwningUserID,
UserName: "音乃木坂学生",
UserLevel: 1,
UserDesc: "你好。",
InviteCode: strconv.Itoa(userID),
UpdateTime: time.Now().Unix(),
}
_, err = ss.UserEng.Table("user_pref").Insert(&userPref)
if ss.CheckErr(err) {
return
}
}
// 检查用户卡组配置
exists, err = ss.UserEng.Table("user_deck").Where("user_id = ?", userID).Exist()
if ss.CheckErr(err) {
return
}
if !exists {
// 默认队伍
userDeck := unit.UserDeckData{
DeckID: 1,
MainFlag: 1,
DeckName: "队伍A",
UserID: userID,
InsertDate: time.Now().Unix(),
}
_, err = ss.UserEng.Table("user_deck").Insert(&userDeck)
userDeckID := userDeck.ID
// 默认卡组 - 仆光
unitID := []int{}
err = ss.MainEng.Table("unit_m").Cols("unit_id").Where("album_series_id = ?", 615).Find(&unitID)
if ss.CheckErr(err) {
return
}
unitData := []profile.UnitData{}
err = ss.MainEng.Table("common_unit_m").In("unit_id", unitID).Find(&unitData)
if ss.CheckErr(err) {
return
}
position := 1
for _, u := range unitData {
unitDeckData := unit.UnitDeckData{
UserDeckID: userDeckID,
UnitOwningUserID: u.UnitOwningUserID,
UnitID: u.UnitID,
Position: position,
Level: 100,
LevelLimitID: 1,
DisplayRank: 2,
Love: 1000,
UnitSkillLevel: 8,
IsRankMax: true,
IsLoveMax: true,
IsLevelMax: true,
IsSigned: u.IsSigned,
BeforeLove: 1000,
MaxLove: 1000,
InsertData: time.Now().Unix(),
}
_, err = ss.UserEng.Table("user_deck_unit").Insert(&unitDeckData)
if ss.CheckErr(err) {
return
}
position++
}
}
loginData.Autokey = autoKey
loginData.HasRealInfo = 1
loginData.Message = "ok"
loginData.RealInfoForce = 1
loginData.Ticket = ticket
loginData.UserAttribute = "0"
loginData.UserID = userID
} else {
// 已注册 - 检查密码
if pass != openssl.Md5ToString(password) {
loginCode = 31
loginMsg = "账号不存在或者密码有误!"
} else {
userData := user.Users{
Autokey: autoKey,
Ticket: ticket,
LastLoginTime: loginTime,
}
_, err = ss.UserEng.Table("users").Where("user_id = ?", userID).Update(&userData)
if ss.CheckErr(err) {
return
}
loginData.Autokey = autoKey // 注意:更换设备(deviceId 发生变化)应重新生成 autokey
loginData.HasRealInfo = 1
loginData.Message = "ok"
loginData.RealInfoForce = 1
loginData.Ticket = fmt.Sprintf("9999999%d%d", userID, loginTime) // 实际登录用的密码(每次登录都会重新生成新的)
loginData.UserAttribute = "0"
loginData.UserID = userID // 实际登录用的账号
}
}
data, err = json.Marshal(loginData)
if ss.CheckErr(err) {
return
}
encryptedData, err := openssl.Des3ECBEncrypt([]byte(data), randKey[0:24], openssl.PKCS7_PADDING)
if ss.CheckErr(err) {
return
}
ss.Respond(ghomeschema.LoginResp{
Code: loginCode,
Msg: loginMsg,
Data: base64.StdEncoding.EncodeToString(encryptedData),
})
}
func checkUserID(ss *session.Session, userID int) (int, bool) {
exist, err := ss.UserEng.Table("users").Where("user_id = ?", userID).Exist()
if ss.CheckErr(err) {
return 0, false
}
if exist {
userID = int(time.Now().Unix())
return checkUserID(ss, userID)
}
return userID, true
}
func init() {
router.AddHandler("v1", "POST", "/account/login", login)
}
@@ -0,0 +1,83 @@
package account
import (
"encoding/base64"
"encoding/json"
"honoka-chan/internal/router"
"honoka-chan/internal/schema/ghome"
"honoka-chan/internal/session"
"net/url"
"github.com/gin-gonic/gin"
"github.com/go-think/openssl"
)
func loginAuto(ctx *gin.Context) {
ss := session.New(ctx)
defer ss.Finalize()
data, err := ctx.GetRawData()
if ss.CheckErr(err) {
return
}
data, err = base64.StdEncoding.DecodeString(string(data))
if ss.CheckErr(err) {
return
}
randKey := ss.GetRandKey()
decryptedData, err := openssl.Des3ECBDecrypt(data, randKey[0:24], openssl.PKCS7_PADDING)
if ss.CheckErr(err) {
return
}
queryStr, _ := url.QueryUnescape(string(decryptedData))
params, _ := url.ParseQuery(queryStr)
autoKey := params.Get("autokey")
var uid, ticket string
_, err = ss.UserEng.Table("users").Cols("user_id,ticket").Where("autokey = ?", autoKey).Get(&uid, &ticket)
if ss.CheckErr(err) {
return
}
loginAutoData := ghome.LoginAutoData{}
loginAutoCode := 0
loginAutoMsg := "ok"
if uid != "" {
loginAutoData = ghome.LoginAutoData{
Result: loginAutoCode,
Message: loginAutoMsg,
Autokey: autoKey,
UserId: uid,
Ticket: ticket,
}
} else {
loginAutoCode = 31
loginAutoMsg = "账号不存在或者登陆状态已过期!"
loginAutoData = ghome.LoginAutoData{
Result: loginAutoCode,
Message: loginAutoMsg,
}
}
data, err = json.Marshal(loginAutoData)
if ss.CheckErr(err) {
return
}
encryptedData, err := openssl.Des3ECBEncrypt([]byte(data), randKey[0:24], openssl.PKCS7_PADDING)
if ss.CheckErr(err) {
return
}
ss.Respond(ghome.LoginAutoResp{
Code: loginAutoCode,
Msg: loginAutoMsg,
Data: base64.StdEncoding.EncodeToString(encryptedData),
})
}
func init() {
router.AddHandler("v1", "POST", "/account/loginauto", loginAuto)
}
@@ -0,0 +1,33 @@
package account
import (
"encoding/base64"
"honoka-chan/internal/router"
"honoka-chan/internal/schema/ghome"
"honoka-chan/internal/session"
"github.com/gin-gonic/gin"
"github.com/go-think/openssl"
)
func reportRole(ctx *gin.Context) {
ss := session.New(ctx)
defer ss.Finalize()
randKey := ss.GetRandKey()
token := `{"message":"ok"}`
encryptedToken, err := openssl.Des3ECBEncrypt([]byte(token), randKey[0:24], openssl.PKCS7_PADDING)
if ss.CheckErr(err) {
return
}
ss.Respond(ghome.ReportRoleResp{
Code: 0,
Msg: "ok",
Data: base64.StdEncoding.EncodeToString(encryptedToken),
})
}
func init() {
router.AddHandler("v1", "POST", "/account/reportRole", reportRole)
}
+33
View File
@@ -0,0 +1,33 @@
package basic
import (
"encoding/json"
"honoka-chan/internal/router"
"honoka-chan/internal/schema/ghome"
"honoka-chan/internal/session"
"github.com/gin-gonic/gin"
)
func getCode(ctx *gin.Context) {
ss := session.New(ctx)
defer ss.Finalize()
codeArray := `{"codeArray":[{"btntext":"好的","code":"-10264022","msg_from":2,"text":"","title":"短信验证码被阻止","type":1},{"btntext":"","code":"-10869623","msg_from":2,"text":"","title":"网络连接失败,无法一键登录","type":2},{"btntext":"","code":"10298300","msg_from":2,"text":"","title":"","type":3},{"btntext":"","code":"10298311","msg_from":2,"text":"","title":"","type":3},{"btntext":"","code":"10298312","msg_from":2,"text":"","title":"","type":3},{"btntext":"","code":"10298313","msg_from":2,"text":"","title":"","type":1},{"btntext":"","code":"10298321","msg_from":2,"text":"","title":"","type":3},{"btntext":"","code":"10298322","msg_from":2,"text":"","title":"","type":3}],"codeVersion":"1.0.5"}`
getCodeData := map[string]any{}
err := json.Unmarshal([]byte(codeArray), &getCodeData)
if ss.CheckErr(err) {
return
}
ss.Respond(ghome.GetCodeResp{
Code: 0,
Msg: "ok",
Data: getCodeData,
})
}
func init() {
router.AddHandler("v1", "GET", "/basic/getcode", getCode)
router.AddHandler("v1", "POST", "/basic/getcode", getCode)
}
@@ -0,0 +1,29 @@
package basic
import (
"honoka-chan/internal/router"
"honoka-chan/internal/schema/ghome"
"honoka-chan/internal/session"
"github.com/gin-gonic/gin"
)
func getProductList(ctx *gin.Context) {
ss := session.New(ctx)
defer ss.Finalize()
getProductListData := ghome.GetProductListData{
Message: []string{},
Result: 0,
}
ss.Respond(ghome.GetProductListResp{
Code: 1,
Msg: "ok",
Data: getProductListData,
})
}
func init() {
router.AddHandler("v1", "POST", "/basic/getProductList", getProductList)
}
+60
View File
@@ -0,0 +1,60 @@
package basic
import (
"encoding/base64"
"fmt"
"honoka-chan/internal/router"
"honoka-chan/internal/schema/ghome"
"honoka-chan/internal/session"
"honoka-chan/pkg/db"
"honoka-chan/pkg/encrypt"
honokautils "honoka-chan/pkg/utils"
"net/url"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-think/openssl"
)
func handshake(ctx *gin.Context) {
ss := session.New(ctx)
defer ss.Finalize()
data, err := ctx.GetRawData()
if ss.CheckErr(err) {
return
}
data, err = base64.StdEncoding.DecodeString(string(data))
if ss.CheckErr(err) {
return
}
decryptedData := encrypt.RSADecrypt(data)
params, _ := url.ParseQuery(string(decryptedData))
randKey := []byte(params.Get("randkey"))
deviceID := ss.GetDeviceID()
err = db.Ldb.Set([]byte(deviceID), randKey)
if ss.CheckErr(err) {
return
}
token := fmt.Sprintf(`{"message":"ok","result":0,"token":"%s"}`, strings.ToUpper(honokautils.RandomStr(33)))
encryptedToken, err := openssl.Des3ECBEncrypt([]byte(token), randKey[0:24], openssl.PKCS7_PADDING)
if ss.CheckErr(err) {
return
}
ss.Respond(ghome.HandshakeResp{
Code: 0,
Msg: "ok",
Data: base64.StdEncoding.EncodeToString(encryptedToken),
})
}
func init() {
router.AddHandler("v1", "POST", "/basic/handshake", handshake)
}
+26
View File
@@ -0,0 +1,26 @@
package basic
import (
"honoka-chan/internal/router"
"honoka-chan/internal/schema/ghome"
"honoka-chan/internal/session"
"github.com/gin-gonic/gin"
)
func loginArea(ctx *gin.Context) {
ss := session.New(ctx)
defer ss.Finalize()
ss.Respond(ghome.LoginAreaResp{
Code: 0,
Msg: "ok",
Data: ghome.LoginAreaData{
UserID: ctx.PostForm("userid"),
},
})
}
func init() {
router.AddHandler("v1", "POST", "/basic/loginarea", loginArea)
}
+45
View File
@@ -0,0 +1,45 @@
package basic
import (
"encoding/base64"
"encoding/pem"
"honoka-chan/config"
"honoka-chan/internal/router"
"honoka-chan/internal/schema/ghome"
"honoka-chan/internal/session"
honokautils "honoka-chan/pkg/utils"
"github.com/gin-gonic/gin"
)
func publicKey(ctx *gin.Context) {
ss := session.New(ctx)
defer ss.Finalize()
publicKeyCode := 0
publicKeyMsg := "ok"
publicKeyData := ghome.PublicKeyData{
Result: publicKeyCode,
Message: publicKeyMsg,
}
publicKey := honokautils.ReadAllText(config.PublicKeyPath)
block, _ := pem.Decode([]byte(publicKey))
if block == nil || block.Type != "PUBLIC KEY" {
publicKeyMsg = "公钥读取失败!"
publicKeyCode = 31
} else {
publicKeyData.Key = base64.StdEncoding.EncodeToString(block.Bytes)
publicKeyData.Method = "rsa"
}
ss.Respond(ghome.PublicKeyResp{
Code: publicKeyCode,
Msg: publicKeyMsg,
Data: publicKeyData,
})
}
func init() {
router.AddHandler("v1", "POST", "/basic/publickey", publicKey)
}
+8
View File
@@ -0,0 +1,8 @@
package ghome
import (
_ "honoka-chan/internal/handler/ghome/account"
_ "honoka-chan/internal/handler/ghome/basic"
_ "honoka-chan/internal/handler/ghome/guest"
_ "honoka-chan/internal/handler/ghome/misc"
)
+29
View File
@@ -0,0 +1,29 @@
package guest
import (
"honoka-chan/internal/router"
"honoka-chan/internal/schema/ghome"
"honoka-chan/internal/session"
"github.com/gin-gonic/gin"
)
func status(ctx *gin.Context) {
ss := session.New(ctx)
defer ss.Finalize()
ss.Respond(ghome.GuestStatusResp{
Code: 0,
Msg: "ok",
Data: ghome.GuestStatusData{
Disablead: 1,
Loginswitch: 1,
Message: "ok",
Result: 0,
},
})
}
func init() {
router.AddHandler("v1", "POST", "/guest/status", status)
}
+25
View File
@@ -0,0 +1,25 @@
package misc
import (
"honoka-chan/internal/router"
"honoka-chan/internal/schema/ghome"
"honoka-chan/internal/session"
"github.com/gin-gonic/gin"
)
func agreement(ctx *gin.Context) {
ss := session.New(ctx)
defer ss.Finalize()
ss.Respond(ghome.AgreementResp{
ReturnCode: 0,
ErrorType: 0,
ReturnMessage: "",
Data: ghome.AgreementData{},
})
}
func init() {
router.AddHandler("/", "GET", "/agreement/all", agreement)
}
@@ -0,0 +1,26 @@
package misc
import (
"honoka-chan/internal/router"
"honoka-chan/internal/schema/ghome"
"honoka-chan/internal/session"
"github.com/gin-gonic/gin"
)
func appReport(ctx *gin.Context) {
ss := session.New(ctx)
defer ss.Finalize()
ss.Respond(ghome.AppReportResp{
Code: 0,
Msg: "",
Data: ghome.AppReportData{
NeedReport: 0,
},
})
}
func init() {
router.AddHandler("/", "GET", "/integration/appReport/initialize", appReport)
}
+16
View File
@@ -0,0 +1,16 @@
package misc
import (
"honoka-chan/internal/router"
"net/http"
"github.com/gin-gonic/gin"
)
func report(ctx *gin.Context) {
ctx.Status(http.StatusOK)
}
func init() {
router.AddHandler("/", "POST", "/report/ge/app", report)
}