Skip to content

Commit

Permalink
move utils into internal package
Browse files Browse the repository at this point in the history
  • Loading branch information
JacksonTian committed Aug 16, 2024
1 parent e6ece0c commit 025af96
Show file tree
Hide file tree
Showing 2 changed files with 298 additions and 0 deletions.
146 changes: 146 additions & 0 deletions credentials/internal/utils/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package utils

import (
"crypto"
"crypto/hmac"
"crypto/md5"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"hash"
"io"
rand2 "math/rand"
"net/url"
"time"
)

type uuid [16]byte

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

var hookRead = func(fn func(p []byte) (n int, err error)) func(p []byte) (n int, err error) {
return fn
}

var hookRSA = func(fn func(rand io.Reader, priv *rsa.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error)) func(rand io.Reader, priv *rsa.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) {
return fn
}

// GetUUID returns a uuid
func GetUUID() (uuidHex string) {
uuid := newUUID()
uuidHex = hex.EncodeToString(uuid[:])
return
}

// RandStringBytes returns a rand string
func RandStringBytes(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = letterBytes[rand2.Intn(len(letterBytes))]
}
return string(b)
}

// ShaHmac1 return a string which has been hashed
func ShaHmac1(source, secret string) string {
key := []byte(secret)
hmac := hmac.New(sha1.New, key)
hmac.Write([]byte(source))
signedBytes := hmac.Sum(nil)
signedString := base64.StdEncoding.EncodeToString(signedBytes)
return signedString
}

// Sha256WithRsa return a string which has been hashed with Rsa
func Sha256WithRsa(source, secret string) string {
decodeString, err := base64.StdEncoding.DecodeString(secret)
if err != nil {
panic(err)
}
private, err := x509.ParsePKCS8PrivateKey(decodeString)
if err != nil {
panic(err)
}

h := crypto.Hash.New(crypto.SHA256)
h.Write([]byte(source))
hashed := h.Sum(nil)
signature, err := hookRSA(rsa.SignPKCS1v15)(rand.Reader, private.(*rsa.PrivateKey),
crypto.SHA256, hashed)
if err != nil {
panic(err)
}

return base64.StdEncoding.EncodeToString(signature)
}

// GetMD5Base64 returns a string which has been base64
func GetMD5Base64(bytes []byte) (base64Value string) {
md5Ctx := md5.New()
md5Ctx.Write(bytes)
md5Value := md5Ctx.Sum(nil)
base64Value = base64.StdEncoding.EncodeToString(md5Value)
return
}

// GetTimeInFormatISO8601 returns a time string
func GetTimeInFormatISO8601() (timeStr string) {
gmt := time.FixedZone("GMT", 0)

return time.Now().In(gmt).Format("2006-01-02T15:04:05Z")
}

// GetURLFormedMap returns a url encoded string
func GetURLFormedMap(source map[string]string) (urlEncoded string) {
urlEncoder := url.Values{}
for key, value := range source {
urlEncoder.Add(key, value)
}
urlEncoded = urlEncoder.Encode()
return
}

func newUUID() uuid {
ns := uuid{}
safeRandom(ns[:])
u := newFromHash(md5.New(), ns, RandStringBytes(16))
u[6] = (u[6] & 0x0f) | (byte(2) << 4)
u[8] = (u[8]&(0xff>>2) | (0x02 << 6))

return u
}

func newFromHash(h hash.Hash, ns uuid, name string) uuid {
u := uuid{}
h.Write(ns[:])
h.Write([]byte(name))
copy(u[:], h.Sum(nil))

return u
}

func safeRandom(dest []byte) {
if _, err := hookRead(rand.Read)(dest); err != nil {
panic(err)
}
}

func (u uuid) String() string {
buf := make([]byte, 36)

hex.Encode(buf[0:8], u[0:4])
buf[8] = '-'
hex.Encode(buf[9:13], u[4:6])
buf[13] = '-'
hex.Encode(buf[14:18], u[6:8])
buf[18] = '-'
hex.Encode(buf[19:23], u[8:10])
buf[23] = '-'
hex.Encode(buf[24:], u[10:])

return string(buf)
}
152 changes: 152 additions & 0 deletions credentials/internal/utils/utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package utils

import (
"crypto"
"crypto/rsa"
"errors"
"io"
"regexp"
"testing"

"github.com/stretchr/testify/assert"
)

