mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-11-04 00:11:04 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			253 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			253 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
// 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()
 | 
						|
}
 |