tweego/ifid.go

85 lines
2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Copyright © 20142019 Thomas Michael Edwards. All rights reserved.
Use of this source code is governed by a Simplified BSD License which
can be found in the LICENSE file.
*/
package main
import (
"crypto/rand"
"fmt"
"io"
"strings"
)
// IFIDs are defined in The Treaty of Babel.
// SEE: http://babel.ifarchive.org/
//
// Most IFIDs, and certainly those generated by Tweego, are simply the
// string form of a v4 random UUID.
// newIFID generates a new IFID (UUID v4).
func newIFID() (string, error) {
var uuid [16]byte
if _, err := io.ReadFull(rand.Reader, uuid[:]); err != nil {
return "", err
}
uuid[6] = (uuid[6] & 0x0f) | 0x40 // version 4
uuid[8] = (uuid[8] & 0x3f) | 0x80 // variant 10
return fmt.Sprintf("%X-%X-%X-%X-%X", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil
}
// validateIFID validates ifid or returns an error.
func validateIFID(ifid string) error {
switch len(ifid) {
case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
case 36 + 9: // UUID://xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx//
if strings.ToUpper(ifid[:7]) != "UUID://" || ifid[43:] != "//" {
return fmt.Errorf("invalid IFID UUID://…// format")
}
ifid = ifid[7:43]
default:
return fmt.Errorf("invalid IFID length: %d", len(ifid))
}
b := []byte(ifid)
for i := 0; i < len(b); i++ {
switch i {
// hyphens
case 8, 13, 18, 23:
if b[i] != '-' {
return fmt.Errorf("invalid IFID character %#U at position %d", b[i], i+1)
}
// version
case 14:
if '1' > b[i] || b[i] > '5' {
return fmt.Errorf("invalid version %#U at position %d", b[i], i+1)
}
// variant
case 19:
switch b[i] {
case '8', '9', 'a', 'A', 'b', 'B':
default:
return fmt.Errorf("invalid variant %#U at position %d", b[i], i+1)
}
// regular hex character
default:
switch {
case '0' <= b[i] && b[i] <= '9':
case 'a' <= b[i] && b[i] <= 'f':
case 'A' <= b[i] && b[i] <= 'F':
default:
return fmt.Errorf("invalid IFID hex value %#U at position %d", b[i], i+1)
}
}
}
return nil
}