func TestGetUUID(t *testing.T) {
uuid := newUUID()
assert.Equal(t, 16, len(uuid))
assert.Equal(t, 36, len(uuid.String()))
uuidString := GetUUID()
assert.Equal(t, 32, len(uuidString))
}

func TestGetMD5Base64(t *testing.T) {
assert.Equal(t, "ERIHLmRX2uZmssDdxQnnxQ==",
GetMD5Base64([]byte("That's all folks!!")))
assert.Equal(t, "GsJRdI3kAbAnHo/0+3wWJw==",
GetMD5Base64([]byte("中文也没啥问题")))
}

func TestGetTimeInFormatISO8601(t *testing.T) {
s := GetTimeInFormatISO8601()
assert.Equal(t, 20, len(s))
// 2006-01-02T15:04:05Z
re := regexp.MustCompile(`^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$`)
assert.True(t, re.MatchString(s))
}

func TestGetURLFormedMap(t *testing.T) {
m := make(map[string]string)
m["key"] = "value"
s := GetURLFormedMap(m)
assert.Equal(t, "key=value", s)
m["key2"] = "http://domain/?key=value&key2=value2"
s2 := GetURLFormedMap(m)
assert.Equal(t, "key=value&key2=http%3A%2F%2Fdomain%2F%3Fkey%3Dvalue%26key2%3Dvalue2", s2)
}

func TestShaHmac1(t *testing.T) {
result := ShaHmac1("source", "secret")
assert.Equal(t, "Jv4yi8SobFhg5t1C7nWLbhBSFZQ=", result)

assert.Equal(t, "CqCYIa39h9SSWuXnTz8F5hh9UPA=", ShaHmac1("中文", "secret"))
}

func TestSha256WithRsa(t *testing.T) {
secret := `
MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAOJC+2WXtkXZ+6sa
3+qJp4mDOsiZb3BghHT9nVbjTeaw4hsZWHYxQ6l6XDmTg4twPB59LOGAlAjYrT31
3pdwEawnmdf6zyF93Zvxxpy7lO2HoxYKSjbtXO4I0pcq3WTnw2xlbhqHvrcuWwt+
FqH9akzcnwHjc03siZBzt/dwDL3vAgMBAAECgYEAzwgZPqFuUEYgaTVDFDl2ynYA
kNMMzBgUu3Pgx0Nf4amSitdLQYLcdbQXtTtMT4eYCxHgwkpDqkCRbLOQRKNwFo0I
oaCuhjZlxWcKil4z4Zb/zB7gkeuXPOVUjFSS3FogsRWMtnNAMgR/yJRlbcg/Puqk
Magt/yDk+7cJCe6H96ECQQDxMT4S+tVP9nOw//QT39Dk+kWe/YVEhnWnCMZmGlEq
1gnN6qpUi68ts6b3BVgrDPrPN6wm/Z9vpcKNeWpIvxXRAkEA8CcT2UEUwDGRKAUu
WVPJqdAJjpjc072eRF5g792NyO+TAF6thBlDKNslRvFQDB6ymLsjfy8JYCnGbbSb
WqbHvwJBAIs7KeI6+jiWxGJA3t06LpSABQCqyOut0u0Bm8YFGyXnOPGtrXXwzMdN
Fe0zIJp5e69zK+W2Mvt4bL7OgBROeoECQQDsE+4uLw0gFln0tosmovhmp60NcfX7
bLbtzL2MbwbXlbOztF7ssgzUWAHgKI6hK3g0LhsqBuo3jzmSVO43giZvAkEA08Nm
2TI9EvX6DfCVfPOiKZM+Pijh0xLN4Dn8qUgt3Tcew/vfj4WA2ZV6qiJqL01vMsHc
vftlY0Hs1vNXcaBgEA==`
result := Sha256WithRsa("source", secret)
assert.Equal(t, "UNyJPD27jjSNl70b02E/DUtgtNESdtAuxbNBZTlksk1t/GYjiQNRlFIubp/EGKcWsqs7p5SFKnNiSRqWG3A51VmJFBXXtyW1nwLC9xY/MbUj6JVWNYCuLkPWM942O+GAk7N+G8ZQZt7ib2MhruDAUmv1lLN26lDaCPBX2MJQJCo=", result)

assert.Equal(t, "CKE0osxUnFFH+oYP3Q427saucBuignE+Mrni63G9w46yZFtVoXFOu5lNiNCnUtaPNpGmBf9X5oGCY+otqPf7bP93nB59rfdteQs0sS65PWH9yjH8RwYCWGCbuyRul/0qIv/nYYGzkLON1C1Vx9Z4Yep6llYuJang5RIXrAkQLmQ=", Sha256WithRsa("中文", secret))
}

