From 397823641c9bf180f5e6b91f6889218fcd66cfef Mon Sep 17 00:00:00 2001 From: SkalaNetworks Date: Tue, 15 Oct 2024 17:14:26 +0000 Subject: [PATCH] feat(crypto): add uuidv5 Signed-off-by: SkalaNetworks --- crypto.go | 11 +++++++++++ crypto_test.go | 28 +++++++++++++++++++++++++++- docs/index.md | 2 +- docs/uuid.md | 13 +++++++++++++ functions.go | 1 + 5 files changed, 53 insertions(+), 2 deletions(-) diff --git a/crypto.go b/crypto.go index 75fe027e..e2d2a957 100644 --- a/crypto.go +++ b/crypto.go @@ -86,6 +86,17 @@ func uuidv4() string { return uuid.New().String() } +// uuidv5 provides a safe and secure UUID v5 implementation +func uuidv5(namespace, name string) string { + // The namespace is always a UUID + ns, err := uuid.Parse(namespace) + if err != nil { + return fmt.Sprintf("namespace must be a valid UUID") + } + + return uuid.NewSHA1(ns, []byte(name)).String() +} + var masterPasswordSeed = "com.lyndir.masterpassword" var passwordTypeTemplates = map[string][][]byte{ diff --git a/crypto_test.go b/crypto_test.go index ac3f43b9..d6990be9 100644 --- a/crypto_test.go +++ b/crypto_test.go @@ -201,7 +201,7 @@ func TestRandBytes(t *testing.T) { } } -func TestUUIDGeneration(t *testing.T) { +func TestUUIDv4Generation(t *testing.T) { tpl := `{{uuidv4}}` out, err := runRaw(tpl, nil) if err != nil { @@ -222,6 +222,32 @@ func TestUUIDGeneration(t *testing.T) { } } +func TestUUIDv5Generation(t *testing.T) { + tpl := `{{uuidv5 "2be4f575-0625-4376-bfca-fc237ac4fd8a" "Hello World"}}` + out, err := runRaw(tpl, nil) + if err != nil { + t.Error(err) + } + + if len(out) != 36 { + t.Error("Expected UUID of length 36") + } + + out2, err := runRaw(tpl, nil) + if err != nil { + t.Error(err) + } + + if out != out2 { + t.Error("Expected subsequent UUID generations to be identical") + } + + tpl = `{{uuidv5 "2be4f575-0625-4376-bfca-fc237ac4fd8a" "Hello World"}}` + if err := runt(tpl, "c493a152-08ba-5679-a958-de98ebcc8160"); err != nil { + t.Error(err) + } +} + func TestBuildCustomCert(t *testing.T) { ca, _ := generateCertificateAuthority("example.com", 365) tpl := fmt.Sprintf( diff --git a/docs/index.md b/docs/index.md index 80a0d3b6..d9fd55ef 100644 --- a/docs/index.md +++ b/docs/index.md @@ -16,7 +16,7 @@ The Sprig library provides over 70 template functions for Go's template language - [Path and Filepath Functions](paths.md): `base`, `dir`, `ext`, `clean`, `isAbs`, `osBase`, `osDir`, `osExt`, `osClean`, `osIsAbs` - [Flow Control Functions](flow_control.md): `fail` - Advanced Functions - - [UUID Functions](uuid.md): `uuidv4` + - [UUID Functions](uuid.md): `uuidv4`, `uuidv5` - [OS Functions](os.md): `env`, `expandenv` - [Version Comparison Functions](semver.md): `semver`, `semverCompare` - [Reflection](reflection.md): `typeOf`, `kindIs`, `typeIsLike`, etc. diff --git a/docs/uuid.md b/docs/uuid.md index 1b57a330..fa33db21 100644 --- a/docs/uuid.md +++ b/docs/uuid.md @@ -1,5 +1,7 @@ # UUID Functions +## UUID v4 + Sprig can generate UUID v4 universally unique IDs. ``` @@ -7,3 +9,14 @@ uuidv4 ``` The above returns a new UUID of the v4 (randomly generated) type. + +## UUID v5 + +Sprig can generate UUID v5 which can output deterministic IDs for a given namespace and name. + +``` +uuidv5 "2be4f575-0625-4376-bfca-fc237ac4fd8a" "Hello World" +``` + +The above returns a new deterministic UUID that will always be the same as long as the parameters stay identical. +The output here would be `c493a152-08ba-5679-a958-de98ebcc8160` diff --git a/functions.go b/functions.go index cda47d26..e105ccee 100644 --- a/functions.go +++ b/functions.go @@ -356,6 +356,7 @@ var genericMap = map[string]interface{}{ // UUIDs: "uuidv4": uuidv4, + "uuidv5": uuidv5, // SemVer: "semver": semver,