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

IT猿看视界 · · 786 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

今天在一个源码里面看到里面的 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, "", "")
}

有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:IT猿看视界

查看原文:GO 里面的比较好用的一些工具方法【值得收藏】

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

786 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传