uid

package module
v0.0.0-...-f1a44db Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 3, 2024 License: MIT Imports: 12 Imported by: 0

README

Yet another UUID library!?

The wonderful libraries by Google and Gofrs have served us quite well, however, they have two fatal flaws. First, they use "Too Much Crypto" https://eprint.iacr.org/2019/1492.pdf. Second, ironically given the first, they can return errors.

It's idiomatic to wrap every New in a Log(err) (if you're responsible), or Must (if you're optimistic), but it's verbose, inefficient, and possibly dangerous. All errors should be informative, safe, and actionable.

Is it always okay to send the raw error to the client? Should they know there is a randomness underflow? Untranslated (non-internationalized) errors are only sentinels to unfluent readers anyway. What action (besides logging or panicking) can the caller take with a "bad" UUID? Retry until it works? Will they properly back off?

This library constructs UUIDs without errors. Parse/validation failure is explicitly the sentinel it's always been.

uid constructs RFC compliant v4 and v7 UUIDs with no errors. Moreover, it parses without errors and, as a bonus, is an order of magnitude faster on construction than Google/Gofrs.

This library follows Go's math/rand/v2 and Linux's /dev/random changes to use ChaCha20-based cryptographic pseudorandom number generators (CPRNG) to ensure no errors during random fills.

What about Short UUIDs?

uid.UUID implements compact UUIDs encoded per https://datatracker.ietf.org/doc/draft-taylor-uuid-ncname/. Specifically Base32 (shorter and case-insensitive) and Base64url (shortest but case-sensitive). Arbitrary shorteners and any library based on the Python shortuuid algorithm still can produce encodings with leading digits which are prohibited in DOM IDs and require escaping in CSS classes. NCName-encoded UUIDs are safe for use in CSS classes, DOM IDs, and URIs without escaping.

But Unmarshal and Parse return errors!

UnmarshalXXX methods return errors because the implemented interfaces require it. uid.ParseError, however, is purely a sentinel error. No text to translate or sanitize. Check it for nil and move on like you would have before, "bad UUID" is probably not your service's primary concern.

Technically speaking, Parse's "ok" idiom is an error "pattern". However, the expected usage of uid.Parse is in an API context (users should never be asked to type a UUID) where input validation strictness needs only check for validity before rejecting the entire request see the example below.

How To

Generate

New Random UUID (v4)...

id := uid.NewV4()

New Sortable UUID (v7 with "method 3", extended precision monotonicity)

id := uid.NewV7()

New Sortable UUID (v7 with "method 3" monotonicity and strict process-local uniqueness... You don't want this, but it's here if you need it.)

id := uid.NewV7Strict()

Parse

Because uid does not include error messages, you are free to handle (count, log, translate, etc...) the failure (or not) your way.

id, ok := uid.Parse(r.PathValue("id"))
if !ok {
    // observe it your way
    slog.Log("bad ID: %s", sanitizeForLog(input))
    badIDCounter.Inc()
    // translate responses your way
    http.Error(w, messagePrinter.Sprint("invalid ID"), http.StatusBadRequest)
    return
}

Documentation

Overview

Package uid ...

UUID V7 uses Method 3 (Replace Leftmost Random Bits with Increased Clock Precision) to implement single-node monotonicity.

Index

Constants

View Source
const (
	// MaxCanonical is the canonical RFC9562 "Max" UUID.
	MaxCanonical = "ffffffff-ffff-ffff-ffff-ffffffffffff"

	// MaxCompact32 is the canonical NCName Compact Base32 "Max" UUID.
	MaxCompact32 = "P777777777777777777777777P"

	// MaxCompact64 is the canonical NCName Compact Base64 "Max" UUID.
	MaxCompact64 = "P____________________P"

	// NilCanonical is the canonical RFC9562 "Nil" UUID.
	NilCanonical = "00000000-0000-0000-0000-000000000000"

	// NilCompact32 is the canonical NCName Compact Base32 "Nil" UUID.
	NilCompact32 = "AAAAAAAAAAAAAAAAAAAAAAAAAA"

	// NilCompact64 is the canonical NCName Compact Base64 "Nil" UUID.
	NilCompact64 = "AAAAAAAAAAAAAAAAAAAAAA"
)
View Source
const (
	// VersionNil is the Nil UUID version.
	VersionNil = Version(0b0000_0000)

	// Version4 is the version of random UUIDs.
	Version4 = Version(0b0000_0100)

	// Version7 is the version of time-sortable UUIDs.
	Version7 = Version(0b0000_0111)

	// VersionMax is the Max UUID version.
	VersionMax = Version(0b0000_1111)
)
View Source
const (
	// Variant9562 is the value of the variant bits of v4 or v7.
	Variant9562 = Variant(0b0000_0010)

	// VariantNil is the value of the variant bits of a Nil UUID.
	VariantNil = Variant(0b0000_0000)

	// VariantMax is the value of the variant bits of a Max UUID.
	VariantMax = Variant(0b0000_0111)
)

Variables

This section is empty.

Functions

func Compare

func Compare(a, b UUID) int

Compare is a helper for sorting/deduping by monotonic time. Note: Sorting non-v7 IDs is a design flaw.

Types

type ParseError

type ParseError struct{}

ParseError is a sentinel error.

func (ParseError) Error

func (e ParseError) Error() string

Error implements errors.Error.

type UUID

type UUID struct {
	// contains filtered or unexported fields
}

UUID is a UUID as defined by RFC... Underlying array is unexported for immutability. UUID is comparable using `==`. The zero value is Nil UUID.

func Max

func Max() UUID

Max constructs a Max UUID (all F).

func NewV4

func NewV4() UUID

NewV4 returns a new v4 UUID.

func NewV7

func NewV7() UUID

NewV7 constructs a new v7 UUID. Enforces method 3 of monotonicity.

func NewV7Strict

func NewV7Strict() UUID

NewV7Strict returns a v7 UUID with guaranteed (beyond RFC method 3) local monotonicity. You don't need this, if you think you need finer than sub-millisecond precision in IDs, what you really need is a sequence generator and not more accurate timekeeping.

func Nil

func Nil() UUID

Nil constructs a Nil UUID (all 0).

func Parse

func Parse(src string) (UUID, bool)

Parse attempts to parse `src` into a UUID and returns the parsed UUID and `true` on success. On failure, Parse returns the Nil UUID and `false`.

func (UUID) Bytes

func (u UUID) Bytes() []byte

Bytes returns a copy of u's raw bytes.

func (UUID) Compact32

func (u UUID) Compact32() string

Compact32 returns NCName Base32 representation.

func (UUID) Compact64

func (u UUID) Compact64() string

Compact64 returns NCName Base64 representation.

func (UUID) IsMax

func (u UUID) IsMax() bool

IsMax returns true when u is the Max UUID.

func (UUID) IsNil

func (u UUID) IsNil() bool

IsNil returns true when u is the Nil UUID.

func (UUID) MarshalBinary

func (u UUID) MarshalBinary() ([]byte, error)

MarshalBinary implements encoding.BinaryMarshaler. Never returns errors.

func (UUID) MarshalJSON

func (u UUID) MarshalJSON() ([]byte, error)

MarshalJSON implements encoding/json.Marshaler. Never returns errors.

func (UUID) MarshalText

func (u UUID) MarshalText() ([]byte, error)

MarshalText implements encoding.TextMarshaler. Never returns errors.

func (UUID) String

func (u UUID) String() string

String implements fmt.Stringer. Returns canonical RFC-4122 representation.

func (UUID) Time

func (u UUID) Time() time.Time

Time returns the embedded timestamp of UUID. For non-V7 zero(time.Time) is returned. If you don't pre-check version use `.IsZero()` to ensure time is "real".

func (*UUID) UnmarshalBinary

func (u *UUID) UnmarshalBinary(b []byte) error

UnmarshalBinary implement encoding.BinaryUnmarshaler.

func (*UUID) UnmarshalJSON

func (u *UUID) UnmarshalJSON(b []byte) error

UnmarshalJSON implements encoding/json.Unmarshaler.

func (*UUID) UnmarshalText

func (u *UUID) UnmarshalText(b []byte) error

UnmarshalText implements encoding.TextUnmarshaler.

func (UUID) Variant

func (u UUID) Variant() Variant

Variant is u's variant.

func (UUID) Version

func (u UUID) Version() Version

Version returns u's version.

type Variant

type Variant byte

Variant is the RFC9562 variant.

type Version

type Version byte

Version is the RFC9562 UUID Version.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL