// Copyright 2013 com authors // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package com import ( "bytes" "crypto/aes" "crypto/cipher" "crypto/rand" "errors" r "math/rand" "strconv" "strings" "time" "unicode" "unicode/utf8" ) // AESGCMEncrypt encrypts plaintext with the given key using AES in GCM mode. func AESGCMEncrypt(key, plaintext []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } nonce := make([]byte, gcm.NonceSize()) if _, err := rand.Read(nonce); err != nil { return nil, err } ciphertext := gcm.Seal(nil, nonce, plaintext, nil) return append(nonce, ciphertext...), nil } // AESGCMDecrypt decrypts ciphertext with the given key using AES in GCM mode. func AESGCMDecrypt(key, ciphertext []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } size := gcm.NonceSize() if len(ciphertext)-size <= 0 { return nil, errors.New("Ciphertext is empty") } nonce := ciphertext[:size] ciphertext = ciphertext[size:] plainText, err := gcm.Open(nil, nonce, ciphertext, nil) if err != nil { return nil, err } return plainText, nil } // IsLetter returns true if the 'l' is an English letter. func IsLetter(l uint8) bool { n := (l | 0x20) - 'a' if n >= 0 && n < 26 { return true } return false } // Expand replaces {k} in template with match[k] or subs[atoi(k)] if k is not in match. func Expand(template string, match map[string]string, subs ...string) string { var p []byte var i int for { i = strings.Index(template, "{") if i < 0 { break } p = append(p, template[:i]...) template = template[i+1:] i = strings.Index(template, "}") if s, ok := match[template[:i]]; ok { p = append(p, s...) } else { j, _ := strconv.Atoi(template[:i]) if j >= len(subs) { p = append(p, []byte("Missing")...) } else { p = append(p, subs[j]...) } } template = template[i+1:] } p = append(p, template...) return string(p) } // Reverse s string, support unicode func Reverse(s string) string { n := len(s) runes := make([]rune, n) for _, rune := range s { n-- runes[n] = rune } return string(runes[n:]) } // RandomCreateBytes generate random []byte by specify chars. func RandomCreateBytes(n int, alphabets ...byte) []byte { const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" var bytes = make([]byte, n) var randby bool if num, err := rand.Read(bytes); num != n || err != nil { r.Seed(time.Now().UnixNano()) randby = true } for i, b := range bytes { if len(alphabets) == 0 { if randby { bytes[i] = alphanum[r.Intn(len(alphanum))] } else { bytes[i] = alphanum[b%byte(len(alphanum))] } } else { if randby { bytes[i] = alphabets[r.Intn(len(alphabets))] } else { bytes[i] = alphabets[b%byte(len(alphabets))] } } } return bytes } // ToSnakeCase can convert all upper case characters in a string to // underscore format. // // Some samples. // "FirstName" => "first_name" // "HTTPServer" => "http_server" // "NoHTTPS" => "no_https" // "GO_PATH" => "go_path" // "GO PATH" => "go_path" // space is converted to underscore. // "GO-PATH" => "go_path" // hyphen is converted to underscore. // // From https://github.com/huandu/xstrings func ToSnakeCase(str string) string { if len(str) == 0 { return "" } buf := &bytes.Buffer{} var prev, r0, r1 rune var size int r0 = '_' for len(str) > 0 { prev = r0 r0, size = utf8.DecodeRuneInString(str) str = str[size:] switch { case r0 == utf8.RuneError: buf.WriteByte(byte(str[0])) case unicode.IsUpper(r0): if prev != '_' { buf.WriteRune('_') } buf.WriteRune(unicode.ToLower(r0)) if len(str) == 0 { break } r0, size = utf8.DecodeRuneInString(str) str = str[size:] if !unicode.IsUpper(r0) { buf.WriteRune(r0) break } // find next non-upper-case character and insert `_` properly. // it's designed to convert `HTTPServer` to `http_server`. // if there are more than 2 adjacent upper case characters in a word, // treat them as an abbreviation plus a normal word. for len(str) > 0 { r1 = r0 r0, size = utf8.DecodeRuneInString(str) str = str[size:] if r0 == utf8.RuneError { buf.WriteRune(unicode.ToLower(r1)) buf.WriteByte(byte(str[0])) break } if !unicode.IsUpper(r0) { if r0 == '_' || r0 == ' ' || r0 == '-' { r0 = '_' buf.WriteRune(unicode.ToLower(r1)) } else { buf.WriteRune('_') buf.WriteRune(unicode.ToLower(r1)) buf.WriteRune(r0) } break } buf.WriteRune(unicode.ToLower(r1)) } if len(str) == 0 || r0 == '_' { buf.WriteRune(unicode.ToLower(r0)) break } default: if r0 == ' ' || r0 == '-' { r0 = '_' } buf.WriteRune(r0) } } return buf.String() }