1
0
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:
源文雨
2025-10-31 23:20:46 +08:00
parent 15fcc9a338
commit da1de770ad
19 changed files with 509 additions and 82 deletions

View File

@@ -2,8 +2,14 @@ package auth
import (
"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/textio"
)
@@ -19,11 +25,126 @@ type ResponseNegotiationEncKey struct {
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) {
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 {
return nil, err
}
defer resp.Body.Close()
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
View 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)
}

View 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()
}
}

View File

@@ -3,7 +3,6 @@ package auth
import (
"crypto/rand"
"crypto/rsa"
"encoding/base64"
"testing"
"github.com/fumiama/tienyik"
@@ -32,23 +31,8 @@ func TestNegotiationEncKey(t *testing.T) {
t.Logf("EncData: %s", r.EncData)
t.Logf("EncKey: %s", r.EncKey)
v, err := base64.StdEncoding.DecodeString(r.EncKey)
_, err = r.Unwrap(tyr)
if err != nil {
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
View 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
View 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
View 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
View File

@@ -5,10 +5,11 @@ go 1.24.4
require (
github.com/fumiama/go-base16384 v1.7.1
github.com/sirupsen/logrus v1.9.3
golang.org/x/net v0.28.0
)
require (
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
github.com/stretchr/testify v1.8.0 // indirect
golang.org/x/sys v0.23.0 // indirect
golang.org/x/text v0.17.0 // indirect
)

12
go.sum
View File

@@ -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/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
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.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
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/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.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=
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=

80
hcli/cli.go Normal file
View 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
}
}

View File

@@ -7,10 +7,12 @@ import (
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("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("Referer", base14.DecodeString("栝啇俌蠯姜吲融艹歛烦宸紀㴆"))
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)
if err != nil {
return nil, err
}
setCommonHeaders(req)
return http.DefaultClient.Do(req)
setCommonHeaders(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)
if err != nil {
return nil, err
}
setCommonHeaders(req)
return http.DefaultClient.Do(req)
setCommonHeaders(req, contentType)
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)
if err != nil {
return nil, err
}
setCommonHeaders(req)
return http.DefaultClient.Do(req)
setCommonHeaders(req, contentType)
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)
if err != nil {
return nil, err
}
setCommonHeaders(req)
return http.DefaultClient.Do(req)
setCommonHeaders(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)
if err != nil {
return nil, err
}
setCommonHeaders(req)
return http.DefaultClient.Do(req)
setCommonHeaders(req, contentType)
cli.setHeaders(req)
return DefaultClient.Do(req)
}

40
http.go Normal file
View 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")
}

View File

@@ -1,11 +1,9 @@
package textio
package tienyik
import (
"encoding/binary"
"net/url"
"testing"
"github.com/fumiama/tienyik"
)
func TestEUrlParams(t *testing.T) {
@@ -21,11 +19,12 @@ func TestEUrlParams(t *testing.T) {
binary.BigEndian.PutUint32(key[i*4:(i+1)*4], k)
}
t.Log(string(key[:])) // wxdispbis8txuueo26ffs2veqs18sism
tya := tienyik.NewAES(key[:])
params := EUrlParams(&tya, url.Values{
tya := NewAES(key[:])
params := tya.EUrlParams(url.Values{
"moduleCode": {"DESKTOP_MSGCENTER"},
})
q, err := ParseQuery(&tya, params)
t.Log(params)
q, err := tya.ParseQuery(params)
if err != nil {
t.Fatal(err)
}
@@ -48,7 +47,7 @@ func TestEUrlParamsMultiple(t *testing.T) {
for i, k := range rawkey {
binary.BigEndian.PutUint32(key[i*4:(i+1)*4], k)
}
tya := tienyik.NewAES(key[:])
tya := NewAES(key[:])
testCases := []struct {
name string
@@ -103,8 +102,8 @@ func TestEUrlParamsMultiple(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
params := EUrlParams(&tya, tc.params)
q, err := ParseQuery(&tya, params)
params := tya.EUrlParams(tc.params)
q, err := tya.ParseQuery(params)
if err != nil {
t.Fatal(err)
}

35
internal/horm/req.go Normal file
View 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)
}

View File

@@ -2,12 +2,18 @@ package hson
import (
"bytes"
"encoding/base64"
"encoding/json"
"github.com/fumiama/tienyik"
"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 {
w := bytes.NewBuffer(make([]byte, 0, 1024))
err := json.NewEncoder(w).Encode(v)
@@ -16,7 +22,9 @@ func Marshal(tya *tienyik.AES, v any) []byte {
}
log.Debugln("Marshal JSON:", w.String())
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()
}

View File

@@ -1,12 +1,8 @@
package textio
import (
"errors"
"net/url"
"runtime"
"strings"
"github.com/fumiama/tienyik"
)
func API() string {
@@ -42,29 +38,3 @@ func API() string {
sb.WriteString(p[1:])
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
View File

@@ -0,0 +1,6 @@
package textio
const (
ContenTypeForm = "application/x-www-form-urlencoded"
ContenTypeJSON = "application/json"
)

25
sha256.go Normal file
View 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]))
}