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