Skip to content
Snippets Groups Projects
id.go 1.93 KiB
Newer Older
package util

import (
	"encoding/base64"
	"golang.org/x/crypto/bcrypt"
	"hash/fnv"
	"math/rand"
	"regexp"
	"strconv"
	"strings"
)

const tempStringMask = "GAEKEEPHIENOHJOHEOJH" // random string to avoid collision with other text nodes
const keyDelimiter = "-"

// NewSecret creates a new secret
func NewSecret() (string, error) {
	return NewSecretWithLength(32)
}

// NewSecretWithLength creates a new secret for a given length
func NewSecretWithLength(length int) (string, error) {
	return RandomString(length)
}

func randomBytes(len int) ([]byte, error) {
	b := make([]byte, len)

	if _, err := rand.Read(b); err != nil {
		return nil, err
	}
	return b, nil
}

func RandomString(length int) (string, error) {
	b, err := randomBytes(length)
	if err != nil {
		return "", err
	}

	s := base64.URLEncoding.EncodeToString(b)

	return cryptID(s, length)

}

func cryptID(t string, length int) (string, error) {
	hash, err := bcrypt.GenerateFromPassword([]byte(t), bcrypt.DefaultCost)
	if err != nil {
		return "", err
	}

	r := strings.ToUpper(string(hash[len(hash)-length-1 : len(hash)-1]))
	return r, nil
}

func hashString(s string) string {
	h := fnv.New32a()
	h.Write([]byte(s))
	return strconv.Itoa(int(h.Sum32()))
}

func BuildTextKey(txt string) (string, error) {

	if txt == "" {
		return "", nil
	}

	txt = strings.TrimSpace(txt)
Volker Schukai's avatar
Volker Schukai committed

	re := regexp.MustCompile(`([a-z])([A-Z])`)
	txt = re.ReplaceAllString(txt, "${1}-${2}")

	txt = strings.ToLower(txt)

	txt = strings.ReplaceAll(txt, keyDelimiter, tempStringMask)
	reg, err := regexp.Compile("[^a-z0-9_-]+")
	if err != nil {
		return "", err
	}
	newStr := reg.ReplaceAllString(txt, keyDelimiter)
	newStr = strings.ReplaceAll(newStr, tempStringMask, keyDelimiter)

	newStr = strings.Trim(newStr, keyDelimiter)

	if len(newStr) > 20 {
		newStr = newStr[:20] + keyDelimiter + hashString(newStr)
	}

	c := strings.TrimSpace(newStr)
	if c == "" {
		return "", nil
	}

	if len(c) < 2 {
		return "", nil
	}

	return c, nil
}