You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
95 lines
2.6 KiB
95 lines
2.6 KiB
package idgen
|
|
|
|
import (
|
|
cryptorand "crypto/rand"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"math/big"
|
|
"sync"
|
|
)
|
|
|
|
// Generator handles the generation of various IDs
|
|
type Generator struct {
|
|
charsetMu sync.RWMutex
|
|
charset string
|
|
}
|
|
|
|
// NewGenerator creates a new ID generator with default settings
|
|
func NewGenerator() *Generator {
|
|
return &Generator{
|
|
charset: "0123456789ABCDEFGHJKLMNPQRSTVWXYZ",
|
|
}
|
|
}
|
|
|
|
// SetCharset allows customizing the character set used for ID generation
|
|
func (g *Generator) SetCharset(charset string) {
|
|
g.charsetMu.Lock()
|
|
defer g.charsetMu.Unlock()
|
|
g.charset = charset
|
|
}
|
|
|
|
// GenerateMachineID generates a new machine ID with the format auth0|user_XX[unique_id]
|
|
func (g *Generator) GenerateMachineID() (string, error) {
|
|
prefix := "auth0|user_"
|
|
|
|
// Generate random sequence number between 0-99
|
|
seqNum, err := cryptorand.Int(cryptorand.Reader, big.NewInt(100))
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to generate sequence number: %w", err)
|
|
}
|
|
sequence := fmt.Sprintf("%02d", seqNum.Int64())
|
|
|
|
uniqueID, err := g.generateUniqueID(23)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to generate unique ID: %w", err)
|
|
}
|
|
|
|
fullID := prefix + sequence + uniqueID
|
|
return hex.EncodeToString([]byte(fullID)), nil
|
|
}
|
|
|
|
// GenerateMacMachineID generates a new MAC machine ID using SHA-256
|
|
func (g *Generator) GenerateMacMachineID() (string, error) {
|
|
data := make([]byte, 32)
|
|
if _, err := cryptorand.Read(data); err != nil {
|
|
return "", fmt.Errorf("failed to generate random data: %w", err)
|
|
}
|
|
|
|
hash := sha256.Sum256(data)
|
|
return hex.EncodeToString(hash[:]), nil
|
|
}
|
|
|
|
// GenerateDeviceID generates a new device ID in UUID v4 format
|
|
func (g *Generator) GenerateDeviceID() (string, error) {
|
|
uuid := make([]byte, 16)
|
|
if _, err := cryptorand.Read(uuid); err != nil {
|
|
return "", fmt.Errorf("failed to generate UUID: %w", err)
|
|
}
|
|
|
|
// Set version (4) and variant (2) bits according to RFC 4122
|
|
uuid[6] = (uuid[6] & 0x0f) | 0x40
|
|
uuid[8] = (uuid[8] & 0x3f) | 0x80
|
|
|
|
return fmt.Sprintf("%x-%x-%x-%x-%x",
|
|
uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:16]), nil
|
|
}
|
|
|
|
// generateUniqueID generates a random string of specified length using the configured charset
|
|
func (g *Generator) generateUniqueID(length int) (string, error) {
|
|
g.charsetMu.RLock()
|
|
defer g.charsetMu.RUnlock()
|
|
|
|
result := make([]byte, length)
|
|
max := big.NewInt(int64(len(g.charset)))
|
|
|
|
for i := range result {
|
|
randNum, err := cryptorand.Int(cryptorand.Reader, max)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to generate random number: %w", err)
|
|
}
|
|
result[i] = g.charset[randNum.Int64()]
|
|
}
|
|
|
|
return string(result), nil
|
|
}
|