Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move utils into internal package #92

Merged
merged 1 commit into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
}
Loading