0%

【Go】比较好用的一些工具方法【值得收藏】

今天在一个源码里面看到里面的 util 包,里面的好多的工具都是我们可以直接拿来使用的,之前没有这个习惯,所以每次就喜欢到处找。现在开始在这些源码里面去记录一下。方便日后的使用。

1
2
3
4
5
6
7
8
9
10
11
12
// 这里是引入的包
import (
"crypto/rand"
"crypto/sha256"
"crypto/md5"
"encoding/base64"
"encoding/hex"
"errors"
"golang.org/x/crypto/pbkdf2"
"strings"
"github.com/grafana/grafana/pkg/util/errutil"
)

Encode 操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// GetRandomString generate random string by specify chars.
// 通过指定字符生成随机字符串
func GetRandomString(n int, alphabets ...byte) (string, error) {
const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
var bytes = make([]byte, n)
if _, err := rand.Read(bytes); err != nil {
return "", err
}

for i, b := range bytes {
if len(alphabets) == 0 {
bytes[i] = alphanum[b%byte(len(alphanum))]
} else {
bytes[i] = alphabets[b%byte(len(alphabets))]
}
}
return string(bytes), nil
}

// EncodePassword encodes a password using PBKDF2.
// 使用PBKDF2对密码进行编码
func EncodePassword(password string, salt string) (string, error) {
newPasswd := pbkdf2.Key([]byte(password), []byte(salt), 10000, 50, sha256.New)
return hex.EncodeToString(newPasswd), nil
}

// GetBasicAuthHeader returns a base64 encoded string from user and password.
// 从用户和密码返回base64编码的字符串。
func GetBasicAuthHeader(user string, password string) string {
var userAndPass = user + ":" + password
return "Basic " + base64.StdEncoding.EncodeToString([]byte(userAndPass))
}

// DecodeBasicAuthHeader decodes user and password from a basic auth header.
// 从基本的auth标头解码用户和密码。
func DecodeBasicAuthHeader(header string) (string, string, error) {
var code string
parts := strings.SplitN(header, " ", 2)
if len(parts) == 2 && parts[0] == "Basic" {
code = parts[1]
}

decoded, err := base64.StdEncoding.DecodeString(code)
if err != nil {
return "", "", err
}

userAndPass := strings.SplitN(string(decoded), ":", 2)
if len(userAndPass) != 2 {
return "", "", errors.New("Invalid basic auth header")
}

return userAndPass[0], userAndPass[1], nil
}

// RandomHex returns a random string from a n seed.
// 从n个种子返回一个随机字符串。
func RandomHex(n int) (string, error) {
bytes := make([]byte, n)
if _, err := rand.Read(bytes); err != nil {
return "", err
}
return hex.EncodeToString(bytes), nil
}

Decrypt / Encrypt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// Decrypt decrypts a payload with a given secret.
func Decrypt(payload []byte, secret string) ([]byte, error) {
salt := payload[:saltLength]
key, err := encryptionKeyToBytes(secret, string(salt))
if err != nil {
return nil, err
}

block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}

// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
if len(payload) < aes.BlockSize {
return nil, errors.New("payload too short")
}
iv := payload[saltLength : saltLength+aes.BlockSize]
payload = payload[saltLength+aes.BlockSize:]
payloadDst := make([]byte, len(payload))

stream := cipher.NewCFBDecrypter(block, iv)

// XORKeyStream can work in-place if the two arguments are the same.
stream.XORKeyStream(payloadDst, payload)
return payloadDst, nil
}

// Encrypt encrypts a payload with a given secret.
func Encrypt(payload []byte, secret string) ([]byte, error) {
salt, err := GetRandomString(saltLength)
if err != nil {
return nil, err
}

key, err := encryptionKeyToBytes(secret, salt)
if err != nil {
return nil, err
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}

// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
ciphertext := make([]byte, saltLength+aes.BlockSize+len(payload))
copy(ciphertext[:saltLength], []byte(salt))
iv := ciphertext[saltLength : saltLength+aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}

stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(ciphertext[saltLength+aes.BlockSize:], payload)

return ciphertext, nil
}

// Key needs to be 32bytes
func encryptionKeyToBytes(secret, salt string) ([]byte, error) {
return pbkdf2.Key([]byte(secret), []byte(salt), 10000, 32, sha256.New), nil
}

