Initial commit

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 13:57:10 +08:00
co-authored by Claude Opus 5
commit 8679200f41
1897 changed files with 257900 additions and 0 deletions
+101
View File
@@ -0,0 +1,101 @@
package ua
import (
"net/url"
"strings"
"91porn-server/common/constant"
"91porn-server/common/log"
"github.com/gin-gonic/gin"
)
type UA struct {
UserAgent string
DevID string //设备id 唯一标识
DevType string //设备类型 华为nova7
SysType string //pc
Ver string //1.0
BuildID string //
Mac string //
GlobalDevID string //全局唯一表示
Terminal string //终端 0-客户端;1-h5(ios)端;2-web端
IsH5 string
SystemVersion string
SystemName string
DeviceBrand string
DeviceModel string
SID string
}
func UAer(c *gin.Context) {
userAgent := c.GetHeader("X-User-Agent") //兼容H5 UserAgent
if userAgent == "" {
userAgent = c.Request.UserAgent()
}
if userAgent == "" {
log.Warn("user-agent empty")
return
}
ua := Parse(userAgent)
if sid := strings.TrimSpace(c.GetHeader("sid")); sid != "" {
ua.SID = sid
}
c.Set(constant.CtxUA, ua)
}
func Parse(userAgent string) UA {
var uastr string
ua := UA{}
decodeUa, err := url.QueryUnescape(userAgent)
if err != nil {
log.Warn("URLDecode user-agent error", log.Any("ua", userAgent))
uastr = userAgent
} else {
uastr = decodeUa
}
uas := strings.Split(uastr, ";")
for _, v := range uas {
vss := strings.SplitN(strings.TrimSpace(v), "=", 2)
if len(vss) < 2 {
log.Warn("user-agent miss", log.Any("ua", userAgent))
continue
}
key := strings.TrimSpace(vss[0])
value := strings.TrimSpace(vss[1])
switch key {
case "DevID":
ua.DevID = value
case "DevType":
ua.DevType = value
case "SysType":
ua.SysType = value
case "Ver":
ua.Ver = value
case "BuildID":
ua.BuildID = value
case "Mac":
ua.Mac = value
case "GlobalDevID":
ua.GlobalDevID = value
case "Terminal":
ua.Terminal = value
case "IsH5":
ua.IsH5 = value
case "SystemVersion":
ua.SystemVersion = value
case "SystemName":
ua.SystemName = value
case "DeviceBrand":
ua.DeviceBrand = value
case "DeviceModel", "device_model":
ua.DeviceModel = value
case "SID", "Sid", "sid":
ua.SID = value
default:
log.Warn("user-agent unknown", log.Any("key", key), log.Any("ua", userAgent))
}
}
ua.UserAgent = uastr
return ua
}
+89
View File
@@ -0,0 +1,89 @@
package ua
import (
"net/http/httptest"
"strings"
"testing"
"91porn-server/common/constant"
"github.com/gin-gonic/gin"
)
func TestUAerParsesSIDFromHeaderAndUserAgent(t *testing.T) {
gin.SetMode(gin.TestMode)
body := `{"devID":"91porn_google_3695e94c7226d787","qrCnt":"","devType":"lynx:36:id=CP1A.260305.018","sysType":"android","ver":"1.0.6","buildID":"com.noporn.newchatone_zero_six","devToken":"Qp6IluBGdByscQvXczvffmfC7YQxO6zm3Rr/A52FBpk=","cutInfos":""}`
req := httptest.NewRequest("POST", "/api/app/mine/login", strings.NewReader(body))
req.Header.Set("sid", "3a73a39a03cf450893f89909e31d4bea")
req.Header.Set("user-agent", "DevID%3D91porn_google_3695e94c7226d787%3BDevType%3Dlynx%3A36%3Aid%3DCP1A.260305.018%3BSysType%3Dandroid%3BVer%3D1.0.6%3BBuildID%3Dcom.noporn.newchatone_zero_six%3BDeviceBrand%3Dgoogle%3BSystemName%3DAndroid%3BSystemVersion%3D16")
req.Header.Set("x-api-key", "timestamp=1776140330;sign=f8c0476aa413e3e21ae6c8e2ad02b0c0f6af6d25;nonce=d8b1f060-6c3b-458b-b059-7ef87d2e9f79")
req.Header.Set("accept-encoding", "*")
req.Header.Set("device", "android")
req.Header.Set("host", "91pornht.remoces.com")
req.Header.Set("authorization", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0aW1lc3RhbXAiOjE3NzYxNDAyNTc3ODk4NjUyMDAsInR5cGUiOjAsInVpZCI6MzAzNzQzfQ.1tXpLY-FsDu9HzkT5SVVbMaOMtzkgLU5PBZzvHm-X0I")
req.Header.Set("api_version", "1.0.0")
req.Header.Set("content-type", "application/json;charset=UTF-8")
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = req
UAer(c)
value, ok := c.Get(constant.CtxUA)
if !ok {
t.Fatal("UAer did not set UA in context")
}
got, ok := value.(UA)
if !ok {
t.Fatalf("context UA type = %T, want ua.UA", value)
}
if got.SID != "3a73a39a03cf450893f89909e31d4bea" {
t.Fatalf("SID = %q, want header sid", got.SID)
}
if got.DevID != "91porn_google_3695e94c7226d787" {
t.Fatalf("DevID = %q", got.DevID)
}
if got.DevType != "lynx:36:id=CP1A.260305.018" {
t.Fatalf("DevType = %q", got.DevType)
}
if got.SysType != "android" {
t.Fatalf("SysType = %q", got.SysType)
}
if got.Ver != "1.0.6" {
t.Fatalf("Ver = %q", got.Ver)
}
if got.BuildID != "com.noporn.newchatone_zero_six" {
t.Fatalf("BuildID = %q", got.BuildID)
}
if got.DeviceBrand != "google" {
t.Fatalf("DeviceBrand = %q", got.DeviceBrand)
}
if got.SystemName != "Android" {
t.Fatalf("SystemName = %q", got.SystemName)
}
if got.SystemVersion != "16" {
t.Fatalf("SystemVersion = %q", got.SystemVersion)
}
}
func TestParseAcceptsSIDKeyVariants(t *testing.T) {
for _, tc := range []struct {
name string
userAgent string
want string
}{
{name: "sid", userAgent: "DevID=device;sid=lower", want: "lower"},
{name: "Sid", userAgent: "DevID=device;Sid=title", want: "title"},
{name: "SID", userAgent: "DevID=device;SID=upper", want: "upper"},
} {
t.Run(tc.name, func(t *testing.T) {
got := Parse(tc.userAgent)
if got.SID != tc.want {
t.Fatalf("SID = %q, want %q", got.SID, tc.want)
}
})
}
}