mirror of
https://github.com/fumiama/tienyik.git
synced 2026-06-27 22:30:29 +08:00
feat: add more apis & cmd tyaliv
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -33,3 +33,9 @@ go.work.sum
|
|||||||
|
|
||||||
# MacOS
|
# MacOS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
# WASM
|
||||||
|
*.wasm
|
||||||
|
|
||||||
|
# configs
|
||||||
|
*.yaml
|
||||||
|
|||||||
@@ -94,11 +94,11 @@ type RequestLogin struct {
|
|||||||
ChallengeID string `form:"challengeId"`
|
ChallengeID string `form:"challengeId"`
|
||||||
DeviceCode string `form:"deviceCode"`
|
DeviceCode string `form:"deviceCode"`
|
||||||
DeviceName string `form:"deviceName"`
|
DeviceName string `form:"deviceName"`
|
||||||
DeviceType string `form:"deviceType"`
|
DeviceType uint64 `form:"deviceType"`
|
||||||
DeviceModel string `form:"deviceModel"`
|
DeviceModel string `form:"deviceModel"`
|
||||||
AppVersion string `form:"appVersion"`
|
AppVersion string `form:"appVersion"`
|
||||||
SysVersion string `form:"sysVersion"`
|
SysVersion string `form:"sysVersion"`
|
||||||
ClientVersion string `form:"clientVersion"`
|
ClientVersion uint64 `form:"clientVersion"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResponseLogin struct {
|
type ResponseLogin struct {
|
||||||
@@ -135,6 +135,8 @@ type ResponseLogin struct {
|
|||||||
func (r *ResponseLogin) SetClient(cli *hcli.Client) {
|
func (r *ResponseLogin) SetClient(cli *hcli.Client) {
|
||||||
cli.Tenantid = strconv.FormatInt(r.TenantID, 10)
|
cli.Tenantid = strconv.FormatInt(r.TenantID, 10)
|
||||||
cli.Usereid = r.UserEid
|
cli.Usereid = r.UserEid
|
||||||
|
cli.SetSecretKey(r.SecretKey)
|
||||||
|
cli.SetTimestamp(r.Timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Login(tya *tienyik.AES, cli *hcli.Client, r *RequestLogin) (*ResponseLogin, error) {
|
func Login(tya *tienyik.AES, cli *hcli.Client, r *RequestLogin) (*ResponseLogin, error) {
|
||||||
@@ -148,3 +150,10 @@ func Login(tya *tienyik.AES, cli *hcli.Client, r *RequestLogin) (*ResponseLogin,
|
|||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
return hson.Unmarshal[*ResponseLogin](tya, resp.Body)
|
return hson.Unmarshal[*ResponseLogin](tya, resp.Body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Logout(tya *tienyik.AES, cli *hcli.Client) error {
|
||||||
|
_, err := cli.Post(
|
||||||
|
textio.API(), "", nil,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,9 +3,12 @@ package auth
|
|||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/fumiama/tienyik"
|
"github.com/fumiama/tienyik"
|
||||||
|
"github.com/fumiama/tienyik/api/cdserv"
|
||||||
|
"github.com/fumiama/tienyik/hcli"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -36,3 +39,39 @@ func TestNegotiationEncKey(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLogin(t *testing.T) {
|
||||||
|
cli := hcli.NewClient()
|
||||||
|
sd, err := cdserv.GetServData()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log("get serv data:", sd)
|
||||||
|
x, err := GenChallengeData(nil, cli)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
sd.SetClient(cli)
|
||||||
|
rsp, err := Login(nil, cli, &RequestLogin{
|
||||||
|
UserAccount: os.Getenv("TYUSR"),
|
||||||
|
Password: tienyik.ChallengePassword(os.Getenv("TYPWD"), x.ChallengeCode),
|
||||||
|
SHA256Password: tienyik.ChallengeSHA256Password(os.Getenv("TYPWD"), x.ChallengeCode),
|
||||||
|
ChallengeID: x.ChallengeID,
|
||||||
|
DeviceCode: cli.Devicecode,
|
||||||
|
DeviceName: tienyik.DeviceNameEdge,
|
||||||
|
DeviceType: cli.Devicetype,
|
||||||
|
DeviceModel: tienyik.DeviceModelMacOS,
|
||||||
|
AppVersion: tienyik.AppVersion,
|
||||||
|
SysVersion: tienyik.DeviceModelMacOS,
|
||||||
|
ClientVersion: cli.Version,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(rsp)
|
||||||
|
rsp.SetClient(cli)
|
||||||
|
err = Logout(nil, cli)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
323
api/desktop/client.go
Normal file
323
api/desktop/client.go
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
package desktop
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"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/textio"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultRequestPageDesktopSortType = "createTimeV1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RequestPageDesktop struct {
|
||||||
|
GetCnt int `json:"getCnt"`
|
||||||
|
DesktopTypes []string `json:"desktopTypes"`
|
||||||
|
SortType string `json:"sortType"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponsePageDesktop struct {
|
||||||
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
SortList []struct {
|
||||||
|
ObjID string `json:"objId"`
|
||||||
|
ObjType int `json:"objType"`
|
||||||
|
ObjValue string `json:"objValue"`
|
||||||
|
DesktopTypes []string `json:"desktopTypes"`
|
||||||
|
} `json:"sortList"`
|
||||||
|
DesktopPoolList []any `json:"desktopPoolList"`
|
||||||
|
DesktopList []struct {
|
||||||
|
ObjType int `json:"objType"`
|
||||||
|
TenantID int `json:"tenantId"`
|
||||||
|
ObjID string `json:"objId"`
|
||||||
|
ConnectURL []string `json:"connectUrl"`
|
||||||
|
ObjName string `json:"objName"`
|
||||||
|
Backupurl []string `json:"backupurl"`
|
||||||
|
OsType string `json:"osType"`
|
||||||
|
OsName string `json:"osName"`
|
||||||
|
ConnectMaster int `json:"connectMaster"`
|
||||||
|
NeedLineUp bool `json:"needLineUp"`
|
||||||
|
UserDesktopGroupID any `json:"userDesktopGroupId"`
|
||||||
|
Strategy struct {
|
||||||
|
ReconnectMsg any `json:"reconnectMsg"`
|
||||||
|
RebootMsg any `json:"rebootMsg"`
|
||||||
|
ShutoffMsg any `json:"shutoffMsg"`
|
||||||
|
ShutdownStrategy any `json:"shutdownStrategy"`
|
||||||
|
RebootStrategy any `json:"rebootStrategy"`
|
||||||
|
ModifyComputerAllas string `json:"modifyComputerAllas"`
|
||||||
|
CheckBeforeConnect any `json:"checkBeforeConnect"`
|
||||||
|
} `json:"strategy"`
|
||||||
|
CloudMobileType any `json:"cloudMobileType"`
|
||||||
|
DesktopID string `json:"desktopId"`
|
||||||
|
DesktopName string `json:"desktopName"`
|
||||||
|
FlavorName any `json:"flavorName"`
|
||||||
|
ImageName string `json:"imageName"`
|
||||||
|
OsBit string `json:"osBit"`
|
||||||
|
CPUCore any `json:"cpuCore"`
|
||||||
|
MemoryGB any `json:"memoryGB"`
|
||||||
|
RootDiskGB any `json:"rootDiskGB"`
|
||||||
|
DataDiskGB any `json:"dataDiskGB"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Summary any `json:"summary"`
|
||||||
|
TanentCode string `json:"tanentCode"`
|
||||||
|
TanentName string `json:"tanentName"`
|
||||||
|
UseStatus string `json:"useStatus"`
|
||||||
|
DesktopCode string `json:"desktopCode"`
|
||||||
|
ForeignDesktopID string `json:"foreignDesktopId"`
|
||||||
|
ForbiddenConnect bool `json:"forbiddenConnect"`
|
||||||
|
GpuType bool `json:"gpuType"`
|
||||||
|
GpuVirtualMethod any `json:"gpuVirtualMethod"`
|
||||||
|
UserMode int `json:"userMode"`
|
||||||
|
DefaultDesktop bool `json:"defaultDesktop"`
|
||||||
|
ExpireDate any `json:"expireDate"`
|
||||||
|
CreateDate int64 `json:"createDate"`
|
||||||
|
NowDate any `json:"nowDate"`
|
||||||
|
NoticeInterval int `json:"noticeInterval"`
|
||||||
|
BandExpireDate any `json:"bandExpireDate"`
|
||||||
|
BandNoticeInterval int `json:"bandNoticeInterval"`
|
||||||
|
UpperResolution any `json:"upperResolution"`
|
||||||
|
ProdType string `json:"prodType"`
|
||||||
|
ProdGroupType int `json:"prodGroupType"`
|
||||||
|
ProdInstID string `json:"prodInstId"`
|
||||||
|
ProdGroupName string `json:"prodGroupName"`
|
||||||
|
DesktopMirrorTagSet []any `json:"desktopMirrorTagSet"`
|
||||||
|
LicenseExpireDate int64 `json:"licenseExpireDate"`
|
||||||
|
LicenseNoticeInterval int `json:"licenseNoticeInterval"`
|
||||||
|
AllowConnStartTime any `json:"allowConnStartTime"`
|
||||||
|
AllowConnEndTime any `json:"allowConnEndTime"`
|
||||||
|
OperationAuditSupported bool `json:"operationAuditSupported"`
|
||||||
|
ProjectionScreenState any `json:"projectionScreenState"`
|
||||||
|
NickName string `json:"nickName"`
|
||||||
|
VMType int `json:"vmType"`
|
||||||
|
PayType string `json:"payType"`
|
||||||
|
ProdSubType any `json:"prodSubType"`
|
||||||
|
InstStatus int `json:"instStatus"`
|
||||||
|
UseTimeVO any `json:"useTimeVO"`
|
||||||
|
UseStatusShowActions any `json:"useStatusShowActions"`
|
||||||
|
UseStatusText string `json:"useStatusText"`
|
||||||
|
UseStatusColor string `json:"useStatusColor"`
|
||||||
|
ModifyComputerAllas any `json:"modifyComputerAllas"`
|
||||||
|
UsePrivateImageFile bool `json:"usePrivateImageFile"`
|
||||||
|
ImageID int `json:"imageId"`
|
||||||
|
ImageCategoryID int `json:"imageCategoryId"`
|
||||||
|
HaProdType int `json:"haProdType"`
|
||||||
|
CtrlTypes []any `json:"ctrlTypes"`
|
||||||
|
OrderProductData struct {
|
||||||
|
TimeLimitTotal any `json:"timeLimitTotal"`
|
||||||
|
TimeLimitUsed any `json:"timeLimitUsed"`
|
||||||
|
NextAcctTime any `json:"nextAcctTime"`
|
||||||
|
BusiChannelType any `json:"busiChannelType"`
|
||||||
|
ManageData any `json:"manageData"`
|
||||||
|
ActiveDate any `json:"activeDate"`
|
||||||
|
KeepTime any `json:"keepTime"`
|
||||||
|
} `json:"orderProductData"`
|
||||||
|
LicenseID int `json:"licenseId"`
|
||||||
|
RegionID int `json:"regionId"`
|
||||||
|
TenantCode string `json:"tenantCode"`
|
||||||
|
ConnectAPIURL struct {
|
||||||
|
ConnectPath string `json:"connectPath"`
|
||||||
|
StatusPath string `json:"statusPath"`
|
||||||
|
StatePath string `json:"statePath"`
|
||||||
|
AppendData any `json:"appendData"`
|
||||||
|
} `json:"connectApiUrl"`
|
||||||
|
} `json:"desktopList"`
|
||||||
|
PreemptionDesktopList []any `json:"preemptionDesktopList"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func PageDesktop(tya *tienyik.AES, cli *hcli.Client, r *RequestPageDesktop) (*ResponsePageDesktop, error) {
|
||||||
|
resp, err := cli.Post(
|
||||||
|
textio.API(), textio.ContenTypeJSON,
|
||||||
|
bytes.NewReader(hson.Marshal(tya, r)),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
return hson.Unmarshal[*ResponsePageDesktop](tya, resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseFeature struct {
|
||||||
|
CPUCore int `json:"cpuCore"`
|
||||||
|
MemoryGB int `json:"memoryGB"`
|
||||||
|
SystemDiskGB int `json:"systemDiskGB"`
|
||||||
|
DataDiskGB any `json:"dataDiskGB"`
|
||||||
|
TotalDiskGB int `json:"totalDiskGB"`
|
||||||
|
SysDisk struct {
|
||||||
|
Size int `json:"size"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
Code string `json:"code"`
|
||||||
|
} `json:"sysDisk"`
|
||||||
|
DataDiskList []any `json:"dataDiskList"`
|
||||||
|
MirrorVersion string `json:"mirrorVersion"`
|
||||||
|
MirrorCategoryName string `json:"mirrorCategoryName"`
|
||||||
|
DesktopName string `json:"desktopName"`
|
||||||
|
GpuSliceRAM any `json:"gpuSliceRam"`
|
||||||
|
GpuSliceRAMDesc any `json:"gpuSliceRamDesc"`
|
||||||
|
ExpireDate any `json:"expireDate"`
|
||||||
|
CreateDate int64 `json:"createDate"`
|
||||||
|
NowDate int64 `json:"nowDate"`
|
||||||
|
LinkInfo any `json:"linkInfo"`
|
||||||
|
OrderProduct struct {
|
||||||
|
TimeLimitTotal any `json:"timeLimitTotal"`
|
||||||
|
TimeLimitUsed any `json:"timeLimitUsed"`
|
||||||
|
NextAcctTime any `json:"nextAcctTime"`
|
||||||
|
BusiChannelType string `json:"busiChannelType"`
|
||||||
|
ManageData any `json:"manageData"`
|
||||||
|
ActiveDate any `json:"activeDate"`
|
||||||
|
KeepTime any `json:"keepTime"`
|
||||||
|
} `json:"orderProduct"`
|
||||||
|
MirrorID int `json:"mirrorId"`
|
||||||
|
MirrorCategoryID int `json:"mirrorCategoryId"`
|
||||||
|
ProductName string `json:"productName"`
|
||||||
|
PayType string `json:"payType"`
|
||||||
|
ProdType string `json:"prodType"`
|
||||||
|
ProdSubType any `json:"prodSubType"`
|
||||||
|
TimePkgVOS []any `json:"timePkgVOS"`
|
||||||
|
Os string `json:"os"`
|
||||||
|
MirrorType string `json:"mirrorType"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func Feature(tya *tienyik.AES, cli *hcli.Client, desktopId string, objType int, objId string) (*ResponseFeature, error) {
|
||||||
|
u, err := url.Parse(textio.API())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
q := u.Query()
|
||||||
|
q.Set("desktopId", desktopId)
|
||||||
|
q.Set("objType", strconv.Itoa(objType))
|
||||||
|
q.Set("objId", objId)
|
||||||
|
u.RawQuery = tya.EUrlParams(q)
|
||||||
|
|
||||||
|
resp, err := cli.Get(u.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
return hson.Unmarshal[*ResponseFeature](tya, resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseGetDesktopExtraInfo struct {
|
||||||
|
Strategy struct {
|
||||||
|
ReconnectMsg any `json:"reconnectMsg"`
|
||||||
|
RebootMsg any `json:"rebootMsg"`
|
||||||
|
ShutoffMsg any `json:"shutoffMsg"`
|
||||||
|
ShutdownStrategy string `json:"shutdownStrategy"`
|
||||||
|
RebootStrategy string `json:"rebootStrategy"`
|
||||||
|
ModifyComputerAllas any `json:"modifyComputerAllas"`
|
||||||
|
CheckBeforeConnect any `json:"checkBeforeConnect"`
|
||||||
|
} `json:"strategy"`
|
||||||
|
UpperResolution string `json:"upperResolution"`
|
||||||
|
TimeLimitProductData any `json:"timeLimitProductData"`
|
||||||
|
HaProdType int `json:"haProdType"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDesktopExtraInfo(tya *tienyik.AES, cli *hcli.Client, objId string, objType int) (*ResponseGetDesktopExtraInfo, error) {
|
||||||
|
u, err := url.Parse(textio.API())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
q := u.Query()
|
||||||
|
q.Set("objId", objId)
|
||||||
|
q.Set("objType", strconv.Itoa(objType))
|
||||||
|
u.RawQuery = tya.EUrlParams(q)
|
||||||
|
|
||||||
|
resp, err := cli.Get(u.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
return hson.Unmarshal[*ResponseGetDesktopExtraInfo](tya, resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RequestConnect struct {
|
||||||
|
ObjID string `form:"objId"`
|
||||||
|
ObjType int `form:"objType"`
|
||||||
|
OsType string `form:"osType"`
|
||||||
|
DeviceID int `form:"deviceId"`
|
||||||
|
DeviceCode string `form:"deviceCode"`
|
||||||
|
DeviceName string `form:"deviceName"`
|
||||||
|
SysVersion string `form:"sysVersion"`
|
||||||
|
AppVersion string `form:"appVersion"`
|
||||||
|
HostName string `form:"hostName"`
|
||||||
|
VdCommand string `form:"vdCommand"`
|
||||||
|
IPAddress string `form:"ipAddress"`
|
||||||
|
MacAddress string `form:"macAddress"`
|
||||||
|
HardwareFeatureCode string `form:"hardwareFeatureCode"`
|
||||||
|
SpecifiedCertCategory int `form:"specifiedCertCategory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseConnect struct {
|
||||||
|
GoingRetry bool `json:"goingRetry"`
|
||||||
|
DesktopInfo any `json:"desktopInfo"`
|
||||||
|
ShadowDesktopInfo struct {
|
||||||
|
InHaMode int `json:"inHaMode"`
|
||||||
|
HaDesktopID any `json:"haDesktopId"`
|
||||||
|
HaConnectingTips any `json:"haConnectingTips"`
|
||||||
|
HaConnectSucTips any `json:"haConnectSucTips"`
|
||||||
|
} `json:"shadowDesktopInfo"`
|
||||||
|
DesktopAnywhereInfo struct {
|
||||||
|
AnywhereStatus int `json:"anywhereStatus"`
|
||||||
|
MigrateStatus any `json:"migrateStatus"`
|
||||||
|
AnywhereDesktopID any `json:"anywhereDesktopId"`
|
||||||
|
SrcResPoolName any `json:"srcResPoolName"`
|
||||||
|
TargetResPoolName any `json:"targetResPoolName"`
|
||||||
|
EstimatedTime int `json:"estimatedTime"`
|
||||||
|
ReminderDays any `json:"reminderDays"`
|
||||||
|
RoamingDays any `json:"roamingDays"`
|
||||||
|
NeedReserveRemind int `json:"needReserveRemind"`
|
||||||
|
ShadowInfoDTO any `json:"shadowInfoDTO"`
|
||||||
|
AnywhereOpen bool `json:"anywhereOpen"`
|
||||||
|
ConnectTargetDesktop bool `json:"connectTargetDesktop"`
|
||||||
|
} `json:"desktopAnywhereInfo"`
|
||||||
|
DesktopID string `json:"desktopId"`
|
||||||
|
PollingKey string `json:"pollingKey"`
|
||||||
|
AuthInfo any `json:"authInfo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func Connect(tya *tienyik.AES, cli *hcli.Client, r *RequestConnect) (*ResponseConnect, 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[*ResponseConnect](tya, resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RequestState struct {
|
||||||
|
ObjID string `json:"objId"`
|
||||||
|
ObjType int `json:"objType"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseState struct {
|
||||||
|
ObjType int `json:"objType"`
|
||||||
|
ObjID string `json:"objId"`
|
||||||
|
DesktopID int `json:"desktopId"`
|
||||||
|
DesktopState string `json:"desktopState"`
|
||||||
|
RunningTask int `json:"runningTask"`
|
||||||
|
RunningTaskName string `json:"runningTaskName"`
|
||||||
|
TaskStartTime int64 `json:"taskStartTime"`
|
||||||
|
MirrorReady any `json:"mirrorReady"`
|
||||||
|
UseStatus string `json:"useStatus"`
|
||||||
|
UseStatusText string `json:"useStatusText"`
|
||||||
|
UseStatusColor string `json:"useStatusColor"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func State(tya *tienyik.AES, cli *hcli.Client, r []RequestState) ([]ResponseState, error) {
|
||||||
|
resp, err := cli.Post(
|
||||||
|
textio.API(), textio.ContenTypeJSON,
|
||||||
|
bytes.NewReader(hson.Marshal(tya, &r)),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
return hson.Unmarshal[[]ResponseState](tya, resp.Body)
|
||||||
|
}
|
||||||
101
api/desktop/client_test.go
Normal file
101
api/desktop/client_test.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package desktop
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/fumiama/tienyik"
|
||||||
|
"github.com/fumiama/tienyik/api/auth"
|
||||||
|
"github.com/fumiama/tienyik/api/cdserv"
|
||||||
|
"github.com/fumiama/tienyik/hcli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDesktop(t *testing.T) {
|
||||||
|
cli := hcli.NewClient()
|
||||||
|
sd, err := cdserv.GetServData()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log("get serv data:", sd)
|
||||||
|
x, err := auth.GenChallengeData(nil, cli)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
sd.SetClient(cli)
|
||||||
|
rsp, err := auth.Login(nil, cli, &auth.RequestLogin{
|
||||||
|
UserAccount: os.Getenv("TYUSR"),
|
||||||
|
Password: tienyik.ChallengePassword(os.Getenv("TYPWD"), x.ChallengeCode),
|
||||||
|
SHA256Password: tienyik.ChallengeSHA256Password(os.Getenv("TYPWD"), x.ChallengeCode),
|
||||||
|
ChallengeID: x.ChallengeID,
|
||||||
|
DeviceCode: cli.Devicecode,
|
||||||
|
DeviceName: tienyik.DeviceNameEdge,
|
||||||
|
DeviceType: cli.Devicetype,
|
||||||
|
DeviceModel: tienyik.DeviceModelMacOS,
|
||||||
|
AppVersion: tienyik.AppVersion,
|
||||||
|
SysVersion: tienyik.DeviceModelMacOS,
|
||||||
|
ClientVersion: cli.Version,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(rsp)
|
||||||
|
rsp.SetClient(cli)
|
||||||
|
pd, err := PageDesktop(nil, cli, &RequestPageDesktop{
|
||||||
|
GetCnt: 1,
|
||||||
|
DesktopTypes: []string{"1", tienyik.ArchX86, tienyik.ArchARM, tienyik.ArchHW},
|
||||||
|
SortType: DefaultRequestPageDesktopSortType,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(pd)
|
||||||
|
for _, x := range pd.DesktopList {
|
||||||
|
feat, err := Feature(nil, cli, x.DesktopID, x.ObjType, x.ObjID)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log("feat:", feat)
|
||||||
|
ext, err := GetDesktopExtraInfo(nil, cli, x.ObjID, x.ObjType)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log("ext:", ext)
|
||||||
|
s, err := State(nil, cli, []RequestState{{
|
||||||
|
ObjID: x.ObjID,
|
||||||
|
ObjType: x.ObjType,
|
||||||
|
}})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log("s1:", s)
|
||||||
|
con, err := Connect(nil, cli, &RequestConnect{
|
||||||
|
ObjID: x.ObjID,
|
||||||
|
ObjType: x.ObjType,
|
||||||
|
OsType: x.OsType,
|
||||||
|
DeviceID: int(cli.Devicetype),
|
||||||
|
DeviceCode: cli.Devicecode,
|
||||||
|
DeviceName: tienyik.DeviceNameEdge,
|
||||||
|
SysVersion: tienyik.DeviceModelMacOS,
|
||||||
|
AppVersion: tienyik.AppVersion,
|
||||||
|
HostName: tienyik.DeviceNameEdge,
|
||||||
|
HardwareFeatureCode: cli.Devicecode,
|
||||||
|
SpecifiedCertCategory: 1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log("con:", con)
|
||||||
|
s, err = State(nil, cli, []RequestState{{
|
||||||
|
ObjID: x.ObjID,
|
||||||
|
ObjType: x.ObjType,
|
||||||
|
}})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log("s2:", s)
|
||||||
|
}
|
||||||
|
err = auth.Logout(nil, cli)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
26
cfg.go
26
cfg.go
@@ -7,12 +7,15 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Version = "103010001"
|
const (
|
||||||
|
Version = 103010001
|
||||||
|
AppVersion = "3.1.0"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DeviceTypePC = "25"
|
DeviceTypePC = 25
|
||||||
DeviceTypeMAC = "45"
|
DeviceTypeMAC = 45
|
||||||
DeviceTypeWEB = "60"
|
DeviceTypeWEB = 60
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -21,6 +24,21 @@ const (
|
|||||||
AppModelPHONE = "3"
|
AppModelPHONE = "3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DeviceNameEdge = "Edge浏览器"
|
||||||
|
)
|
||||||
|
|
||||||
|
// alos sysVersion
|
||||||
|
const (
|
||||||
|
DeviceModelMacOS = "Macintosh; Intel Mac OS X 10_15_7"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ArchX86 = "2001"
|
||||||
|
ArchARM = "2002"
|
||||||
|
ArchHW = "2003"
|
||||||
|
)
|
||||||
|
|
||||||
func NewDeviceCode() string {
|
func NewDeviceCode() string {
|
||||||
sb := &strings.Builder{}
|
sb := &strings.Builder{}
|
||||||
sb.WriteString("web_")
|
sb.WriteString("web_")
|
||||||
|
|||||||
198
cmd/tyaliv/main.go
Normal file
198
cmd/tyaliv/main.go
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
|
base14 "github.com/fumiama/go-base16384"
|
||||||
|
"github.com/fumiama/tienyik"
|
||||||
|
"github.com/fumiama/tienyik/api/auth"
|
||||||
|
"github.com/fumiama/tienyik/api/cdserv"
|
||||||
|
"github.com/fumiama/tienyik/api/desktop"
|
||||||
|
"github.com/fumiama/tienyik/hcli"
|
||||||
|
"github.com/fumiama/tienyik/internal/log"
|
||||||
|
"github.com/fumiama/tienyik/internal/textio"
|
||||||
|
)
|
||||||
|
|
||||||
|
type config struct {
|
||||||
|
UserAccount string `yaml:"UserAccount"`
|
||||||
|
PasswordB14 string `yaml:"PasswordB14"` // PasswordB14 is a little bit more secure
|
||||||
|
CheckIntervalSec int `yaml:"CheckIntervalSec"` // CheckIntervalSec default 60
|
||||||
|
GetDeviceCount int `yaml:"GetDeviceCount"` // GetDeviceCount default 20
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
c := flag.String("c", "config.yaml", "load config file")
|
||||||
|
s := flag.String("s", "", "save config file template")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
cfg := config{}
|
||||||
|
|
||||||
|
if *s != "" {
|
||||||
|
fmt.Print("UserAccount: ")
|
||||||
|
fmt.Scanln(&cfg.UserAccount)
|
||||||
|
pwd := ""
|
||||||
|
fmt.Print("Password: ")
|
||||||
|
textio.NoEchoScanln(&pwd)
|
||||||
|
cfg.PasswordB14 = base14.EncodeString(pwd)
|
||||||
|
cfg.CheckIntervalSec = 60
|
||||||
|
cfg.GetDeviceCount = 20
|
||||||
|
data, err := yaml.Marshal(&cfg)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
err = os.WriteFile(*s, data, 0644)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open(*c)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
err = yaml.NewDecoder(f).Decode(&cfg)
|
||||||
|
_ = f.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
if cfg.UserAccount == "" {
|
||||||
|
log.Fatalln("user account must be set")
|
||||||
|
}
|
||||||
|
if cfg.PasswordB14 == "" {
|
||||||
|
log.Fatalln("password must be set (in b14 format)")
|
||||||
|
}
|
||||||
|
if cfg.CheckIntervalSec <= 0 {
|
||||||
|
cfg.CheckIntervalSec = 60
|
||||||
|
}
|
||||||
|
if cfg.GetDeviceCount <= 0 {
|
||||||
|
cfg.GetDeviceCount = 20
|
||||||
|
}
|
||||||
|
|
||||||
|
RECONN:
|
||||||
|
cli := hcli.NewClient()
|
||||||
|
sd, err := cdserv.GetServData()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
x, err := auth.GenChallengeData(nil, cli)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
sd.SetClient(cli)
|
||||||
|
pwd := base14.DecodeString(cfg.PasswordB14)
|
||||||
|
rsp, err := auth.Login(nil, cli, &auth.RequestLogin{
|
||||||
|
UserAccount: cfg.UserAccount,
|
||||||
|
Password: tienyik.ChallengePassword(pwd, x.ChallengeCode),
|
||||||
|
SHA256Password: tienyik.ChallengeSHA256Password(pwd, x.ChallengeCode),
|
||||||
|
ChallengeID: x.ChallengeID,
|
||||||
|
DeviceCode: cli.Devicecode,
|
||||||
|
DeviceName: tienyik.DeviceNameEdge,
|
||||||
|
DeviceType: cli.Devicetype,
|
||||||
|
DeviceModel: tienyik.DeviceModelMacOS,
|
||||||
|
AppVersion: tienyik.AppVersion,
|
||||||
|
SysVersion: tienyik.DeviceModelMacOS,
|
||||||
|
ClientVersion: cli.Version,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
rsp.SetClient(cli)
|
||||||
|
defer auth.Logout(nil, cli)
|
||||||
|
|
||||||
|
pd, err := desktop.PageDesktop(nil, cli, &desktop.RequestPageDesktop{
|
||||||
|
GetCnt: 20,
|
||||||
|
DesktopTypes: []string{"1", tienyik.ArchX86},
|
||||||
|
SortType: desktop.DefaultRequestPageDesktopSortType,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mp := make(map[string][2]string, len(pd.DesktopList)*4)
|
||||||
|
sb := strings.Builder{}
|
||||||
|
sb.WriteString("available desktops:")
|
||||||
|
for _, x := range pd.DesktopList {
|
||||||
|
if x.UseStatusText == "运行中" {
|
||||||
|
sb.WriteString(" |●")
|
||||||
|
} else {
|
||||||
|
sb.WriteString(" |○")
|
||||||
|
}
|
||||||
|
sb.WriteString("[")
|
||||||
|
sb.WriteString(x.ObjID)
|
||||||
|
sb.WriteString("]")
|
||||||
|
sb.WriteString(x.ObjName)
|
||||||
|
sb.WriteString("(")
|
||||||
|
sb.WriteString(x.OsName)
|
||||||
|
sb.WriteString(")|")
|
||||||
|
mp[x.ObjID] = [2]string{x.ObjName, x.OsType}
|
||||||
|
}
|
||||||
|
log.Infoln(&sb)
|
||||||
|
|
||||||
|
t := time.NewTicker(time.Second * time.Duration(cfg.CheckIntervalSec))
|
||||||
|
defer t.Stop()
|
||||||
|
|
||||||
|
mainStopCh := make(chan struct{})
|
||||||
|
mc := make(chan os.Signal, 4)
|
||||||
|
signal.Notify(mc, os.Interrupt, syscall.SIGQUIT, syscall.SIGTERM)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
<-mc
|
||||||
|
close(mainStopCh)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-t.C:
|
||||||
|
log.Infoln("start refreshing...")
|
||||||
|
|
||||||
|
reqs := make([]desktop.RequestState, len(pd.DesktopList))
|
||||||
|
for i, x := range pd.DesktopList {
|
||||||
|
reqs[i].ObjID = x.ObjID
|
||||||
|
reqs[i].ObjType = x.ObjType
|
||||||
|
}
|
||||||
|
s, err := desktop.State(nil, cli, reqs)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnln("get state err:", err)
|
||||||
|
goto RECONN
|
||||||
|
}
|
||||||
|
for _, x := range s {
|
||||||
|
log.Infof("%s [%s]%s status is %s", x.ObjID, mp[x.ObjID][0], x.DesktopState)
|
||||||
|
if x.DesktopState == "ACTIVE" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Infof("%s [%s]%s do refresh", x.ObjID, mp[x.ObjID][0])
|
||||||
|
_, err = desktop.Connect(nil, cli, &desktop.RequestConnect{
|
||||||
|
ObjID: x.ObjID,
|
||||||
|
ObjType: x.ObjType,
|
||||||
|
OsType: mp[x.ObjID][1],
|
||||||
|
DeviceID: int(cli.Devicetype),
|
||||||
|
DeviceCode: cli.Devicecode,
|
||||||
|
DeviceName: tienyik.DeviceNameEdge,
|
||||||
|
SysVersion: tienyik.DeviceModelMacOS,
|
||||||
|
AppVersion: tienyik.AppVersion,
|
||||||
|
HostName: tienyik.DeviceNameEdge,
|
||||||
|
HardwareFeatureCode: cli.Devicecode,
|
||||||
|
SpecifiedCertCategory: 1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Warnln("connect err:", err)
|
||||||
|
goto RECONN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case <-mainStopCh:
|
||||||
|
log.Warnln("quit loop")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
3
go.mod
3
go.mod
@@ -5,7 +5,10 @@ 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
|
||||||
|
github.com/tetratelabs/wazero v1.9.0
|
||||||
golang.org/x/net v0.28.0
|
golang.org/x/net v0.28.0
|
||||||
|
golang.org/x/term v0.23.0
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|||||||
5
go.sum
5
go.sum
@@ -13,15 +13,20 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
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=
|
||||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
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=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
|
||||||
|
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
|
||||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
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/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/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
|
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/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
|
||||||
|
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
|
||||||
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 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
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 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
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=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
|||||||
53
hcli/cli.go
53
hcli/cli.go
@@ -1,6 +1,7 @@
|
|||||||
package hcli
|
package hcli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -21,17 +22,22 @@ var DefaultClient = http.Client{
|
|||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
rcnt uintptr
|
rcnt uintptr
|
||||||
|
sg tienyik.Signer
|
||||||
|
secretKey string
|
||||||
|
offsetTime int64
|
||||||
|
|
||||||
Appmodel string
|
Appmodel string
|
||||||
Devicecode string
|
Devicecode string
|
||||||
Devicetype string
|
Devicetype uint64
|
||||||
Servernode string
|
Servernode string
|
||||||
Tenantid string
|
Tenantid string
|
||||||
Usereid string
|
Usereid string
|
||||||
Version string
|
Version uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient() *Client {
|
func NewClient() *Client {
|
||||||
return &Client{
|
return &Client{
|
||||||
|
sg: tienyik.NewSigner(context.TODO()),
|
||||||
Appmodel: tienyik.AppModelTOB,
|
Appmodel: tienyik.AppModelTOB,
|
||||||
Devicecode: tienyik.NewDeviceCode(),
|
Devicecode: tienyik.NewDeviceCode(),
|
||||||
Devicetype: tienyik.DeviceTypeWEB,
|
Devicetype: tienyik.DeviceTypeWEB,
|
||||||
@@ -39,6 +45,15 @@ func NewClient() *Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) SetSecretKey(k string) {
|
||||||
|
c.secretKey = k
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) SetTimestamp(ts int64) {
|
||||||
|
n := time.Now().UnixMilli()
|
||||||
|
c.offsetTime = n - ts
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) setHeaders(req *http.Request) {
|
func (c *Client) setHeaders(req *http.Request) {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return
|
return
|
||||||
@@ -54,27 +69,39 @@ func (c *Client) setHeaders(req *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fieldValue := v.Field(i)
|
fieldValue := v.Field(i)
|
||||||
|
if fieldValue.IsZero() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
k := base14.DecodeString("廝呲舀㴄") + field.Name
|
||||||
|
|
||||||
if fieldValue.Kind() == reflect.String {
|
switch fieldValue.Kind() {
|
||||||
req.Header.Set(
|
case reflect.String:
|
||||||
base14.DecodeString("廝呲舀㴄")+field.Name,
|
req.Header.Set(k, fieldValue.String())
|
||||||
fieldValue.String(),
|
case reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uint, reflect.Uintptr:
|
||||||
)
|
req.Header.Set(k, strconv.FormatUint(fieldValue.Uint(), 10))
|
||||||
|
case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int:
|
||||||
|
req.Header.Set(k, strconv.FormatInt(fieldValue.Int(), 10))
|
||||||
|
default:
|
||||||
|
panic("unsupported field " + field.Name + " value type " + fieldValue.Type().String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Appmodel != "" {
|
if c.Appmodel != "" {
|
||||||
ts := time.Now().UnixMilli()
|
ts := time.Now().UnixMilli()
|
||||||
|
rid := uint64(atomic.AddUintptr(&c.rcnt, 1)) + uint64(ts)
|
||||||
|
requestid := strconv.FormatUint(rid, 10)
|
||||||
|
|
||||||
|
ts -= c.offsetTime
|
||||||
timestamp := strconv.FormatInt(ts, 10)
|
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("廝呲草獱歙攷徥爀㴆"), requestid)
|
||||||
req.Header.Set(base14.DecodeString("廝呲荑睭杜蕆厵縀㴆"), timestamp)
|
req.Header.Set(base14.DecodeString("廝呲荑睭杜蕆厵縀㴆"), timestamp)
|
||||||
}
|
|
||||||
|
|
||||||
if c.Servernode != "" {
|
if c.secretKey != "" {
|
||||||
//TODO: gensign
|
req.Header.Set(base14.DecodeString("廝呲荍睧榘敇揉獳欜渀㴂"), c.sg.GenKeyNew(
|
||||||
|
context.TODO(), c.Devicetype, uint64(ts), rid, c.secretKey,
|
||||||
|
c.Usereid, req.URL.EscapedPath(), c.Servernode, c.Version,
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package horm
|
|||||||
import (
|
import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/fumiama/tienyik"
|
"github.com/fumiama/tienyik"
|
||||||
"github.com/fumiama/tienyik/internal/textio"
|
"github.com/fumiama/tienyik/internal/textio"
|
||||||
@@ -22,8 +23,13 @@ func Marshal(tya *tienyik.AES, x any) []byte {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if field.Kind() == reflect.String {
|
switch field.Kind() {
|
||||||
|
case reflect.String:
|
||||||
q.Set(formTag, field.String())
|
q.Set(formTag, field.String())
|
||||||
|
case reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uint, reflect.Uintptr:
|
||||||
|
q.Set(formTag, strconv.FormatUint(field.Uint(), 10))
|
||||||
|
case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int:
|
||||||
|
q.Set(formTag, strconv.FormatInt(field.Int(), 10))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
17
internal/textio/interact.go
Normal file
17
internal/textio/interact.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package textio
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/term"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NoEchoScanln(a ...any) (n int, err error) {
|
||||||
|
fd := int(os.Stdin.Fd())
|
||||||
|
bytePassword, err := term.ReadPassword(fd)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return fmt.Sscanln(string(bytePassword)+"\n", a...)
|
||||||
|
}
|
||||||
198
wasm.go
Normal file
198
wasm.go
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
package tienyik
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
_ "embed"
|
||||||
|
|
||||||
|
"github.com/fumiama/tienyik/internal/op"
|
||||||
|
"github.com/tetratelabs/wazero"
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed main.1755740488270.wasm
|
||||||
|
var wasmdata []byte
|
||||||
|
|
||||||
|
type Signer struct {
|
||||||
|
rt wazero.Runtime
|
||||||
|
md api.Module
|
||||||
|
genKey api.Function
|
||||||
|
genKeyNew api.Function
|
||||||
|
genKeyWithoutURI api.Function
|
||||||
|
_malloc api.Function
|
||||||
|
_free api.Function
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSigner(ctx context.Context) (sg Signer) {
|
||||||
|
rt := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfigInterpreter())
|
||||||
|
_, err := rt.NewHostModuleBuilder("a").
|
||||||
|
// ___cxa_throw
|
||||||
|
NewFunctionBuilder().WithFunc(func(ctx context.Context, e, n, t uint32) {
|
||||||
|
panic(fmt.Sprintf("___cxa_throw: ptr(e)=%08x, type(n)=%08x, destructor(t)=%08x", e, n, t))
|
||||||
|
}).Export("c").
|
||||||
|
// __abort_js
|
||||||
|
NewFunctionBuilder().WithFunc(func(ctx context.Context) {
|
||||||
|
panic("wasm aborted")
|
||||||
|
}).Export("a").
|
||||||
|
// _emscripten_resize_heap
|
||||||
|
NewFunctionBuilder().WithFunc(func(ctx context.Context, _ uint32) uint32 {
|
||||||
|
panic("wasm oom")
|
||||||
|
}).Export("b").
|
||||||
|
Instantiate(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
md, err := rt.InstantiateWithConfig(ctx, wasmdata,
|
||||||
|
wazero.NewModuleConfig())
|
||||||
|
if err != nil {
|
||||||
|
_ = rt.Close(ctx)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sg.rt = rt
|
||||||
|
sg.md = md
|
||||||
|
|
||||||
|
sg.genKey = md.ExportedFunction("f")
|
||||||
|
sg.genKeyNew = md.ExportedFunction("g")
|
||||||
|
sg.genKeyWithoutURI = md.ExportedFunction("h")
|
||||||
|
sg._malloc = md.ExportedFunction("i")
|
||||||
|
sg._free = md.ExportedFunction("j")
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenKey is the go repr of js func
|
||||||
|
//
|
||||||
|
// generatorSign(e) {
|
||||||
|
// const t = Module.lengthBytesUTF8(e.secretKey) + 1
|
||||||
|
// , n = Module._malloc(t);
|
||||||
|
// Module.stringToUTF8(e.secretKey, n, t);
|
||||||
|
// const r = Module._gen_key(e.deviceType, BigInt(e.timestamp), BigInt(e.requestId), n, e.tenantId, e.userId, e.version)
|
||||||
|
// , o = Module.UTF8ToString(r);
|
||||||
|
// return Module._free(n),
|
||||||
|
// Module._free(r),
|
||||||
|
// o
|
||||||
|
// }
|
||||||
|
func (sg *Signer) GenKey(
|
||||||
|
ctx context.Context, deviceType, timestamp, requestID uint64,
|
||||||
|
secretKey string, tenantID, userID, version uint64,
|
||||||
|
) string {
|
||||||
|
t := len(secretKey) + 1
|
||||||
|
n := sg.malloc(ctx, uint64(t))
|
||||||
|
if !sg.md.Memory().WriteString(uint32(n), secretKey+"\x00") {
|
||||||
|
panic("write out-of-bound")
|
||||||
|
}
|
||||||
|
defer sg.free(ctx, n)
|
||||||
|
|
||||||
|
return sg.string(op.Must(sg.genKey.Call(
|
||||||
|
ctx, deviceType, timestamp, requestID,
|
||||||
|
n, tenantID, userID, version),
|
||||||
|
)[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenKeyNew is the go repr of js func
|
||||||
|
//
|
||||||
|
// generatorSignNew(e) {
|
||||||
|
// const t = Module.lengthBytesUTF8(e.secretKey) + 1
|
||||||
|
// , n = Module._malloc(t);
|
||||||
|
// Module.stringToUTF8(e.secretKey, n, t);
|
||||||
|
// const r = Module.lengthBytesUTF8(e.userEid) + 1
|
||||||
|
// , o = Module._malloc(r);
|
||||||
|
// Module.stringToUTF8(e.userEid, o, r);
|
||||||
|
// const i = Module.lengthBytesUTF8(e.requestUri) + 1
|
||||||
|
// , a = Module._malloc(i);
|
||||||
|
// Module.stringToUTF8(e.requestUri, a, i);
|
||||||
|
// const s = Module.lengthBytesUTF8(this.serverNode) + 1
|
||||||
|
// , l = Module._malloc(s);
|
||||||
|
// Module.stringToUTF8(this.serverNode, l, s);
|
||||||
|
// const c = Module._gen_key_new(e.deviceType, BigInt(e.timestamp), BigInt(e.requestId), n, o, a, l, e.version)
|
||||||
|
// , u = Module.UTF8ToString(c);
|
||||||
|
// return Module._free(n),
|
||||||
|
// Module._free(o),
|
||||||
|
// Module._free(a),
|
||||||
|
// Module._free(l),
|
||||||
|
// Module._free(c),
|
||||||
|
// u
|
||||||
|
// }
|
||||||
|
func (sg *Signer) GenKeyNew(
|
||||||
|
ctx context.Context, deviceType, timestamp, requestID uint64,
|
||||||
|
secretKey, userEID, requestURI, serverNode string, version uint64,
|
||||||
|
) string {
|
||||||
|
t := len(secretKey) + 1
|
||||||
|
n := sg.malloc(ctx, uint64(t))
|
||||||
|
if !sg.md.Memory().WriteString(uint32(n), secretKey+"\x00") {
|
||||||
|
panic("write out-of-bound")
|
||||||
|
}
|
||||||
|
defer sg.free(ctx, n)
|
||||||
|
|
||||||
|
r := len(userEID) + 1
|
||||||
|
o := sg.malloc(ctx, uint64(r))
|
||||||
|
if !sg.md.Memory().WriteString(uint32(o), userEID+"\x00") {
|
||||||
|
panic("write out-of-bound")
|
||||||
|
}
|
||||||
|
defer sg.free(ctx, o)
|
||||||
|
|
||||||
|
i := len(requestURI) + 1
|
||||||
|
a := sg.malloc(ctx, uint64(i))
|
||||||
|
if !sg.md.Memory().WriteString(uint32(a), requestURI+"\x00") {
|
||||||
|
panic("write out-of-bound")
|
||||||
|
}
|
||||||
|
defer sg.free(ctx, a)
|
||||||
|
|
||||||
|
s := len(serverNode) + 1
|
||||||
|
l := sg.malloc(ctx, uint64(s))
|
||||||
|
if !sg.md.Memory().WriteString(uint32(l), serverNode+"\x00") {
|
||||||
|
panic("write out-of-bound")
|
||||||
|
}
|
||||||
|
defer sg.free(ctx, l)
|
||||||
|
|
||||||
|
return sg.string(op.Must(sg.genKeyNew.Call(
|
||||||
|
ctx, deviceType, timestamp, requestID,
|
||||||
|
n, o, a, l, version),
|
||||||
|
)[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sg *Signer) malloc(ctx context.Context, n uint64) uint64 {
|
||||||
|
return op.Must(sg._malloc.Call(ctx, n))[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sg *Signer) free(ctx context.Context, n uint64) {
|
||||||
|
op.Must(sg._free.Call(ctx, n))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sg *Signer) string(ptr uint64) string {
|
||||||
|
buf := strings.Builder{}
|
||||||
|
x := uint32(ptr)
|
||||||
|
for {
|
||||||
|
b, ok := sg.md.Memory().ReadByte(x)
|
||||||
|
x++
|
||||||
|
if !ok {
|
||||||
|
panic("read out-of-bound")
|
||||||
|
}
|
||||||
|
if b == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
buf.WriteByte(b)
|
||||||
|
}
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sg *Signer) IsClosed() bool {
|
||||||
|
return sg.md == nil || sg.rt == nil || sg.md.IsClosed() ||
|
||||||
|
sg.genKey == nil || sg.genKeyNew == nil || sg.genKeyWithoutURI == nil ||
|
||||||
|
sg._malloc == nil || sg._free == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sg *Signer) Close(ctx context.Context) {
|
||||||
|
if sg.md != nil && !sg.md.IsClosed() {
|
||||||
|
sg.md.Close(ctx)
|
||||||
|
sg.md = nil
|
||||||
|
}
|
||||||
|
if sg.rt != nil {
|
||||||
|
sg.rt.Close(ctx)
|
||||||
|
sg.rt = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
20
wasm_test.go
Normal file
20
wasm_test.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package tienyik
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSigner(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
sg := NewSigner(ctx)
|
||||||
|
sigstr := sg.GenKeyNew(
|
||||||
|
ctx, 60, 1763891935806, 1763891937568, "9c047f01dfab388a3ef7c4ae34855e3a",
|
||||||
|
"6806caebc2cdaef5f10987a94d21cf1f", "/api/cdserv/client/msgcenter/page",
|
||||||
|
"8aff800b3c96e620043bb7deb4a0258d", 103010001,
|
||||||
|
)
|
||||||
|
if sigstr != "66443F2BF714E1D2B4AC8D3B3CBC3913" {
|
||||||
|
t.Fatal("got", sigstr)
|
||||||
|
}
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user