func TestSha256WithRsa_DecodeString_Error(t *testing.T) {
defer func() { // 进行异常捕捉
err := recover()
assert.NotNil(t, err)
assert.Equal(t, "illegal base64 data at input byte 0", err.(error).Error())
}()
secret := `==`
Sha256WithRsa("source", secret)
}

func TestSha256WithRsa_ParsePKCS8PrivateKey_Error(t *testing.T) {
defer func() { // 进行异常捕捉
err := recover()
assert.NotNil(t, err)
assert.Equal(t, "asn1: structure error: length too large", err.(error).Error())
}()
secret := `Jv4yi8SobFhg5t1C7nWLbhBSFZQ=`
Sha256WithRsa("source", secret)
}

func TestHookRead(t *testing.T) {
fn := func(p []byte) (n int, err error) {
return 0, errors.New("hookRead")
}
result := hookRead(fn)
n, err := result(nil)
assert.Equal(t, 0, n)
assert.Equal(t, "hookRead", err.Error())

originHookRead := hookRead
hookRead = func(old func(p []byte) (n int, err error)) func(p []byte) (n int, err error) {
return fn
}
defer func() {
err := recover()
assert.Equal(t, "hookRead", err.(error).Error())
hookRead = originHookRead
}()
safeRandom([]byte("credentialtest"))
}

func TestHookRSA(t *testing.T) {
fn := func(rand io.Reader, priv *rsa.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) {
return nil, errors.New("hookRSA")
}
result := hookRSA(fn)
hash := crypto.Hash(10)
byt, err := result(nil, nil, hash, nil)
assert.Nil(t, byt)
assert.Equal(t, "hookRSA", err.Error())

originHookRSA := hookRSA
hookRSA = func(old func(rand io.Reader, priv *rsa.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error)) func(rand io.Reader, priv *rsa.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) {
return fn
}
defer func() {
err := recover()
assert.Equal(t, "hookRSA", err.(error).Error())
hookRSA = originHookRSA
}()
secret := `
MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAOJC+2WXtkXZ+6sa
3+qJp4mDOsiZb3BghHT9nVbjTeaw4hsZWHYxQ6l6XDmTg4twPB59LOGAlAjYrT31
3pdwEawnmdf6zyF93Zvxxpy7lO2HoxYKSjbtXO4I0pcq3WTnw2xlbhqHvrcuWwt+
FqH9akzcnwHjc03siZBzt/dwDL3vAgMBAAECgYEAzwgZPqFuUEYgaTVDFDl2ynYA
kNMMzBgUu3Pgx0Nf4amSitdLQYLcdbQXtTtMT4eYCxHgwkpDqkCRbLOQRKNwFo0I
oaCuhjZlxWcKil4z4Zb/zB7gkeuXPOVUjFSS3FogsRWMtnNAMgR/yJRlbcg/Puqk
Magt/yDk+7cJCe6H96ECQQDxMT4S+tVP9nOw//QT39Dk+kWe/YVEhnWnCMZmGlEq
1gnN6qpUi68ts6b3BVgrDPrPN6wm/Z9vpcKNeWpIvxXRAkEA8CcT2UEUwDGRKAUu
WVPJqdAJjpjc072eRF5g792NyO+TAF6thBlDKNslRvFQDB6ymLsjfy8JYCnGbbSb
WqbHvwJBAIs7KeI6+jiWxGJA3t06LpSABQCqyOut0u0Bm8YFGyXnOPGtrXXwzMdN
Fe0zIJp5e69zK+W2Mvt4bL7OgBROeoECQQDsE+4uLw0gFln0tosmovhmp60NcfX7
bLbtzL2MbwbXlbOztF7ssgzUWAHgKI6hK3g0LhsqBuo3jzmSVO43giZvAkEA08Nm
2TI9EvX6DfCVfPOiKZM+Pijh0xLN4Dn8qUgt3Tcew/vfj4WA2ZV6qiJqL01vMsHc
vftlY0Hs1vNXcaBgEA==`
Sha256WithRsa("source", secret)
}

0 comments on commit 025af96

Please sign in to comment.