package ids import ( "crypto/rand" "crypto/sha256" "encoding/binary" "fmt" "strings" ) const ( alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" randomLength = 11 ) const ( Project = "prj" Task = "tsk" Session = "ses" Snapshot = "snp" Review = "rev" InboxItem = "inb" InboxResponse = "rsp" Blob = "blb" LeadNote = "not" WorkflowDefinition = "wfd" WorkflowRun = "run" Send = "snd" Client = "cli" ClientRequest = "req" Transfer = "xfr" ) var prefixes = map[string]bool{ Project: true, Task: true, Session: true, Snapshot: true, Review: true, InboxItem: true, InboxResponse: true, Blob: true, LeadNote: true, WorkflowDefinition: true, WorkflowRun: true, Send: true, Client: true, ClientRequest: true, Transfer: true, } func New(prefix string) string { check(prefix) out := make([]byte, randomLength) buf := make([]byte, 1) for i := 0; i < len(out); { rand.Read(buf) if int(buf[0]) >= 256/len(alphabet)*len(alphabet) { continue } out[i] = alphabet[int(buf[0])%len(alphabet)] i++ } return prefix + string(out) } func Derive(prefix string, parts ...string) string { check(prefix) sum := sha256.Sum256([]byte(strings.Join(parts, "\x00"))) n := binary.BigEndian.Uint64(sum[:8]) out := make([]byte, randomLength) for i := range out { out[i] = alphabet[n%uint64(len(alphabet))] n /= uint64(len(alphabet)) } return prefix + string(out) } func check(prefix string) { if !prefixes[prefix] { panic(fmt.Sprintf("no id prefix %q", prefix)) } }