// Code generated by csid-generate.go DO NOT EDIT. package {{.PkgName}} import "crypto/rand" import "crypto/sha256" import "fmt" import "github.com/go-playground/validator/v10" import "github.com/rs/zerolog/log" import "gogs.mikescher.com/BlackForestBytes/goext/exerr" import "gogs.mikescher.com/BlackForestBytes/goext/langext" import "gogs.mikescher.com/BlackForestBytes/goext/rext" import "math/big" import "reflect" import "regexp" import "strings" const ChecksumCharsetIDGenerator = "{{.Checksum}}" // GoExtVersion: {{.GoextVersion}} const idlen = 24 const checklen = 1 const idCharset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" const idCharsetLen = len(idCharset) var charSetReverseMap = generateCharsetMap() const ({{range .IDs}} prefix{{.Name}} = "{{.Prefix}}" {{end}} ) var ({{range .IDs}} regex{{.Name}} = generateRegex(prefix{{.Name}}) {{end}} ) func generateRegex(prefix string) rext.Regex { return rext.W(regexp.MustCompile(fmt.Sprintf("^%s[%s]{%d}[%s]{%d}$", prefix, idCharset, idlen-len(prefix)-checklen, idCharset, checklen))) } func generateCharsetMap() []int { result := make([]int, 128) for i := 0; i < len(result); i++ { result[i] = -1 } for idx, chr := range idCharset { result[int(chr)] = idx } return result } func generateID(prefix string) string { k := "" csMax := big.NewInt(int64(idCharsetLen)) checksum := 0 for i := 0; i < idlen-len(prefix)-checklen; i++ { v, err := rand.Int(rand.Reader, csMax) if err != nil { panic(err) } v64 := v.Int64() k += string(idCharset[v64]) checksum = (checksum + int(v64)) % (idCharsetLen) } checkstr := string(idCharset[checksum%idCharsetLen]) return prefix + k + checkstr } func generateIDFromSeed(prefix string, seed string) string { h := sha256.New() iddata := "" for len(iddata) < idlen-len(prefix)-checklen { h.Write([]byte(seed)) bs := h.Sum(nil) iddata += langext.NewAnyBaseConverter(idCharset).Encode(bs) } checksum := 0 for i := 0; i < idlen-len(prefix)-checklen; i++ { ichr := int(iddata[i]) checksum = (checksum + charSetReverseMap[ichr]) % (idCharsetLen) } checkstr := string(idCharset[checksum%idCharsetLen]) return prefix + iddata[:(idlen-len(prefix)-checklen)] + checkstr } func validateID(prefix string, value string) error { if len(value) != idlen { return exerr.New(exerr.TypeInvalidCSID, "id has the wrong length").Str("value", value).Build() } if !strings.HasPrefix(value, prefix) { return exerr.New(exerr.TypeInvalidCSID, "id is missing the correct prefix").Str("value", value).Str("prefix", prefix).Build() } checksum := 0 for i := len(prefix); i < len(value)-checklen; i++ { ichr := int(value[i]) if ichr < 0 || ichr >= len(charSetReverseMap) || charSetReverseMap[ichr] == -1 { return exerr.New(exerr.TypeInvalidCSID, "id contains invalid characters").Str("value", value).Build() } checksum = (checksum + charSetReverseMap[ichr]) % (idCharsetLen) } checkstr := string(idCharset[checksum%idCharsetLen]) if !strings.HasSuffix(value, checkstr) { return exerr.New(exerr.TypeInvalidCSID, "id checkstring is invalid").Str("value", value).Str("checkstr", checkstr).Build() } return nil } func getRawData(prefix string, value string) string { if len(value) != idlen { return "" } return value[len(prefix) : idlen-checklen] } func getCheckString(prefix string, value string) string { if len(value) != idlen { return "" } return value[idlen-checklen:] } func ValidateEntityID(vfl validator.FieldLevel) bool { if !vfl.Field().CanInterface() { log.Error().Msgf("Failed to validate EntityID (cannot interface ?!?)") return false } ifvalue := vfl.Field().Interface() if value1, ok := ifvalue.(EntityID); ok { if vfl.Field().Type().Kind() == reflect.Pointer && langext.IsNil(value1) { return true } if err := value1.Valid(); err != nil { log.Debug().Msgf("Failed to validate EntityID '%s' (%s)", value1.String(), err.Error()) return false } else { return true } } else { log.Error().Msgf("Failed to validate EntityID (wrong type: %T)", ifvalue) return false } } {{range .IDs}} // ================================ {{.Name}} ({{.FileRelative}}) ================================ func New{{.Name}}() {{.Name}} { return {{.Name}}(generateID(prefix{{.Name}})) } func (id {{.Name}}) Valid() error { return validateID(prefix{{.Name}}, string(id)) } func (i *{{.Name}}) String() string { if i == nil { return "" } return string(i) } func (i {{.Name}}) Prefix() string { return prefix{{.Name}} } func (id {{.Name}}) Raw() string { return getRawData(prefix{{.Name}}, string(id)) } func (id {{.Name}}) CheckString() string { return getCheckString(prefix{{.Name}}, string(id)) } func (id {{.Name}}) Regex() rext.Regex { return regex{{.Name}} } {{end}}