mirror of
https://github.com/fumiama/tienyik.git
synced 2026-06-04 23:10:26 +08:00
feat: add more apis
This commit is contained in:
@@ -2,8 +2,14 @@ package auth
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/fumiama/tienyik/internal/hcli"
|
"github.com/fumiama/tienyik"
|
||||||
|
"github.com/fumiama/tienyik/hcli"
|
||||||
|
"github.com/fumiama/tienyik/internal/horm"
|
||||||
"github.com/fumiama/tienyik/internal/hson"
|
"github.com/fumiama/tienyik/internal/hson"
|
||||||
"github.com/fumiama/tienyik/internal/textio"
|
"github.com/fumiama/tienyik/internal/textio"
|
||||||
)
|
)
|
||||||
@@ -19,11 +25,126 @@ type ResponseNegotiationEncKey struct {
|
|||||||
EncKey string `json:"encKey"`
|
EncKey string `json:"encKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ResponseNegotiationEncKeyData struct {
|
||||||
|
EValue string `json:"evalue"`
|
||||||
|
EID string `json:"eid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ResponseNegotiationEncKey) Unwrap(tyr *tienyik.RSA) (*ResponseNegotiationEncKeyData, error) {
|
||||||
|
v, err := base64.StdEncoding.DecodeString(r.EncKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
aesk, err := tyr.Decrypt(v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err = base64.StdEncoding.DecodeString(r.EncData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
v, err = tienyik.NewAES(aesk).Decrypt(v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var rsp ResponseNegotiationEncKeyData
|
||||||
|
err = json.Unmarshal(v, &rsp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &rsp, nil
|
||||||
|
}
|
||||||
|
|
||||||
func NegotiationEncKey(r *RequestNegotiationEncKey) (*ResponseNegotiationEncKey, error) {
|
func NegotiationEncKey(r *RequestNegotiationEncKey) (*ResponseNegotiationEncKey, error) {
|
||||||
resp, err := hcli.Post(textio.API(), bytes.NewReader(hson.Marshal(nil, r)))
|
resp, err := hcli.NoClient.Post(
|
||||||
|
textio.API(), textio.ContenTypeJSON,
|
||||||
|
bytes.NewReader(hson.Marshal(nil, r)),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
return hson.Unmarshal[*ResponseNegotiationEncKey](nil, resp.Body)
|
return hson.Unmarshal[*ResponseNegotiationEncKey](nil, resp.Body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ResponseGenChallengeData struct {
|
||||||
|
EffectiveSeconds int `json:"effectiveSeconds"`
|
||||||
|
ChallengeID string `json:"challengeId"`
|
||||||
|
ChallengeCode string `json:"challengeCode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenChallengeData(tya *tienyik.AES, cli *hcli.Client) (*ResponseGenChallengeData, error) {
|
||||||
|
resp, err := cli.Post(
|
||||||
|
textio.API(), textio.ContenTypeJSON,
|
||||||
|
strings.NewReader("{}"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
return hson.Unmarshal[*ResponseGenChallengeData](tya, resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RequestLogin struct {
|
||||||
|
UserAccount string `form:"userAccount"`
|
||||||
|
Password string `form:"password"`
|
||||||
|
SHA256Password string `form:"sha256Password"`
|
||||||
|
ChallengeID string `form:"challengeId"`
|
||||||
|
DeviceCode string `form:"deviceCode"`
|
||||||
|
DeviceName string `form:"deviceName"`
|
||||||
|
DeviceType string `form:"deviceType"`
|
||||||
|
DeviceModel string `form:"deviceModel"`
|
||||||
|
AppVersion string `form:"appVersion"`
|
||||||
|
SysVersion string `form:"sysVersion"`
|
||||||
|
ClientVersion string `form:"clientVersion"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseLogin struct {
|
||||||
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
UserID int64 `json:"userId"`
|
||||||
|
UserEid string `json:"userEid"`
|
||||||
|
UserName string `json:"userName"`
|
||||||
|
UserAccount string `json:"userAccount"`
|
||||||
|
Email *string `json:"email"`
|
||||||
|
Mobilephone string `json:"mobilephone"`
|
||||||
|
TenantID int64 `json:"tenantId"`
|
||||||
|
SecretKey string `json:"secretKey"`
|
||||||
|
DeviceType string `json:"deviceType"`
|
||||||
|
TenantName string `json:"tenantName"`
|
||||||
|
BondedDevice bool `json:"bondedDevice"`
|
||||||
|
RealNameStatus int64 `json:"realNameStatus"`
|
||||||
|
HasPassword int64 `json:"hasPassword"`
|
||||||
|
PID *string `json:"pid"`
|
||||||
|
NeedSmsValidate bool `json:"needSmsValidate"`
|
||||||
|
NeedUpdatePassword bool `json:"needUpdatePassword"`
|
||||||
|
ForceUpdateInitialPwd bool `json:"forceUpdateInitialPwd"`
|
||||||
|
AdminUser bool `json:"adminUser"`
|
||||||
|
LoginNotify *string `json:"loginNotify"`
|
||||||
|
CommonLoginReqHeader string `json:"commonLoginReqHeader"`
|
||||||
|
RecordSn bool `json:"recordSn"`
|
||||||
|
Token *string `json:"token"`
|
||||||
|
TwoFaValidateType *string `json:"twoFaValidateType"`
|
||||||
|
Random *string `json:"random"`
|
||||||
|
NeedBindVirtualMfa *bool `json:"needBindVirtualMfa"`
|
||||||
|
Tryout *string `json:"tryout"`
|
||||||
|
CtqEncID *string `json:"ctqEncId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ResponseLogin) SetClient(cli *hcli.Client) {
|
||||||
|
cli.Tenantid = strconv.FormatInt(r.TenantID, 10)
|
||||||
|
cli.Usereid = r.UserEid
|
||||||
|
}
|
||||||
|
|
||||||
|
func Login(tya *tienyik.AES, cli *hcli.Client, r *RequestLogin) (*ResponseLogin, error) {
|
||||||
|
resp, err := cli.Post(
|
||||||
|
textio.API(), textio.ContenTypeForm,
|
||||||
|
bytes.NewReader(horm.Marshal(tya, r)),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
return hson.Unmarshal[*ResponseLogin](tya, resp.Body)
|
||||||
|
}
|
||||||
|
|||||||
50
api/auth/client/qrCode.go
Normal file
50
api/auth/client/qrCode.go
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/fumiama/tienyik"
|
||||||
|
"github.com/fumiama/tienyik/hcli"
|
||||||
|
"github.com/fumiama/tienyik/internal/hson"
|
||||||
|
"github.com/fumiama/tienyik/internal/textio"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ResponseGenData struct {
|
||||||
|
QrCodeId string `json:"qrCodeId"`
|
||||||
|
QrCodeEndpoint *string `json:"qrCodeEndpoint"`
|
||||||
|
ServerHost string `json:"serverHost"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenData(tya *tienyik.AES, cli *hcli.Client) (*ResponseGenData, error) {
|
||||||
|
resp, err := cli.Post(textio.API(), textio.ContenTypeForm, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
return hson.Unmarshal[*ResponseGenData](tya, resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseGetStatusData struct {
|
||||||
|
CodeId string `json:"codeId"`
|
||||||
|
CodeStatus string `json:"codeStatus"`
|
||||||
|
LoginToken *string `json:"loginToken"`
|
||||||
|
ClientCustomData *string `json:"clientCustomData"`
|
||||||
|
SupplementData *string `json:"supplementData"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetStatus(tya *tienyik.AES, cli *hcli.Client, qrCodeId string) (*ResponseGetStatusData, error) {
|
||||||
|
u, err := url.Parse(textio.API())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
q := u.Query()
|
||||||
|
q.Set("qrCodeId", qrCodeId)
|
||||||
|
u.RawQuery = tya.EUrlParams(q)
|
||||||
|
|
||||||
|
resp, err := cli.Get(u.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
return hson.Unmarshal[*ResponseGetStatusData](tya, resp.Body)
|
||||||
|
}
|
||||||
18
api/auth/client/qrCode_test.go
Normal file
18
api/auth/client/qrCode_test.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/fumiama/tienyik/hcli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGenData(t *testing.T) {
|
||||||
|
r, err := GenData(nil, hcli.NewClient())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(r)
|
||||||
|
if r.QrCodeId == "" {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@ package auth
|
|||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"encoding/base64"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/fumiama/tienyik"
|
"github.com/fumiama/tienyik"
|
||||||
@@ -32,23 +31,8 @@ func TestNegotiationEncKey(t *testing.T) {
|
|||||||
t.Logf("EncData: %s", r.EncData)
|
t.Logf("EncData: %s", r.EncData)
|
||||||
t.Logf("EncKey: %s", r.EncKey)
|
t.Logf("EncKey: %s", r.EncKey)
|
||||||
|
|
||||||
v, err := base64.StdEncoding.DecodeString(r.EncKey)
|
_, err = r.Unwrap(tyr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
aesk, err := tyr.Decrypt(v)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
t.Log(string(aesk))
|
|
||||||
|
|
||||||
v, err = base64.StdEncoding.DecodeString(r.EncData)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
v, err = tienyik.NewAES([]byte(aesk)).Decrypt(v)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
t.Log(string(v))
|
|
||||||
}
|
}
|
||||||
|
|||||||
32
api/cdserv/client.go
Normal file
32
api/cdserv/client.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package cdserv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/fumiama/tienyik/hcli"
|
||||||
|
"github.com/fumiama/tienyik/internal/hson"
|
||||||
|
"github.com/fumiama/tienyik/internal/textio"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GlobalSwitches struct {
|
||||||
|
BodyMsgEType []string `json:"bodyMsgEType"`
|
||||||
|
PasswordRulesEnable bool `json:"passwordRulesEnable"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseGetServData struct {
|
||||||
|
GlobalSwitches GlobalSwitches `json:"globalSwitches"`
|
||||||
|
ServerNodeId string `json:"serverNodeId"`
|
||||||
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
NetAccessType int `json:"netAccessType"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ResponseGetServData) SetClient(cli *hcli.Client) {
|
||||||
|
cli.Servernode = r.ServerNodeId
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetServData() (*ResponseGetServData, error) {
|
||||||
|
resp, err := hcli.NoClient.Get(textio.API())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
return hson.Unmarshal[*ResponseGetServData](nil, resp.Body)
|
||||||
|
}
|
||||||
14
api/cdserv/client_test.go
Normal file
14
api/cdserv/client_test.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package cdserv
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestGetServData(t *testing.T) {
|
||||||
|
r, err := GetServData()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(r)
|
||||||
|
if len(r.GlobalSwitches.BodyMsgEType) == 0 {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
31
cfg.go
Normal file
31
cfg.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package tienyik
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const Version = "103010001"
|
||||||
|
|
||||||
|
const (
|
||||||
|
DeviceTypePC = "25"
|
||||||
|
DeviceTypeMAC = "45"
|
||||||
|
DeviceTypeWEB = "60"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AppModelTOC = "1"
|
||||||
|
AppModelTOB = "2"
|
||||||
|
AppModelPHONE = "3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewDeviceCode() string {
|
||||||
|
sb := &strings.Builder{}
|
||||||
|
sb.WriteString("web_")
|
||||||
|
enc := base64.NewEncoder(base64.RawURLEncoding, sb)
|
||||||
|
io.CopyN(enc, rand.Reader, (32/6+1)*8)
|
||||||
|
enc.Close()
|
||||||
|
return sb.String()[:4+32]
|
||||||
|
}
|
||||||
7
go.mod
7
go.mod
@@ -5,10 +5,11 @@ go 1.24.4
|
|||||||
require (
|
require (
|
||||||
github.com/fumiama/go-base16384 v1.7.1
|
github.com/fumiama/go-base16384 v1.7.1
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
|
golang.org/x/net v0.28.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
|
github.com/stretchr/testify v1.8.0 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/sys v0.23.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
golang.org/x/text v0.17.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
12
go.sum
12
go.sum
@@ -8,13 +8,19 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
|||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||||
|
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
|
||||||
|
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||||
|
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|||||||
80
hcli/cli.go
Normal file
80
hcli/cli.go
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
package hcli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
base14 "github.com/fumiama/go-base16384"
|
||||||
|
"github.com/fumiama/tienyik"
|
||||||
|
"golang.org/x/net/http2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var NoClient = (*Client)(nil)
|
||||||
|
|
||||||
|
// DefaultClient is the default HTTP2 client.
|
||||||
|
var DefaultClient = http.Client{
|
||||||
|
Transport: &http2.Transport{},
|
||||||
|
}
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
rcnt uintptr
|
||||||
|
Appmodel string
|
||||||
|
Devicecode string
|
||||||
|
Devicetype string
|
||||||
|
Servernode string
|
||||||
|
Tenantid string
|
||||||
|
Usereid string
|
||||||
|
Version string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient() *Client {
|
||||||
|
return &Client{
|
||||||
|
Appmodel: tienyik.AppModelTOB,
|
||||||
|
Devicecode: tienyik.NewDeviceCode(),
|
||||||
|
Devicetype: tienyik.DeviceTypeWEB,
|
||||||
|
Version: tienyik.Version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) setHeaders(req *http.Request) {
|
||||||
|
if c == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v := reflect.ValueOf(c).Elem()
|
||||||
|
t := v.Type()
|
||||||
|
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
field := t.Field(i)
|
||||||
|
if !field.IsExported() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldValue := v.Field(i)
|
||||||
|
|
||||||
|
if fieldValue.Kind() == reflect.String {
|
||||||
|
req.Header.Set(
|
||||||
|
base14.DecodeString("廝呲舀㴄")+field.Name,
|
||||||
|
fieldValue.String(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Appmodel != "" {
|
||||||
|
ts := time.Now().UnixMilli()
|
||||||
|
timestamp := strconv.FormatInt(ts, 10)
|
||||||
|
requestid := strconv.FormatUint(
|
||||||
|
uint64(atomic.AddUintptr(&c.rcnt, 1))+uint64(ts), 10,
|
||||||
|
)
|
||||||
|
|
||||||
|
req.Header.Set(base14.DecodeString("廝呲草獱歙攷徥爀㴆"), requestid)
|
||||||
|
req.Header.Set(base14.DecodeString("廝呲荑睭杜蕆厵縀㴆"), timestamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Servernode != "" {
|
||||||
|
//TODO: gensign
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,10 +7,12 @@ import (
|
|||||||
base14 "github.com/fumiama/go-base16384"
|
base14 "github.com/fumiama/go-base16384"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setCommonHeaders(req *http.Request) {
|
func setCommonHeaders(req *http.Request, contentType string) {
|
||||||
req.Header.Set("Accept", "application/json")
|
req.Header.Set("Accept", "application/json")
|
||||||
req.Header.Set("Pragma", "no-cache")
|
req.Header.Set("Pragma", "no-cache")
|
||||||
req.Header.Set("Content-Type", "application/json")
|
if contentType != "" {
|
||||||
|
req.Header.Set("Content-Type", contentType)
|
||||||
|
}
|
||||||
req.Header.Set("Origin", base14.DecodeString("栝啇俌蠯姜吲融艹歛烦宸㴅"))
|
req.Header.Set("Origin", base14.DecodeString("栝啇俌蠯姜吲融艹歛烦宸㴅"))
|
||||||
req.Header.Set("Referer", base14.DecodeString("栝啇俌蠯姜吲融艹歛烦宸紀㴆"))
|
req.Header.Set("Referer", base14.DecodeString("栝啇俌蠯姜吲融艹歛烦宸紀㴆"))
|
||||||
req.Header.Set(
|
req.Header.Set(
|
||||||
@@ -19,47 +21,52 @@ func setCommonHeaders(req *http.Request) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Get(path string) (resp *http.Response, err error) {
|
func (cli *Client) Get(path string) (resp *http.Response, err error) {
|
||||||
req, err := http.NewRequest(http.MethodGet, ep(path), nil)
|
req, err := http.NewRequest(http.MethodGet, ep(path), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
setCommonHeaders(req)
|
setCommonHeaders(req, "")
|
||||||
return http.DefaultClient.Do(req)
|
cli.setHeaders(req)
|
||||||
|
return DefaultClient.Do(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Post(path string, body io.Reader) (resp *http.Response, err error) {
|
func (cli *Client) Post(path string, contentType string, body io.Reader) (resp *http.Response, err error) {
|
||||||
req, err := http.NewRequest(http.MethodPost, ep(path), body)
|
req, err := http.NewRequest(http.MethodPost, ep(path), body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
setCommonHeaders(req)
|
setCommonHeaders(req, contentType)
|
||||||
return http.DefaultClient.Do(req)
|
cli.setHeaders(req)
|
||||||
|
return DefaultClient.Do(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Put(path string, body io.Reader) (resp *http.Response, err error) {
|
func (cli *Client) Put(path string, contentType string, body io.Reader) (resp *http.Response, err error) {
|
||||||
req, err := http.NewRequest(http.MethodPut, ep(path), body)
|
req, err := http.NewRequest(http.MethodPut, ep(path), body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
setCommonHeaders(req)
|
setCommonHeaders(req, contentType)
|
||||||
return http.DefaultClient.Do(req)
|
cli.setHeaders(req)
|
||||||
|
return DefaultClient.Do(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Delete(path string) (resp *http.Response, err error) {
|
func (cli *Client) Delete(path string) (resp *http.Response, err error) {
|
||||||
req, err := http.NewRequest(http.MethodDelete, ep(path), nil)
|
req, err := http.NewRequest(http.MethodDelete, ep(path), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
setCommonHeaders(req)
|
setCommonHeaders(req, "")
|
||||||
return http.DefaultClient.Do(req)
|
cli.setHeaders(req)
|
||||||
|
return DefaultClient.Do(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Patch(path string, body io.Reader) (resp *http.Response, err error) {
|
func (cli *Client) Patch(path string, contentType string, body io.Reader) (resp *http.Response, err error) {
|
||||||
req, err := http.NewRequest(http.MethodPatch, ep(path), body)
|
req, err := http.NewRequest(http.MethodPatch, ep(path), body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
setCommonHeaders(req)
|
setCommonHeaders(req, contentType)
|
||||||
return http.DefaultClient.Do(req)
|
cli.setHeaders(req)
|
||||||
|
return DefaultClient.Do(req)
|
||||||
}
|
}
|
||||||
40
http.go
Normal file
40
http.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package tienyik
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/fumiama/tienyik/internal/textio"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (tya *AES) EUrlParams(params url.Values) string {
|
||||||
|
if tya == nil {
|
||||||
|
return params.Encode()
|
||||||
|
}
|
||||||
|
return url.Values{
|
||||||
|
textio.FuncName(1, true): {textio.BytesToString(tya.Encrypt(
|
||||||
|
textio.StringToBytes(params.Encode()),
|
||||||
|
))},
|
||||||
|
}.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tya *AES) ParseQuery(eparams string) (url.Values, error) {
|
||||||
|
if tya == nil {
|
||||||
|
return url.ParseQuery(eparams)
|
||||||
|
}
|
||||||
|
q, err := url.ParseQuery(eparams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(q) != 1 {
|
||||||
|
return nil, errors.New("len(q) must be 1")
|
||||||
|
}
|
||||||
|
for _, v := range q {
|
||||||
|
dec, err := tya.Decrypt(textio.StringToBytes(v[0]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return url.ParseQuery(textio.BytesToString(dec))
|
||||||
|
}
|
||||||
|
panic("unexpected")
|
||||||
|
}
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
package textio
|
package tienyik
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/fumiama/tienyik"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEUrlParams(t *testing.T) {
|
func TestEUrlParams(t *testing.T) {
|
||||||
@@ -21,11 +19,12 @@ func TestEUrlParams(t *testing.T) {
|
|||||||
binary.BigEndian.PutUint32(key[i*4:(i+1)*4], k)
|
binary.BigEndian.PutUint32(key[i*4:(i+1)*4], k)
|
||||||
}
|
}
|
||||||
t.Log(string(key[:])) // wxdispbis8txuueo26ffs2veqs18sism
|
t.Log(string(key[:])) // wxdispbis8txuueo26ffs2veqs18sism
|
||||||
tya := tienyik.NewAES(key[:])
|
tya := NewAES(key[:])
|
||||||
params := EUrlParams(&tya, url.Values{
|
params := tya.EUrlParams(url.Values{
|
||||||
"moduleCode": {"DESKTOP_MSGCENTER"},
|
"moduleCode": {"DESKTOP_MSGCENTER"},
|
||||||
})
|
})
|
||||||
q, err := ParseQuery(&tya, params)
|
t.Log(params)
|
||||||
|
q, err := tya.ParseQuery(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -48,7 +47,7 @@ func TestEUrlParamsMultiple(t *testing.T) {
|
|||||||
for i, k := range rawkey {
|
for i, k := range rawkey {
|
||||||
binary.BigEndian.PutUint32(key[i*4:(i+1)*4], k)
|
binary.BigEndian.PutUint32(key[i*4:(i+1)*4], k)
|
||||||
}
|
}
|
||||||
tya := tienyik.NewAES(key[:])
|
tya := NewAES(key[:])
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -103,8 +102,8 @@ func TestEUrlParamsMultiple(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
params := EUrlParams(&tya, tc.params)
|
params := tya.EUrlParams(tc.params)
|
||||||
q, err := ParseQuery(&tya, params)
|
q, err := tya.ParseQuery(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
35
internal/horm/req.go
Normal file
35
internal/horm/req.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package horm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/fumiama/tienyik"
|
||||||
|
"github.com/fumiama/tienyik/internal/textio"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Marshal(tya *tienyik.AES, x any) []byte {
|
||||||
|
q := url.Values{}
|
||||||
|
v := reflect.ValueOf(x).Elem()
|
||||||
|
t := v.Type()
|
||||||
|
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
field := v.Field(i)
|
||||||
|
fieldType := t.Field(i)
|
||||||
|
|
||||||
|
formTag := fieldType.Tag.Get("form")
|
||||||
|
if formTag == "" || formTag == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if field.Kind() == reflect.String {
|
||||||
|
q.Set(formTag, field.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s := q.Encode()
|
||||||
|
if tya != nil {
|
||||||
|
return tya.Encrypt(textio.StringToBytes(s))
|
||||||
|
}
|
||||||
|
return textio.StringToBytes(s)
|
||||||
|
}
|
||||||
@@ -2,12 +2,18 @@ package hson
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/fumiama/tienyik"
|
"github.com/fumiama/tienyik"
|
||||||
"github.com/fumiama/tienyik/internal/log"
|
"github.com/fumiama/tienyik/internal/log"
|
||||||
|
"github.com/fumiama/tienyik/internal/op"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type reqbody struct {
|
||||||
|
EData string `json:"edata"`
|
||||||
|
}
|
||||||
|
|
||||||
func Marshal(tya *tienyik.AES, v any) []byte {
|
func Marshal(tya *tienyik.AES, v any) []byte {
|
||||||
w := bytes.NewBuffer(make([]byte, 0, 1024))
|
w := bytes.NewBuffer(make([]byte, 0, 1024))
|
||||||
err := json.NewEncoder(w).Encode(v)
|
err := json.NewEncoder(w).Encode(v)
|
||||||
@@ -16,7 +22,9 @@ func Marshal(tya *tienyik.AES, v any) []byte {
|
|||||||
}
|
}
|
||||||
log.Debugln("Marshal JSON:", w.String())
|
log.Debugln("Marshal JSON:", w.String())
|
||||||
if tya != nil {
|
if tya != nil {
|
||||||
return tya.Encrypt(w.Bytes())
|
return tya.Encrypt(op.Must(json.Marshal(&reqbody{
|
||||||
|
EData: base64.StdEncoding.EncodeToString(w.Bytes()),
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
return w.Bytes()
|
return w.Bytes()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
package textio
|
package textio
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"net/url"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/fumiama/tienyik"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func API() string {
|
func API() string {
|
||||||
@@ -42,29 +38,3 @@ func API() string {
|
|||||||
sb.WriteString(p[1:])
|
sb.WriteString(p[1:])
|
||||||
return sb.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func EUrlParams(tya *tienyik.AES, params url.Values) string {
|
|
||||||
return url.Values{
|
|
||||||
FuncName(1, true): {BytesToString(tya.Encrypt(
|
|
||||||
StringToBytes(params.Encode()),
|
|
||||||
))},
|
|
||||||
}.Encode()
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseQuery(tya *tienyik.AES, eparams string) (url.Values, error) {
|
|
||||||
q, err := url.ParseQuery(eparams)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(q) != 1 {
|
|
||||||
return nil, errors.New("len(q) must be 1")
|
|
||||||
}
|
|
||||||
for _, v := range q {
|
|
||||||
dec, err := tya.Decrypt(StringToBytes(v[0]))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return url.ParseQuery(BytesToString(dec))
|
|
||||||
}
|
|
||||||
panic("unexpected")
|
|
||||||
}
|
|
||||||
|
|||||||
6
internal/textio/http.go
Normal file
6
internal/textio/http.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package textio
|
||||||
|
|
||||||
|
const (
|
||||||
|
ContenTypeForm = "application/x-www-form-urlencoded"
|
||||||
|
ContenTypeJSON = "application/json"
|
||||||
|
)
|
||||||
25
sha256.go
Normal file
25
sha256.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package tienyik
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ChallengePassword(pwd string, chlg string) string {
|
||||||
|
h := sha256.New()
|
||||||
|
h.Write([]byte(pwd))
|
||||||
|
h.Write([]byte(chlg))
|
||||||
|
var sum [sha256.Size]byte
|
||||||
|
return hex.EncodeToString(h.Sum(sum[:0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ChallengeSHA256Password(pwd string, chlg string) string {
|
||||||
|
h := sha256.New()
|
||||||
|
h.Write([]byte(pwd))
|
||||||
|
var sum [sha256.Size]byte
|
||||||
|
s := hex.EncodeToString(h.Sum(sum[:0]))
|
||||||
|
h.Reset()
|
||||||
|
h.Write([]byte(s))
|
||||||
|
h.Write([]byte(chlg))
|
||||||
|
return hex.EncodeToString(h.Sum(sum[:0]))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user