MD5 操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Md5Sum calculates the md5sum of a stream
// 计算流的md5sum
func Md5Sum(reader io.Reader) (string, error) {
var returnMD5String string
hash := md5.New()
if _, err := io.Copy(hash, reader); err != nil {
return returnMD5String, err
}
hashInBytes := hash.Sum(nil)[:16]
returnMD5String = hex.EncodeToString(hashInBytes)
return returnMD5String, nil
}

// Md5SumString calculates the md5sum of a string
// 计算字符串的md5sum
func Md5SumString(input string) (string, error) {
buffer := strings.NewReader(input)
return Md5Sum(buffer)
}

IP 操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// ParseIPAddress parses an IP address and removes port and/or IPV6 format
func ParseIPAddress(input string) (string, error) {
addr, err := SplitHostPort(input)
if err != nil {
return "", errutil.Wrapf(err, "Failed to split network address '%s' by host and port",
input)
}

ip := net.ParseIP(addr.Host)
if ip == nil {
return addr.Host, nil
}

if ip.IsLoopback() {
if strings.Contains(addr.Host, ":") {
// IPv6
return "::1", nil
}
return "127.0.0.1", nil
}

return ip.String(), nil
}

type NetworkAddress struct {
Host string
Port string
}

// SplitHostPortDefault splits ip address/hostname string by host and port. Defaults used if no match found
func SplitHostPortDefault(input, defaultHost, defaultPort string) (NetworkAddress, error) {
addr := NetworkAddress{
Host: defaultHost,
Port: defaultPort,
}
if len(input) == 0 {
return addr, nil
}

start := 0
// Determine if IPv6 address, in which case IP address will be enclosed in square brackets
if strings.Index(input, "[") == 0 {
addrEnd := strings.LastIndex(input, "]")
if addrEnd < 0 {
// Malformed address
return addr, fmt.Errorf("Malformed IPv6 address: '%s'", input)
}

start = addrEnd
}
if strings.LastIndex(input[start:], ":") < 0 {
// There's no port section of the input
// It's still useful to call net.SplitHostPort though, since it removes IPv6
// square brackets from the address
input = fmt.Sprintf("%s:%s", input, defaultPort)
}

host, port, err := net.SplitHostPort(input)
if err != nil {
return addr, errutil.Wrapf(err, "net.SplitHostPort failed for '%s'", input)
}

if len(host) > 0 {
addr.Host = host
}
if len(port) > 0 {
addr.Port = port
}

return addr, nil
}

// SplitHostPort splits ip address/hostname string by host and port
func SplitHostPort(input string) (NetworkAddress, error) {
if len(input) == 0 {
return NetworkAddress{}, fmt.Errorf("Input is empty")
}
return SplitHostPortDefault(input, "", "")
}

Env

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// GetEnvAsStringOrFallback returns the env variable for the given key
// and falls back to the given defaultValue if not set
func GetEnvAsStringOrFallback(key, defaultValue string) string {
if v := os.Getenv(key); v != "" {
return v
}
return defaultValue
}

// GetEnvAsIntOrFallback returns the env variable (parsed as integer) for
// the given key and falls back to the given defaultValue if not set
func GetEnvAsIntOrFallback(key string, defaultValue int) (int, error) {
if v := os.Getenv(key); v != "" {
value, err := strconv.Atoi(v)
if err != nil {
return defaultValue, err
}
return value, nil
}
return defaultValue, nil
}

// GetEnvAsFloat64OrFallback returns the env variable (parsed as float64) for
// the given key and falls back to the given defaultValue if not set
func GetEnvAsFloat64OrFallback(key string, defaultValue float64) (float64, error) {
if v := os.Getenv(key); v != "" {
value, err := strconv.ParseFloat(v, 64)
if err != nil {
return defaultValue, err
}
return value, nil
}
return defaultValue, nil
}
这是打赏的地方...

本文标题:【Go】比较好用的一些工具方法【值得收藏】

文章作者:Mr.Sun

发布时间:2020年06月04日 - 15:02:08

最后更新:2020年06月10日 - 14:30:48

原始链接:http://www.blog.sun-iot.xyz/posts/bbbe4f17

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

---------Thanks for your attention---------