GO-里面的比较好用的一些工具方法值得收藏

118次阅读

共计 5490 个字符,预计需要花费 14 分钟才能阅读完成。

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

// 这里是引入的包
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 操作

// 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

// 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 操作

// 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 操作

// 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, "","")
}

正文完
 0