mirror of
https://github.com/fumiama/tienyik.git
synced 2026-06-04 23:10:26 +08:00
feat: add log & supporting packages
This commit is contained in:
8
aes.go
8
aes.go
@@ -10,9 +10,9 @@ const (
|
|||||||
ETPYE_AES_CBC = "2"
|
ETPYE_AES_CBC = "2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TYAES [32]byte
|
type AES [32]byte
|
||||||
|
|
||||||
func NewTYAES(rawKey []byte) (tya TYAES) {
|
func NewAES(rawKey []byte) (tya AES) {
|
||||||
if len(rawKey) != 32 {
|
if len(rawKey) != 32 {
|
||||||
panic("len(key) must == 32")
|
panic("len(key) must == 32")
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ func pkcs7Unpadding(data []byte) []byte {
|
|||||||
return data[:len(data)-padding]
|
return data[:len(data)-padding]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tya TYAES) Encrypt(b []byte) []byte {
|
func (tya AES) Encrypt(b []byte) []byte {
|
||||||
blk, err := aes.NewCipher(tya[:])
|
blk, err := aes.NewCipher(tya[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -55,7 +55,7 @@ func (tya TYAES) Encrypt(b []byte) []byte {
|
|||||||
return ciphertext
|
return ciphertext
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tya TYAES) Decrypt(b []byte) ([]byte, error) {
|
func (tya AES) Decrypt(b []byte) ([]byte, error) {
|
||||||
blk, err := aes.NewCipher(tya[:])
|
blk, err := aes.NewCipher(tya[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ func TestDecrypt(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dat, err := NewTYAES(key[:]).Decrypt(d)
|
dat, err := NewAES(key[:]).Decrypt(d)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
29
api/auth/client.go
Normal file
29
api/auth/client.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
|
||||||
|
"github.com/fumiama/tienyik/internal/hcli"
|
||||||
|
"github.com/fumiama/tienyik/internal/hson"
|
||||||
|
"github.com/fumiama/tienyik/internal/textio"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RequestNegotiationEncKey struct {
|
||||||
|
CertData string `json:"certData"`
|
||||||
|
CertType string `json:"certType"`
|
||||||
|
Etype string `json:"etype"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseNegotiationEncKey struct {
|
||||||
|
EncData string `json:"encData"`
|
||||||
|
EncKey string `json:"encKey"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NegotiationEncKey(r *RequestNegotiationEncKey) (*ResponseNegotiationEncKey, error) {
|
||||||
|
resp, err := hcli.Post(textio.API(), bytes.NewReader(hson.Marshal(nil, r)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
return hson.Unmarshal[*ResponseNegotiationEncKey](nil, resp.Body)
|
||||||
|
}
|
||||||
54
api/auth/client_test.go
Normal file
54
api/auth/client_test.go
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"encoding/base64"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/fumiama/tienyik"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNegotiationEncKey(t *testing.T) {
|
||||||
|
logrus.SetLevel(logrus.DebugLevel)
|
||||||
|
|
||||||
|
k, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tyr := (*tienyik.RSA)(k)
|
||||||
|
tyr.E = 0x010001
|
||||||
|
|
||||||
|
r, err := NegotiationEncKey(&RequestNegotiationEncKey{
|
||||||
|
CertData: tyr.PublicKeyToSPKI(),
|
||||||
|
CertType: tienyik.ETPYE_AES_CBC,
|
||||||
|
Etype: tienyik.ETPYE_AES_CBC,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("EncData: %s", r.EncData)
|
||||||
|
t.Logf("EncKey: %s", r.EncKey)
|
||||||
|
|
||||||
|
v, err := base64.StdEncoding.DecodeString(r.EncKey)
|
||||||
|
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))
|
||||||
|
}
|
||||||
11
go.mod
11
go.mod
@@ -1,3 +1,14 @@
|
|||||||
module github.com/fumiama/tienyik
|
module github.com/fumiama/tienyik
|
||||||
|
|
||||||
go 1.24.4
|
go 1.24.4
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/fumiama/go-base16384 v1.7.1
|
||||||
|
github.com/sirupsen/logrus v1.9.3
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|||||||
22
go.sum
Normal file
22
go.sum
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/fumiama/go-base16384 v1.7.1 h1:1P1x6FWRvd7PtbH4idDAGWAjKKcVxggxlROYKRXbw58=
|
||||||
|
github.com/fumiama/go-base16384 v1.7.1/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
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/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=
|
||||||
|
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/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
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=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
18
internal/hcli/api.go
Normal file
18
internal/hcli/api.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package hcli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
base14 "github.com/fumiama/go-base16384"
|
||||||
|
"github.com/fumiama/tienyik/internal/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
var eps = base14.DecodeString("栝啇俌蠯姙呗宬籣欞敖蚹煮岎冃勀紀㴆")
|
||||||
|
|
||||||
|
func ep(p string) string {
|
||||||
|
sb := &strings.Builder{}
|
||||||
|
sb.WriteString(eps)
|
||||||
|
sb.WriteString(p)
|
||||||
|
log.Debugln("ep wraps:", sb)
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
65
internal/hcli/http.go
Normal file
65
internal/hcli/http.go
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package hcli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
base14 "github.com/fumiama/go-base16384"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setCommonHeaders(req *http.Request) {
|
||||||
|
req.Header.Set("Accept", "application/json")
|
||||||
|
req.Header.Set("Pragma", "no-cache")
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("Origin", base14.DecodeString("栝啇俌蠯姜吲融艹歛烦宸㴅"))
|
||||||
|
req.Header.Set("Referer", base14.DecodeString("栝啇俌蠯姜吲融艹歛烦宸紀㴆"))
|
||||||
|
req.Header.Set(
|
||||||
|
"User-Agent",
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Post(path 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Put(path 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Patch(path 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)
|
||||||
|
}
|
||||||
22
internal/hson/req.go
Normal file
22
internal/hson/req.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package hson
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/fumiama/tienyik"
|
||||||
|
"github.com/fumiama/tienyik/internal/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Marshal(tya *tienyik.AES, v any) []byte {
|
||||||
|
w := bytes.NewBuffer(make([]byte, 0, 1024))
|
||||||
|
err := json.NewEncoder(w).Encode(v)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
log.Debugln("Marshal JSON:", w.String())
|
||||||
|
if tya != nil {
|
||||||
|
return tya.Encrypt(w.Bytes())
|
||||||
|
}
|
||||||
|
return w.Bytes()
|
||||||
|
}
|
||||||
56
internal/hson/resp.go
Normal file
56
internal/hson/resp.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package hson
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/fumiama/tienyik"
|
||||||
|
"github.com/fumiama/tienyik/internal/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type responseBase[T any] struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Data T `json:"data"`
|
||||||
|
EData string `json:"edata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rb *responseBase[T]) ok() error {
|
||||||
|
if rb.Code != 0 {
|
||||||
|
return errors.New("[" + strconv.Itoa(rb.Code) + "] " + rb.Msg)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Unmarshal[T any](tya *tienyik.AES, r io.Reader) (data T, err error) {
|
||||||
|
var rsp responseBase[T]
|
||||||
|
err = json.NewDecoder(r).Decode(&rsp)
|
||||||
|
if err == nil {
|
||||||
|
err = rsp.ok()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(rsp.EData) > 0 && tya != nil {
|
||||||
|
var d []byte
|
||||||
|
d, err = base64.StdEncoding.DecodeString(rsp.EData)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d, err = tya.Decrypt(d)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debugln("decrypted data:", string(d))
|
||||||
|
err = json.Unmarshal(d, &rsp)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = rsp.ok()
|
||||||
|
}
|
||||||
|
data = rsp.Data
|
||||||
|
return
|
||||||
|
}
|
||||||
3
internal/log/def.go
Normal file
3
internal/log/def.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
const debug = true
|
||||||
103
internal/log/wrap.go
Normal file
103
internal/log/wrap.go
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/fumiama/tienyik/internal/textio"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Debug(args ...any) {
|
||||||
|
if debug {
|
||||||
|
args = append([]any{textio.Logger(2)}, args...)
|
||||||
|
logrus.Debug(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Debugf(format string, args ...any) {
|
||||||
|
if debug {
|
||||||
|
args = append([]any{textio.Logger(2)}, args...)
|
||||||
|
logrus.Debugf(format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Debugln(args ...any) {
|
||||||
|
if debug {
|
||||||
|
args = append([]any{textio.Logger(2)}, args...)
|
||||||
|
logrus.Debugln(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Info(args ...any) {
|
||||||
|
args = append([]any{textio.Logger(2)}, args...)
|
||||||
|
logrus.Info(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Infof(format string, args ...any) {
|
||||||
|
args = append([]any{textio.Logger(2)}, args...)
|
||||||
|
logrus.Infof(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Infoln(args ...any) {
|
||||||
|
args = append([]any{textio.Logger(2)}, args...)
|
||||||
|
logrus.Infoln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Warn(args ...any) {
|
||||||
|
args = append([]any{textio.Logger(2)}, args...)
|
||||||
|
logrus.Warn(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Warnf(format string, args ...any) {
|
||||||
|
args = append([]any{textio.Logger(2)}, args...)
|
||||||
|
logrus.Warnf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Warnln(args ...any) {
|
||||||
|
args = append([]any{textio.Logger(2)}, args...)
|
||||||
|
logrus.Warnln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Error(args ...any) {
|
||||||
|
args = append([]any{textio.Logger(2)}, args...)
|
||||||
|
logrus.Error(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Errorf(format string, args ...any) {
|
||||||
|
args = append([]any{textio.Logger(2)}, args...)
|
||||||
|
logrus.Errorf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Errorln(args ...any) {
|
||||||
|
args = append([]any{textio.Logger(2)}, args...)
|
||||||
|
logrus.Errorln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fatal(args ...any) {
|
||||||
|
args = append([]any{textio.Logger(2)}, args...)
|
||||||
|
logrus.Fatal(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fatalf(format string, args ...any) {
|
||||||
|
args = append([]any{textio.Logger(2)}, args...)
|
||||||
|
logrus.Fatalf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fatalln(args ...any) {
|
||||||
|
args = append([]any{textio.Logger(2)}, args...)
|
||||||
|
logrus.Fatalln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Panic(args ...any) {
|
||||||
|
args = append([]any{textio.Logger(2)}, args...)
|
||||||
|
logrus.Panic(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Panicf(format string, args ...any) {
|
||||||
|
args = append([]any{textio.Logger(2)}, args...)
|
||||||
|
logrus.Panicf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Panicln(args ...any) {
|
||||||
|
args = append([]any{textio.Logger(2)}, args...)
|
||||||
|
logrus.Panicln(args...)
|
||||||
|
}
|
||||||
8
internal/op/chain.go
Normal file
8
internal/op/chain.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package op
|
||||||
|
|
||||||
|
func Must[T any](x T, err error) T {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
70
internal/textio/api.go
Normal file
70
internal/textio/api.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package textio
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/fumiama/tienyik"
|
||||||
|
)
|
||||||
|
|
||||||
|
func API() string {
|
||||||
|
pc, f, _, ok := runtime.Caller(1)
|
||||||
|
if !ok {
|
||||||
|
panic("cannot get api of caller")
|
||||||
|
}
|
||||||
|
if strings.Contains(f, "\\") {
|
||||||
|
f = strings.ReplaceAll(f, "\\", "/")
|
||||||
|
}
|
||||||
|
_, p, ok := strings.Cut(f, "/tienyik/")
|
||||||
|
if !ok {
|
||||||
|
panic("cannot cut api " + f + " of caller")
|
||||||
|
}
|
||||||
|
f = strings.TrimSuffix(p, ".go")
|
||||||
|
fn := runtime.FuncForPC(pc)
|
||||||
|
if fn == nil {
|
||||||
|
panic("cannot get func name of caller, api: " + f)
|
||||||
|
}
|
||||||
|
p = fn.Name()
|
||||||
|
i := strings.LastIndex(p, ".")
|
||||||
|
if i < 0 {
|
||||||
|
panic("func name of caller '" + p + " has no '.', api: " + f)
|
||||||
|
}
|
||||||
|
p = p[i+1:]
|
||||||
|
if len(p) <= 1 {
|
||||||
|
panic("func name of caller '" + p + " too short', api: " + f)
|
||||||
|
}
|
||||||
|
sb := strings.Builder{}
|
||||||
|
sb.WriteString(f)
|
||||||
|
sb.WriteByte('/')
|
||||||
|
sb.WriteString(strings.ToLower(p[:1]))
|
||||||
|
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")
|
||||||
|
}
|
||||||
122
internal/textio/api_test.go
Normal file
122
internal/textio/api_test.go
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
package textio
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/fumiama/tienyik"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEUrlParams(t *testing.T) {
|
||||||
|
const aesplain = "moduleCode=DESKTOP_MSGCENTER"
|
||||||
|
var (
|
||||||
|
rawkey = []uint32{
|
||||||
|
2004378729, 1936745065, 1933079672, 1970627951,
|
||||||
|
842425958, 1932686949, 1903374648, 1936290669,
|
||||||
|
}
|
||||||
|
key [32]byte
|
||||||
|
)
|
||||||
|
for i, k := range rawkey {
|
||||||
|
binary.BigEndian.PutUint32(key[i*4:(i+1)*4], k)
|
||||||
|
}
|
||||||
|
t.Log(string(key[:])) // wxdispbis8txuueo26ffs2veqs18sism
|
||||||
|
tya := tienyik.NewAES(key[:])
|
||||||
|
params := EUrlParams(&tya, url.Values{
|
||||||
|
"moduleCode": {"DESKTOP_MSGCENTER"},
|
||||||
|
})
|
||||||
|
q, err := ParseQuery(&tya, params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for k, v := range q {
|
||||||
|
plainValue := k + "=" + v[0]
|
||||||
|
if plainValue != aesplain {
|
||||||
|
t.Fatal("expect", aesplain, "got", plainValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEUrlParamsMultiple(t *testing.T) {
|
||||||
|
var (
|
||||||
|
rawkey = []uint32{
|
||||||
|
2004378729, 1936745065, 1933079672, 1970627951,
|
||||||
|
842425958, 1932686949, 1903374648, 1936290669,
|
||||||
|
}
|
||||||
|
key [32]byte
|
||||||
|
)
|
||||||
|
for i, k := range rawkey {
|
||||||
|
binary.BigEndian.PutUint32(key[i*4:(i+1)*4], k)
|
||||||
|
}
|
||||||
|
tya := tienyik.NewAES(key[:])
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
params url.Values
|
||||||
|
expected map[string]string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "single parameter",
|
||||||
|
params: url.Values{
|
||||||
|
"userId": {"12345"},
|
||||||
|
},
|
||||||
|
expected: map[string]string{
|
||||||
|
"userId": "12345",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple parameters",
|
||||||
|
params: url.Values{
|
||||||
|
"userId": {"12345"},
|
||||||
|
"userName": {"testUser"},
|
||||||
|
"status": {"active"},
|
||||||
|
},
|
||||||
|
expected: map[string]string{
|
||||||
|
"userId": "12345",
|
||||||
|
"userName": "testUser",
|
||||||
|
"status": "active",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "special characters",
|
||||||
|
params: url.Values{
|
||||||
|
"email": {"test@example.com"},
|
||||||
|
"message": {"Hello World!"},
|
||||||
|
},
|
||||||
|
expected: map[string]string{
|
||||||
|
"email": "test@example.com",
|
||||||
|
"message": "Hello World!",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "chinese characters",
|
||||||
|
params: url.Values{
|
||||||
|
"name": {"张三"},
|
||||||
|
"city": {"北京"},
|
||||||
|
},
|
||||||
|
expected: map[string]string{
|
||||||
|
"name": "张三",
|
||||||
|
"city": "北京",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
params := EUrlParams(&tya, tc.params)
|
||||||
|
q, err := ParseQuery(&tya, params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for key, expectedValue := range tc.expected {
|
||||||
|
if vals, ok := q[key]; ok && len(vals) > 0 {
|
||||||
|
if vals[0] != expectedValue {
|
||||||
|
t.Fatalf("key %s: expect %s, got %s", key, expectedValue, vals[0])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Fatalf("key %s not found in query", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
64
internal/textio/name.go
Normal file
64
internal/textio/name.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package textio
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Logger(skip int) string {
|
||||||
|
sb := strings.Builder{}
|
||||||
|
sb.WriteString("[")
|
||||||
|
sb.WriteString(FileName(skip + 1))
|
||||||
|
sb.WriteString("]")
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func FileName(skip int) string {
|
||||||
|
_, file, _, ok := runtime.Caller(skip)
|
||||||
|
if !ok {
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
i := strings.LastIndex(file, "/")
|
||||||
|
if i < 0 {
|
||||||
|
i = strings.LastIndex(file, "\\")
|
||||||
|
if i < 0 {
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nm := file[i+1:]
|
||||||
|
if len(nm) == 0 {
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
i = strings.LastIndex(nm, ".")
|
||||||
|
if i <= 0 {
|
||||||
|
return nm
|
||||||
|
}
|
||||||
|
return nm[:i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func FuncName(skip int, lowerfirst bool) string {
|
||||||
|
fn, _, _, ok := runtime.Caller(skip)
|
||||||
|
if !ok {
|
||||||
|
panic("cannot get func name of caller")
|
||||||
|
}
|
||||||
|
f := runtime.FuncForPC(fn)
|
||||||
|
if f == nil {
|
||||||
|
panic("invalid func pc")
|
||||||
|
}
|
||||||
|
p := f.Name()
|
||||||
|
i := strings.LastIndex(p, ".")
|
||||||
|
if i < 0 {
|
||||||
|
panic("func name of caller '" + p + " has no '.'")
|
||||||
|
}
|
||||||
|
p = p[i+1:]
|
||||||
|
if len(p) <= 1 {
|
||||||
|
panic("func name of caller '" + p + " too short'")
|
||||||
|
}
|
||||||
|
if lowerfirst {
|
||||||
|
sb := strings.Builder{}
|
||||||
|
sb.WriteString(strings.ToLower(p[:1]))
|
||||||
|
sb.WriteString(p[1:])
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
13
internal/textio/str.go
Normal file
13
internal/textio/str.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package textio
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
// BytesToString 没有内存开销的转换
|
||||||
|
func BytesToString(b []byte) string {
|
||||||
|
return *(*string)(unsafe.Pointer(&b))
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToBytes 没有内存开销的转换
|
||||||
|
func StringToBytes(s string) (b []byte) {
|
||||||
|
return unsafe.Slice(unsafe.StringData(s), len(s))
|
||||||
|
}
|
||||||
10
rsa.go
10
rsa.go
@@ -7,19 +7,19 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TYRSA rsa.PrivateKey
|
type RSA rsa.PrivateKey
|
||||||
|
|
||||||
func NewTYRSA() *TYRSA {
|
func NewRSA() *RSA {
|
||||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
privateKey.E = 0x010001
|
privateKey.E = 0x010001
|
||||||
|
|
||||||
return (*TYRSA)(privateKey)
|
return (*RSA)(privateKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tyr *TYRSA) PublicKeyToSPKI() string {
|
func (tyr *RSA) PublicKeyToSPKI() string {
|
||||||
spkiBytes, err := x509.MarshalPKIXPublicKey(&tyr.PublicKey)
|
spkiBytes, err := x509.MarshalPKIXPublicKey(&tyr.PublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -27,6 +27,6 @@ func (tyr *TYRSA) PublicKeyToSPKI() string {
|
|||||||
return base64.StdEncoding.EncodeToString(spkiBytes)
|
return base64.StdEncoding.EncodeToString(spkiBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tyr *TYRSA) Decrypt(ciphertext []byte) ([]byte, error) {
|
func (tyr *RSA) Decrypt(ciphertext []byte) ([]byte, error) {
|
||||||
return rsa.DecryptPKCS1v15(rand.Reader, (*rsa.PrivateKey)(tyr), ciphertext)
|
return rsa.DecryptPKCS1v15(rand.Reader, (*rsa.PrivateKey)(tyr), ciphertext)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func TestRSANegotiationEncKey(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
tyr := (*TYRSA)(k.(*rsa.PrivateKey))
|
tyr := (*RSA)(k.(*rsa.PrivateKey))
|
||||||
tyr.E = 0x010001
|
tyr.E = 0x010001
|
||||||
|
|
||||||
w := bytes.NewBuffer(make([]byte, 0, 1024))
|
w := bytes.NewBuffer(make([]byte, 0, 1024))
|
||||||
@@ -86,7 +86,7 @@ func TestRSANegotiationEncKey(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
v, err = NewTYAES([]byte(aesk)).Decrypt(v)
|
v, err = NewAES([]byte(aesk)).Decrypt(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user