mirror of https://github.com/dexidp/dex.git
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.
163 lines
3.7 KiB
163 lines
3.7 KiB
// Copyright 2011 Google Inc. All rights reserved. |
|
// Use of this source code is governed by a BSD-style |
|
// license that can be found in the LICENSE file. |
|
|
|
package uuid |
|
|
|
import ( |
|
"bytes" |
|
"crypto/rand" |
|
"fmt" |
|
"io" |
|
"strings" |
|
) |
|
|
|
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC |
|
// 4122. |
|
type UUID []byte |
|
|
|
// A Version represents a UUIDs version. |
|
type Version byte |
|
|
|
// A Variant represents a UUIDs variant. |
|
type Variant byte |
|
|
|
// Constants returned by Variant. |
|
const ( |
|
Invalid = Variant(iota) // Invalid UUID |
|
RFC4122 // The variant specified in RFC4122 |
|
Reserved // Reserved, NCS backward compatibility. |
|
Microsoft // Reserved, Microsoft Corporation backward compatibility. |
|
Future // Reserved for future definition. |
|
) |
|
|
|
var rander = rand.Reader // random function |
|
|
|
// New returns a new random (version 4) UUID as a string. It is a convenience |
|
// function for NewRandom().String(). |
|
func New() string { |
|
return NewRandom().String() |
|
} |
|
|
|
// Parse decodes s into a UUID or returns nil. Both the UUID form of |
|
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and |
|
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded. |
|
func Parse(s string) UUID { |
|
if len(s) == 36+9 { |
|
if strings.ToLower(s[:9]) != "urn:uuid:" { |
|
return nil |
|
} |
|
s = s[9:] |
|
} else if len(s) != 36 { |
|
return nil |
|
} |
|
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { |
|
return nil |
|
} |
|
uuid := make([]byte, 16) |
|
for i, x := range []int{ |
|
0, 2, 4, 6, |
|
9, 11, |
|
14, 16, |
|
19, 21, |
|
24, 26, 28, 30, 32, 34} { |
|
if v, ok := xtob(s[x:]); !ok { |
|
return nil |
|
} else { |
|
uuid[i] = v |
|
} |
|
} |
|
return uuid |
|
} |
|
|
|
// Equal returns true if uuid1 and uuid2 are equal. |
|
func Equal(uuid1, uuid2 UUID) bool { |
|
return bytes.Equal(uuid1, uuid2) |
|
} |
|
|
|
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx |
|
// , or "" if uuid is invalid. |
|
func (uuid UUID) String() string { |
|
if uuid == nil || len(uuid) != 16 { |
|
return "" |
|
} |
|
b := []byte(uuid) |
|
return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", |
|
b[:4], b[4:6], b[6:8], b[8:10], b[10:]) |
|
} |
|
|
|
// URN returns the RFC 2141 URN form of uuid, |
|
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid. |
|
func (uuid UUID) URN() string { |
|
if uuid == nil || len(uuid) != 16 { |
|
return "" |
|
} |
|
b := []byte(uuid) |
|
return fmt.Sprintf("urn:uuid:%08x-%04x-%04x-%04x-%012x", |
|
b[:4], b[4:6], b[6:8], b[8:10], b[10:]) |
|
} |
|
|
|
// Variant returns the variant encoded in uuid. It returns Invalid if |
|
// uuid is invalid. |
|
func (uuid UUID) Variant() Variant { |
|
if len(uuid) != 16 { |
|
return Invalid |
|
} |
|
switch { |
|
case (uuid[8] & 0xc0) == 0x80: |
|
return RFC4122 |
|
case (uuid[8] & 0xe0) == 0xc0: |
|
return Microsoft |
|
case (uuid[8] & 0xe0) == 0xe0: |
|
return Future |
|
default: |
|
return Reserved |
|
} |
|
panic("unreachable") |
|
} |
|
|
|
// Version returns the verison of uuid. It returns false if uuid is not |
|
// valid. |
|
func (uuid UUID) Version() (Version, bool) { |
|
if len(uuid) != 16 { |
|
return 0, false |
|
} |
|
return Version(uuid[6] >> 4), true |
|
} |
|
|
|
func (v Version) String() string { |
|
if v > 15 { |
|
return fmt.Sprintf("BAD_VERSION_%d", v) |
|
} |
|
return fmt.Sprintf("VERSION_%d", v) |
|
} |
|
|
|
func (v Variant) String() string { |
|
switch v { |
|
case RFC4122: |
|
return "RFC4122" |
|
case Reserved: |
|
return "Reserved" |
|
case Microsoft: |
|
return "Microsoft" |
|
case Future: |
|
return "Future" |
|
case Invalid: |
|
return "Invalid" |
|
} |
|
return fmt.Sprintf("BadVariant%d", int(v)) |
|
} |
|
|
|
// SetRand sets the random number generator to r, which implents io.Reader. |
|
// If r.Read returns an error when the package requests random data then |
|
// a panic will be issued. |
|
// |
|
// Calling SetRand with nil sets the random number generator to the default |
|
// generator. |
|
func SetRand(r io.Reader) { |
|
if r == nil { |
|
rander = rand.Reader |
|
return |
|
} |
|
rander = r |
|
}
|
|
|