* feat: kubesphere 4.0 Signed-off-by: ci-bot <ci-bot@kubesphere.io> * feat: kubesphere 4.0 Signed-off-by: ci-bot <ci-bot@kubesphere.io> --------- Signed-off-by: ci-bot <ci-bot@kubesphere.io> Co-authored-by: ks-ci-bot <ks-ci-bot@example.com> Co-authored-by: joyceliu <joyceliu@yunify.com>
116 lines
3.2 KiB
Go
116 lines
3.2 KiB
Go
// Copyright 2017 The OPA Authors. All rights reserved.
|
|
// Use of this source code is governed by an Apache2
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package uuid
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
const (
|
|
BILLION = 1000000000
|
|
)
|
|
|
|
// New Create a version 4 random UUID
|
|
func New(r io.Reader) (string, error) {
|
|
bs := make([]byte, 16)
|
|
n, err := io.ReadFull(r, bs)
|
|
if n != len(bs) || err != nil {
|
|
return "", err
|
|
}
|
|
bs[8] = bs[8]&^0xc0 | 0x80
|
|
bs[6] = bs[6]&^0xf0 | 0x40
|
|
return fmt.Sprintf("%x-%x-%x-%x-%x", bs[0:4], bs[4:6], bs[6:8], bs[8:10], bs[10:]), nil
|
|
}
|
|
|
|
// Parse will use the google/uuid library to parse the string into a uuid
|
|
// if parsing fails, it will return an empty map. It will fill the map
|
|
// with some decoded values with fillMap
|
|
// ref: https://datatracker.ietf.org/doc/html/rfc4122
|
|
func Parse(s string) (map[string]interface{}, error) {
|
|
uuid, err := uuid.Parse(s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out := make(map[string]interface{}, getVersionLen(int(uuid.Version())))
|
|
fillMap(out, uuid)
|
|
return out, nil
|
|
}
|
|
|
|
// Fills the map with values from the uuid. Version and variant for every version.
|
|
// Version 1-2 has decodable values that could be of use, version 4 is random,
|
|
// and version 3,5 is not feasible to extract data. Generated with either MD5 or SHA1 hash
|
|
// ref: https://datatracker.ietf.org/doc/html/rfc4122 about creation of UUIDs
|
|
func fillMap(m map[string]interface{}, u uuid.UUID) {
|
|
m["version"] = int(u.Version())
|
|
m["variant"] = u.Variant().String()
|
|
switch version := m["version"]; version {
|
|
case 1, 2:
|
|
m["time"] = nanoUnix(u.Time())
|
|
m["nodeid"] = byteDecimalToHexMAC(u.NodeID(), "-")
|
|
m["macvariables"] = macVars(u.NodeID()[0])
|
|
m["clocksequence"] = u.ClockSequence()
|
|
if version == 2 {
|
|
m["id"] = int(u.ID())
|
|
m["domain"] = u.Domain().String()
|
|
}
|
|
}
|
|
}
|
|
|
|
// macVars will take the first byte of a MAC-address and check for the
|
|
// local/global bit and check for the unicast/multicast bit of the byte,
|
|
// and return a string with this info.
|
|
// ref: https://datatracker.ietf.org/doc/html/rfc7042#section-2.1
|
|
func macVars(inpb byte) string {
|
|
switch {
|
|
case inpb&byte(0b11) == byte(0b11):
|
|
return "local:multicast"
|
|
case inpb&byte(0b01) == byte(0b01):
|
|
return "global:multicast"
|
|
case inpb&byte(0b10) == byte(0b10):
|
|
return "local:unicast"
|
|
}
|
|
return "global:unicast"
|
|
}
|
|
|
|
// loops through the byte array to convert all bytes to hexes.
|
|
// It will also put the separator between every other to make it human-readable
|
|
func byteDecimalToHexMAC(bytes []byte, sep string) string {
|
|
hexs := strings.Builder{}
|
|
l := len(bytes)
|
|
hexs.Grow((l * 3) - 1) // 1 byte -> 2 hexes + 1 separator (if one char)
|
|
|
|
for i, b := range bytes {
|
|
hexs.WriteString(fmt.Sprintf("%02x", b))
|
|
if i < l-1 {
|
|
hexs.WriteString(sep)
|
|
}
|
|
}
|
|
|
|
return hexs.String()
|
|
}
|
|
|
|
// nanoUnix Converts the uuids encoded time into unix represented time in nanoseconds
|
|
func nanoUnix(t uuid.Time) int64 {
|
|
unixsec, unixnsec := t.UnixTime()
|
|
return unixsec*BILLION + unixnsec
|
|
}
|
|
|
|
// Helper function to make map with length based on version of uuid
|
|
// Most are 2 in length (version, variant), but version 1 and 2 have more.
|
|
func getVersionLen(version int) int {
|
|
switch version {
|
|
case 1:
|
|
return 5
|
|
case 2:
|
|
return 7
|
|
default:
|
|
return 2
|
|
}
|
|
}
|