From 8eef351026d5654e6475b9a44bd9f6fd3525c753 Mon Sep 17 00:00:00 2001 From: Inhere Date: Thu, 8 Dec 2022 16:15:49 +0800 Subject: [PATCH] :necktie: up: str - update bytes util and add new hash utils - HashPasswd - VerifyPasswd --- strutil/bytes.go | 110 ++--------------------------------------- strutil/crypto.go | 54 ++++++++++++++++++++ strutil/crypto_test.go | 26 ++++++++++ strutil/encode.go | 25 ---------- strutil/encode_test.go | 7 --- 5 files changed, 85 insertions(+), 137 deletions(-) create mode 100644 strutil/crypto.go create mode 100644 strutil/crypto_test.go diff --git a/strutil/bytes.go b/strutil/bytes.go index fd1f54973..1b39b1832 100644 --- a/strutil/bytes.go +++ b/strutil/bytes.go @@ -1,69 +1,17 @@ package strutil import ( - "bytes" - "fmt" - "strings" + "github.com/gookit/goutil/byteutil" ) // Buffer wrap and extends the bytes.Buffer -type Buffer struct { - bytes.Buffer -} +type Buffer = byteutil.Buffer // NewBuffer instance func NewBuffer() *Buffer { return &Buffer{} } -// WriteAny type value to buffer -func (b *Buffer) WriteAny(vs ...any) { - for _, v := range vs { - _, _ = b.Buffer.WriteString(fmt.Sprint(v)) - } -} - -// QuietWriteByte to buffer -func (b *Buffer) QuietWriteByte(c byte) { - _ = b.WriteByte(c) -} - -// QuietWritef write message to buffer -func (b *Buffer) QuietWritef(tpl string, vs ...any) { - _, _ = b.WriteString(fmt.Sprintf(tpl, vs...)) -} - -// Writeln write message to buffer with newline -func (b *Buffer) Writeln(ss ...string) { - b.QuietWriteln(ss...) -} - -// QuietWriteln write message to buffer with newline -func (b *Buffer) QuietWriteln(ss ...string) { - _, _ = b.WriteString(strings.Join(ss, "")) - _ = b.WriteByte('\n') -} - -// QuietWriteString to buffer -func (b *Buffer) QuietWriteString(ss ...string) { - _, _ = b.WriteString(strings.Join(ss, "")) -} - -// MustWriteString to buffer -func (b *Buffer) MustWriteString(ss ...string) { - _, err := b.WriteString(strings.Join(ss, "")) - if err != nil { - panic(err) - } -} - -// ResetAndGet buffer string. -func (b *Buffer) ResetAndGet() string { - s := b.String() - b.Reset() - return s -} - // ByteChanPool struct // // Usage: @@ -72,57 +20,9 @@ func (b *Buffer) ResetAndGet() string { // buf:=bp.Get() // defer bp.Put(buf) // // use buf do something ... -// -// refer https://www.flysnow.org/2020/08/21/golang-chan-byte-pool.html -// from https://github.com/minio/minio/blob/master/internal/bpool/bpool.go -type ByteChanPool struct { - c chan []byte - w int - wcap int -} +type ByteChanPool = byteutil.ChanPool // NewByteChanPool instance -func NewByteChanPool(maxSize int, width int, capWidth int) *ByteChanPool { - return &ByteChanPool{ - c: make(chan []byte, maxSize), - w: width, - wcap: capWidth, - } -} - -// Get gets a []byte from the BytePool, or creates a new one if none are -// available in the pool. -func (bp *ByteChanPool) Get() (b []byte) { - select { - case b = <-bp.c: - // reuse existing buffer - default: - // create new buffer - if bp.wcap > 0 { - b = make([]byte, bp.w, bp.wcap) - } else { - b = make([]byte, bp.w) - } - } - return -} - -// Put returns the given Buffer to the BytePool. -func (bp *ByteChanPool) Put(b []byte) { - select { - case bp.c <- b: - // buffer went back into pool - default: - // buffer didn't go back into pool, just discard - } -} - -// Width returns the width of the byte arrays in this pool. -func (bp *ByteChanPool) Width() (n int) { - return bp.w -} - -// WidthCap returns the cap width of the byte arrays in this pool. -func (bp *ByteChanPool) WidthCap() (n int) { - return bp.wcap +func NewByteChanPool(maxSize, width, capWidth int) *ByteChanPool { + return byteutil.NewChanPool(maxSize, width, capWidth) } diff --git a/strutil/crypto.go b/strutil/crypto.go new file mode 100644 index 000000000..7c5337118 --- /dev/null +++ b/strutil/crypto.go @@ -0,0 +1,54 @@ +package strutil + +import ( + "crypto/hmac" + "crypto/md5" + "crypto/sha256" + "encoding/hex" + "fmt" +) + +// Md5 Generate a 32-bit md5 string +func Md5(src any) string { + return hex.EncodeToString(Md5Bytes(src)) +} + +// MD5 Generate a 32-bit md5 string +func MD5(src any) string { return Md5(src) } + +// GenMd5 Generate a 32-bit md5 string +func GenMd5(src any) string { return Md5(src) } + +// Md5Bytes Generate a 32-bit md5 bytes +func Md5Bytes(src any) []byte { + h := md5.New() + if s, ok := src.(string); ok { + h.Write([]byte(s)) + } else { + h.Write([]byte(fmt.Sprint(src))) + } + return h.Sum(nil) +} + +// HashPasswd for quick hash an input password string +func HashPasswd(pwd, key string) string { + hm := hmac.New(sha256.New, []byte(key)) + hm.Write([]byte(pwd)) + + return hex.EncodeToString(hm.Sum(nil)) +} + +// VerifyPasswd for quick verify input password is valid +// +// - pwdMAC from db or config, generated by EncryptPasswd() +func VerifyPasswd(pwdMAC, pwd, key string) bool { + decBts, err := hex.DecodeString(pwdMAC) + if err != nil { + return false + } + + hm := hmac.New(sha256.New, []byte(key)) + hm.Write([]byte(pwd)) + + return hmac.Equal(decBts, hm.Sum(nil)) +} diff --git a/strutil/crypto_test.go b/strutil/crypto_test.go new file mode 100644 index 000000000..8653f1032 --- /dev/null +++ b/strutil/crypto_test.go @@ -0,0 +1,26 @@ +package strutil_test + +import ( + "testing" + + "github.com/gookit/goutil/dump" + "github.com/gookit/goutil/strutil" + "github.com/gookit/goutil/testutil/assert" +) + +func TestMd5(t *testing.T) { + assert.Eq(t, "e10adc3949ba59abbe56e057f20f883e", strutil.Md5("123456")) + assert.Eq(t, "e10adc3949ba59abbe56e057f20f883e", strutil.MD5("123456")) + assert.Eq(t, "a906449d5769fa7361d7ecc6aa3f6d28", strutil.GenMd5("123abc")) + assert.Eq(t, "289dff07669d7a23de0ef88d2f7129e7", strutil.GenMd5(234)) +} + +func TestEncryptPasswd(t *testing.T) { + key := "ot54c" + pwd := "abc123456" + + msgMac := strutil.HashPasswd(pwd, key) + dump.P(msgMac) + assert.NotEmpty(t, msgMac) + assert.True(t, strutil.VerifyPasswd(msgMac, pwd, key)) +} diff --git a/strutil/encode.go b/strutil/encode.go index a102e1881..70d50a8e1 100644 --- a/strutil/encode.go +++ b/strutil/encode.go @@ -2,11 +2,8 @@ package strutil import ( "bytes" - "crypto/md5" "encoding/base32" "encoding/base64" - "encoding/hex" - "fmt" "net/url" "strings" "text/template" @@ -73,28 +70,6 @@ func StripSlashes(s string) string { // -------------------- encode -------------------- // -// Md5 Generate a 32-bit md5 string -func Md5(src any) string { - return hex.EncodeToString(Md5Bytes(src)) -} - -// MD5 Generate a 32-bit md5 string -func MD5(src any) string { return Md5(src) } - -// GenMd5 Generate a 32-bit md5 string -func GenMd5(src any) string { return Md5(src) } - -// Md5Bytes Generate a 32-bit md5 bytes -func Md5Bytes(src any) []byte { - h := md5.New() - if s, ok := src.(string); ok { - h.Write([]byte(s)) - } else { - h.Write([]byte(fmt.Sprint(src))) - } - return h.Sum(nil) -} - // URLEncode encode url string. func URLEncode(s string) string { if pos := strings.IndexRune(s, '?'); pos > -1 { // escape query data diff --git a/strutil/encode_test.go b/strutil/encode_test.go index c489912fb..f2a5b88fc 100644 --- a/strutil/encode_test.go +++ b/strutil/encode_test.go @@ -7,13 +7,6 @@ import ( "github.com/gookit/goutil/testutil/assert" ) -func TestMd5(t *testing.T) { - assert.Eq(t, "e10adc3949ba59abbe56e057f20f883e", strutil.Md5("123456")) - assert.Eq(t, "e10adc3949ba59abbe56e057f20f883e", strutil.MD5("123456")) - assert.Eq(t, "a906449d5769fa7361d7ecc6aa3f6d28", strutil.GenMd5("123abc")) - assert.Eq(t, "289dff07669d7a23de0ef88d2f7129e7", strutil.GenMd5(234)) -} - func TestEscape(t *testing.T) { tests := struct{ give, want string }{ "

some text

",