utils.go raw

   1  package utils
   2  
   3  import (
   4  	"bytes"
   5  	"crypto"
   6  	"crypto/hmac"
   7  	"crypto/md5"
   8  	"crypto/rand"
   9  	"crypto/rsa"
  10  	"crypto/sha1"
  11  	"crypto/x509"
  12  	"encoding/base64"
  13  	"encoding/hex"
  14  	"fmt"
  15  	"hash"
  16  	"io"
  17  	mathrand "math/rand"
  18  	"net/url"
  19  	"os"
  20  	"runtime"
  21  	"strconv"
  22  	"sync/atomic"
  23  	"time"
  24  )
  25  
  26  type uuid [16]byte
  27  
  28  const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  29  
  30  var hookRead = func(fn func(p []byte) (n int, err error)) func(p []byte) (n int, err error) {
  31  	return fn
  32  }
  33  
  34  var hookRSA = func(fn func(rand io.Reader, priv *rsa.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error)) func(rand io.Reader, priv *rsa.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) {
  35  	return fn
  36  }
  37  
  38  // GetUUID returns a uuid
  39  func GetUUID() (uuidHex string) {
  40  	uuid := newUUID()
  41  	uuidHex = hex.EncodeToString(uuid[:])
  42  	return
  43  }
  44  
  45  // RandStringBytes returns a rand string
  46  func RandStringBytes(n int) string {
  47  	b := make([]byte, n)
  48  	for i := range b {
  49  		b[i] = letterBytes[mathrand.Intn(len(letterBytes))]
  50  	}
  51  	return string(b)
  52  }
  53  
  54  // ShaHmac1 return a string which has been hashed
  55  func ShaHmac1(source, secret string) string {
  56  	key := []byte(secret)
  57  	hmac := hmac.New(sha1.New, key)
  58  	hmac.Write([]byte(source))
  59  	signedBytes := hmac.Sum(nil)
  60  	signedString := base64.StdEncoding.EncodeToString(signedBytes)
  61  	return signedString
  62  }
  63  
  64  // Sha256WithRsa return a string which has been hashed with Rsa
  65  func Sha256WithRsa(source, secret string) string {
  66  	decodeString, err := base64.StdEncoding.DecodeString(secret)
  67  	if err != nil {
  68  		panic(err)
  69  	}
  70  	private, err := x509.ParsePKCS8PrivateKey(decodeString)
  71  	if err != nil {
  72  		panic(err)
  73  	}
  74  
  75  	h := crypto.Hash.New(crypto.SHA256)
  76  	h.Write([]byte(source))
  77  	hashed := h.Sum(nil)
  78  	signature, err := hookRSA(rsa.SignPKCS1v15)(rand.Reader, private.(*rsa.PrivateKey),
  79  		crypto.SHA256, hashed)
  80  	if err != nil {
  81  		panic(err)
  82  	}
  83  
  84  	return base64.StdEncoding.EncodeToString(signature)
  85  }
  86  
  87  // GetMD5Base64 returns a string which has been base64
  88  func GetMD5Base64(bytes []byte) (base64Value string) {
  89  	md5Ctx := md5.New()
  90  	md5Ctx.Write(bytes)
  91  	md5Value := md5Ctx.Sum(nil)
  92  	base64Value = base64.StdEncoding.EncodeToString(md5Value)
  93  	return
  94  }
  95  
  96  // GetTimeInFormatISO8601 returns a time string
  97  func GetTimeInFormatISO8601() (timeStr string) {
  98  	gmt := time.FixedZone("GMT", 0)
  99  
 100  	return time.Now().In(gmt).Format("2006-01-02T15:04:05Z")
 101  }
 102  
 103  // GetURLFormedMap returns a url encoded string
 104  func GetURLFormedMap(source map[string]string) (urlEncoded string) {
 105  	urlEncoder := url.Values{}
 106  	for key, value := range source {
 107  		urlEncoder.Add(key, value)
 108  	}
 109  	urlEncoded = urlEncoder.Encode()
 110  	return
 111  }
 112  
 113  func newUUID() uuid {
 114  	ns := uuid{}
 115  	safeRandom(ns[:])
 116  	u := newFromHash(md5.New(), ns, RandStringBytes(16))
 117  	u[6] = (u[6] & 0x0f) | (byte(2) << 4)
 118  	u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
 119  
 120  	return u
 121  }
 122  
 123  func newFromHash(h hash.Hash, ns uuid, name string) uuid {
 124  	u := uuid{}
 125  	h.Write(ns[:])
 126  	h.Write([]byte(name))
 127  	copy(u[:], h.Sum(nil))
 128  
 129  	return u
 130  }
 131  
 132  func safeRandom(dest []byte) {
 133  	if _, err := hookRead(rand.Read)(dest); err != nil {
 134  		panic(err)
 135  	}
 136  }
 137  
 138  func (u uuid) String() string {
 139  	buf := make([]byte, 36)
 140  
 141  	hex.Encode(buf[0:8], u[0:4])
 142  	buf[8] = '-'
 143  	hex.Encode(buf[9:13], u[4:6])
 144  	buf[13] = '-'
 145  	hex.Encode(buf[14:18], u[6:8])
 146  	buf[18] = '-'
 147  	hex.Encode(buf[19:23], u[8:10])
 148  	buf[23] = '-'
 149  	hex.Encode(buf[24:], u[10:])
 150  
 151  	return string(buf)
 152  }
 153  
 154  var processStartTime int64 = time.Now().UnixNano() / 1e6
 155  var seqId int64 = 0
 156  
 157  func getGID() uint64 {
 158  	// https://blog.sgmansfield.com/2015/12/goroutine-ids/
 159  	b := make([]byte, 64)
 160  	b = b[:runtime.Stack(b, false)]
 161  	b = bytes.TrimPrefix(b, []byte("goroutine "))
 162  	b = b[:bytes.IndexByte(b, ' ')]
 163  	n, _ := strconv.ParseUint(string(b), 10, 64)
 164  	return n
 165  }
 166  
 167  func GetNonce() (uuidHex string) {
 168  	routineId := getGID()
 169  	currentTime := time.Now().UnixNano() / 1e6
 170  	seq := atomic.AddInt64(&seqId, 1)
 171  	randNum := mathrand.Int63()
 172  	msg := fmt.Sprintf("%d-%d-%d-%d-%d", processStartTime, routineId, currentTime, seq, randNum)
 173  	h := md5.New()
 174  	h.Write([]byte(msg))
 175  	return hex.EncodeToString(h.Sum(nil))
 176  }
 177  
 178  // Get first non-empty value
 179  func GetDefaultString(values ...string) string {
 180  	for _, v := range values {
 181  		if v != "" {
 182  			return v
 183  		}
 184  	}
 185  
 186  	return ""
 187  }
 188  
 189  // set back the memoried enviroment variables
 190  type Rollback func()
 191  
 192  func Memory(keys ...string) Rollback {
 193  	// remenber enviroment variables
 194  	m := make(map[string]string)
 195  	for _, key := range keys {
 196  		m[key] = os.Getenv(key)
 197  	}
 198  
 199  	return func() {
 200  		for _, key := range keys {
 201  			os.Setenv(key, m[key])
 202  		}
 203  	}
 204  }
 205