From 560df0f87db088668cafc400b84b52a8608fba73 Mon Sep 17 00:00:00 2001 From: Peter Lithammer Date: Tue, 1 Feb 2022 09:35:41 +0100 Subject: [PATCH 1/2] feat!: encode/decode using MSB first --- README.md | 8 +- alphabet.go | 12 +- alphabet_test.go | 8 +- base57.go | 44 ++++---- base57_test.go | 13 +++ go.mod | 2 +- shortuuid_test.go | 277 ++++++++++++++++++++-------------------------- 7 files changed, 173 insertions(+), 191 deletions(-) create mode 100644 base57_test.go diff --git a/README.md b/README.md index ac214d6..c13f947 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,11 @@ package main import ( "fmt" - "github.com/lithammer/shortuuid/v3" + "github.com/lithammer/shortuuid/v4" ) func main() { - u := shortuuid.New() // Cekw67uyMpBGZLRP2HFVbe + u := shortuuid.New() // KwSysDpxcBU9FNhGkn2dCf } ``` @@ -42,7 +42,7 @@ characters long. ```go alphabet := "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxy=" -shortuuid.NewWithAlphabet(alphabet) // u=BFWRLr5dXbeWf==iasZi +shortuuid.NewWithAlphabet(alphabet) // iZsai==fWebXd5rLRWFB=u ``` Bring your own encoder! For example, base58 is popular among bitcoin. @@ -55,7 +55,7 @@ import ( "github.com/btcsuite/btcutil/base58" "github.com/google/uuid" - "github.com/lithammer/shortuuid/v3" + "github.com/lithammer/shortuuid/v4" ) type base58Encoder struct{} diff --git a/alphabet.go b/alphabet.go index ed0cf5e..1e5356d 100644 --- a/alphabet.go +++ b/alphabet.go @@ -10,7 +10,7 @@ import ( const DefaultAlphabet = "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" type alphabet struct { - chars [57]string + chars [57]rune len int64 } @@ -26,7 +26,11 @@ func newAlphabet(s string) alphabet { a := alphabet{ len: int64(len(abc)), } - copy(a.chars[:], abc) + + for i, char := range strings.Join(abc, "") { + a.chars[i] = char + } + return a } @@ -36,13 +40,13 @@ func (a *alphabet) Length() int64 { // Index returns the index of the first instance of t in the alphabet, or an // error if t is not present. -func (a *alphabet) Index(t string) (int64, error) { +func (a *alphabet) Index(t rune) (int64, error) { for i, char := range a.chars { if char == t { return int64(i), nil } } - return 0, fmt.Errorf("Element '%v' is not part of the alphabet", t) + return 0, fmt.Errorf("element '%v' is not part of the alphabet", t) } // dudupe removes duplicate characters from s. diff --git a/alphabet_test.go b/alphabet_test.go index 5bdd624..fab1522 100644 --- a/alphabet_test.go +++ b/alphabet_test.go @@ -23,8 +23,7 @@ func TestDedupe(t *testing.T) { func TestAlphabetIndex(t *testing.T) { abc := newAlphabet(DefaultAlphabet) - idx, err := abc.Index("z") - + idx, err := abc.Index('z') if err != nil { t.Errorf("expected index 56, got an error trying to get it %v", err) } @@ -35,8 +34,7 @@ func TestAlphabetIndex(t *testing.T) { func TestAlphabetIndexZero(t *testing.T) { abc := newAlphabet(DefaultAlphabet) - idx, err := abc.Index("2") - + idx, err := abc.Index('2') if err != nil { t.Errorf("expected index 0, got an error trying to get it %v", err) } @@ -47,7 +45,7 @@ func TestAlphabetIndexZero(t *testing.T) { func TestAlphabetIndexError(t *testing.T) { abc := newAlphabet(DefaultAlphabet) - idx, err := abc.Index("l") + idx, err := abc.Index('l') if err == nil { t.Errorf("expected an error, got a valid index %d", idx) } diff --git a/base57.go b/base57.go index ec78213..2499600 100644 --- a/base57.go +++ b/base57.go @@ -14,16 +14,14 @@ type base57 struct { alphabet alphabet } -// Encode encodes uuid.UUID into a string using the least significant bits -// (LSB) first according to the alphabet. If the most significant bits (MSB) -// are 0, the string might be shorter. +// Encode encodes uuid.UUID into a string using the most significant bits (MSB) +// first according to the alphabet. func (b base57) Encode(u uuid.UUID) string { var num big.Int num.SetString(strings.Replace(u.String(), "-", "", 4), 16) // Calculate encoded length. - factor := math.Log(float64(25)) / math.Log(float64(b.alphabet.Length())) - length := math.Ceil(factor * float64(len(u))) + length := math.Ceil(math.Log(math.Pow(2, 128)) / math.Log(float64(b.alphabet.Length()))) return b.numToString(&num, int(length)) } @@ -41,32 +39,36 @@ func (b base57) Decode(u string) (uuid.UUID, error) { // numToString converts a number a string using the given alphabet. func (b *base57) numToString(number *big.Int, padToLen int) string { var ( - out string + out []rune digit *big.Int ) + alphaLen := big.NewInt(b.alphabet.Length()) + zero := new(big.Int) for number.Cmp(zero) > 0 { - number, digit = new(big.Int).DivMod(number, big.NewInt(b.alphabet.Length()), new(big.Int)) - out += b.alphabet.chars[digit.Int64()] + number, digit = new(big.Int).DivMod(number, alphaLen, new(big.Int)) + out = append(out, b.alphabet.chars[digit.Int64()]) } if padToLen > 0 { remainder := math.Max(float64(padToLen-len(out)), 0) - out = out + strings.Repeat(b.alphabet.chars[0], int(remainder)) + out = append(out, []rune(strings.Repeat(string(b.alphabet.chars[0]), int(remainder)))...) } - return out + reverse(out) + + return string(out) } // stringToNum converts a string a number using the given alphabet. func (b *base57) stringToNum(s string) (string, error) { n := big.NewInt(0) - for i := len(s) - 1; i >= 0; i-- { + for _, char := range s { n.Mul(n, big.NewInt(b.alphabet.Length())) - index, err := b.alphabet.Index(string(s[i])) + index, err := b.alphabet.Index(char) if err != nil { return "", err } @@ -74,14 +76,16 @@ func (b *base57) stringToNum(s string) (string, error) { n.Add(n, big.NewInt(index)) } - x := fmt.Sprintf("%x", n) - - if len(x) < 32 { - // Pad the most significant bit (MSG) with 0 (zero) if the string is too short. - x = strings.Repeat("0", 32-len(x)) + x - } else if len(x) > 32 { - return "", fmt.Errorf("UUID length overflow for %q", s) + if n.BitLen() > 128 { + return "", fmt.Errorf("number is out of range (need a 128-bit value)") } - return fmt.Sprintf("%s-%s-%s-%s-%s", x[0:8], x[8:12], x[12:16], x[16:20], x[20:32]), nil + return fmt.Sprintf("%032x", n), nil +} + +// reverse reverses a inline. +func reverse(a []rune) { + for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 { + a[i], a[j] = a[j], a[i] + } } diff --git a/base57_test.go b/base57_test.go new file mode 100644 index 0000000..0a1f2ac --- /dev/null +++ b/base57_test.go @@ -0,0 +1,13 @@ +package shortuuid + +import ( + "testing" +) + +func TestReverse(t *testing.T) { + a := []rune("abc123") + reverse(a) + if string(a) != "321cba" { + t.Errorf("expected string to be %q, got %q", "321cba", string(a)) + } +} diff --git a/go.mod b/go.mod index 6d6fb91..a924aa9 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/lithammer/shortuuid/v3 +module github.com/lithammer/shortuuid/v4 require github.com/google/uuid v1.3.0 diff --git a/shortuuid_test.go b/shortuuid_test.go index 8a5983e..1bc6492 100644 --- a/shortuuid_test.go +++ b/shortuuid_test.go @@ -10,159 +10,122 @@ var testVector = []struct { uuid string shortuuid string }{ - {"c3eeb3e6-e577-4de2-b5bb-08371196b453", "nSKHvGZM4M5A4KyN4zp4sc"}, - {"7c37b0a5-9d63-4d91-a79e-85a480fd2348", "gos3umowEP9bS8QAGSuk7Q"}, - {"52600a3d-a12a-4041-aa9c-afd5e5923a70", "ZHhWmgrdXxgMqzgYRXGRfG"}, - {"7b80853c-a9f3-4acd-b735-17d29b3b9122", "gGpmQT6oVMVeQvnLkgJWyP"}, - {"2f56ebd5-373f-478f-afab-1142b74b75bc", "Hi7d4MYcbjKxzeg8YiN7SA"}, - {"72573478-ade8-4a6c-a583-d098e9c24de3", "yoANdrf88xUXvwbS5GRbMN"}, - {"f4c03714-aa7e-42e3-91f8-9a7a3bc05f75", "VTtAQPXV7MRyAghQPA6AZm"}, - {"f9ee01c3-2015-4716-930e-4d5449810833", "7fm8A5kT3j9j5M2HcjofUn"}, - {"a5fb9251-9373-486b-b9bd-ecf1c7cc6d9c", "DQqWKCLAjsm6fTTFCwuKYX"}, - {"9cbfe3da-dc50-4d07-9d3a-3d161e5a82b1", "dhRv9nyctV3M6uUJtcZgtV"}, - {"cda34e96-188b-41b2-acac-05cd288c32e1", "Cekw67uyMpBGZLRP2HFVbe"}, - {"0ce70d9e-830e-404b-8b56-25cc611eed6a", "qXPoF8kNjxoqWZVCnoXrJ4"}, - {"36a06807-8c07-4e65-8b99-855b3628c155", "LXuzZwRWpEYos2yAiDmziB"}, - {"4672c1dc-125a-4469-a81e-c69dc3b8f792", "p6tjrWt5UH9RpAUqPfjTYE"}, - {"e63d7da2-7f8d-4954-9c2d-d46b324d10f2", "P3bYrwnrsvRXdsRCTByyxi"}, - {"926251a7-41a3-4029-bf44-bf860e881423", "r3FdNDkxMf4rdz8V7dcZ4U"}, - {"464a919f-54e9-435e-a029-a3b942b07134", "THvwuXRQt9soLzL3L2zrWE"}, - {"7c24ef71-f4eb-4000-afb6-710c7f9e0942", "9tXMVg3xaJxwuK7v4XZ27Q"}, - {"d3973d0f-22e4-44b5-a03f-34a57458a8ff", "rqcFhGVXy7quTXiERRPref"}, - {"74102102-3d04-48fc-b2b5-6ef50109e27f", "v8tx4KDUXyfSFcSmFZ45fN"}, - {"67cdb44b-f0fb-47c1-9060-025216c14067", "nD4n6pXuc9BanbiQM6HjUL"}, - {"503c91b0-6a52-4b26-be71-b96c1d4d908b", "fq2q5eoUmgGuuKTtCa3jHG"}, - {"174ea6fa-9321-4e80-b732-006b11998663", "zw3YBp3erLmWGWFvNW8PA6"}, - {"fa60d3a9-df24-468c-8006-e2a4f37ddf17", "zohky26otniDxSonDD6EZn"}, - {"eff670a0-75f5-4458-afd4-9aa442dcc507", "feViSxBJPp7ZUgCA2hCbhk"}, - {"2c301095-3f99-4fc8-88e3-a2be83fd39fc", "YAJdktpVp9ioZXyerGS9s9"}, - {"ee2d3de2-4ad7-4f32-9071-f8aa4b46dc0b", "XrKarC8cp4dWSRnWQjoUPk"}, - {"12942a1b-cf39-44d6-bfbb-0ae17affd408", "tYx4TiGiu78HcFfkmgkRK5"}, - {"f9b2ea09-32c6-426b-bb3b-a269182e99f3", "b7rFanuSDdkVW4Af7vNLSn"}, - {"02f3da16-b995-445a-877b-2319f0c06b41", "5aQC5t9BRRcicH9GbfmwX"}, - {"b8538991-0957-4bab-93f3-7f78ca9c1550", "vDJmAtHGFpqmrP6MNTjMoa"}, - {"3bf87639-ba74-463e-9455-bf7bcb8fd898", "4pUYNRFHTG3YVgThPZvCgC"}, - {"c9c7cafa-a131-4193-a21d-b65d0052f77b", "ziGxvYy3dYbecxB2VPNNud"}, - {"f921ebe3-2d1b-42fc-951b-7b275d5a1e5f", "pwt3bwxM4WTMGRqNTuxaLn"}, - {"c3d5e2c5-1bc8-4a86-96fb-bf0877c9fc03", "UNqNwmt3Eb9TDXRJXon5rc"}, - {"582dd24f-beda-42cf-b751-7c7e9827b7d1", "cjhuJfBhZQiSZ7GkYPGHhH"}, - {"6dfacd19-5cfd-4b95-92be-7e9fb0fe343e", "C6wrxXg46LWXAnhNTyVNaM"}, - {"ea3f3050-d7ce-4ad7-ae24-9b7b164dcec1", "r29MuyWbYNZ75FhWmh5dgj"}, - {"07dcc180-1323-4985-8359-296261dd53c8", "Qw7DZuPhurJbWAAGwhwjQ3"}, - {"89ffb519-4cea-4cd2-b051-0da7b451ca1a", "q7C7JQRar8QxqhkePNRXZS"}, - {"81fa1f63-389e-44ae-906d-4c1f4a715a61", "mQVvJQHRPinBYydtDaHB9R"}, - {"77eee831-5e48-400b-b1e1-31bc8d28876e", "hnGWZSNK7xyhivxQoYJKMP"}, - {"63815548-e46f-441a-8bdf-3153db75e56b", "Qnmrn7WRTv2kmDC5oNZ9iK"}, - {"60cba957-dc15-404a-994a-cab6b11b1315", "po3Y5UByzV7T8ny9fvCfEK"}, - {"a23360e0-1caf-4275-b957-0bcd7aa109d8", "mRV85qM4gaVEVidUCrfxrW"}, - {"48610926-01fb-4ef8-ae6b-ba9b45569525", "4YcLEHE6evYdnN9R6Er3tE"}, - {"c1d07707-c751-4e18-bf53-924a02e7a312", "tfdCPzDgjH7kDZmoUbRaVc"}, - {"d22b3035-2213-49a8-8399-a547303f29a3", "9K49a86KhGxzjfdt8YLSQf"}, - {"ba40a392-f1f6-4486-8c27-00b78db13ddc", "iHHZerT4hpfGqMbjuXCt9b"}, - {"241d6b4e-81a7-439a-896d-b645ec223eb5", "fuTJdCqF7jvgn6p8ZRoGS8"}, - {"e2f1fc6f-c8c8-4e6c-91ff-aca0ca558535", "qHhWwrK3ZPHZ3w5LDjHaPi"}, - {"b6f1e412-da4f-43bf-8a9f-ae4658f5b9ce", "7EohUgpsHtHugJudodBMZa"}, - {"db850c2c-a4e2-45c5-9b67-fda3be319df2", "uAQEWZNR9MQrqTVCU3qG5h"}, - {"63ac6e18-e0c9-477d-b08f-039b9538e577", "Qh3dcsgZBQCseB34xNsqjK"}, - {"eda9eacb-d698-41af-8790-4f26ecbd3a39", "29XrEqVWgteJF2Kr6xGHJk"}, - {"76d61350-f831-40fe-ae88-c2d63885c954", "u6xS5LyehZPedbnBRjACAP"}, - {"9dc996f5-2dfb-4e60-96a2-f11f59eb71de", "B8tRdDRCz6spwRDVPoXD6W"}, - {"9e0ef764-f98d-4c66-abd8-5d5e7392bacb", "TsnXJsfNMZGvuu9WJHCx8W"}, - {"08c79281-f45e-4463-b26d-1dc84ece1a05", "VgbLFBmKXHXs5VZdxuB4a3"}, - {"6611ce43-fe22-47ef-879e-de3fbbd4d9f6", "HHsWgxyECxDUUdNKEvu9BL"}, - {"748374a4-43c4-42a4-92be-f70daffe5d58", "h6793J2TNezTRPo8iFUdjN"}, - {"eb571f9d-dbe4-4d37-840f-0db7c9a35e3a", "snrX2R8WkCAALQ5Ux6Cisj"}, - {"dbc3f7d2-5f4b-4fb9-b473-2ca74cf7e2ef", "WRGi6eUnSKwVAaCwcXuk7h"}, - {"4e4d65f0-22b1-48ba-acc4-b378e7a826e3", "ybEmP4TsGe53BYtqDAu7wF"}, - {"c5232425-c634-4653-a367-0eb07235ccfc", "U6XjtF8PADo2bW7Gd6KH6d"}, - {"8a95bedb-0592-4329-87be-8affdf5f2e97", "ck493bWVpcBsppo94mDUfS"}, - {"52fa1417-02e9-4656-96ec-5cf44fdcd3c2", "RyF2UdmNpgzbxjNVbo6XmG"}, - {"d728fb9b-240b-4ca1-b864-50b807364acb", "y3kctB9VyUVeDABHVQg4Jg"}, - {"9da4fb93-9260-46a7-b6df-f04218560fe0", "jxBVLETqKeFjofyJe8sk4W"}, - {"fa9c1ef1-1f4d-4b74-9590-878c79f1f353", "xKpbsbfBxJA5r5uC7wxZbn"}, - {"64d1355f-d052-4bd9-83f4-39b93fb1c01f", "fCd2nkGhNF9UBcxpDsySwK"}, - {"7227d320-fd77-4430-8e9c-ac3f93e07c51", "crnPpyJpmterz6sLUwRiKN"}, - {"22eac9a7-b0b7-4c8b-9e88-4a2c4a48eef4", "PKMNKhycsviQJbcG3uQ8E8"}, - {"68252941-638b-4e0d-807a-3e8cd04f2493", "iRPfmXvLunFTvtoanekCYL"}, - {"3c9886b3-cabc-4854-8fe3-d394c0901830", "ELPAWnjUbWpbS3xhJSNYnC"}, - {"37eea0c0-ec18-42e8-a152-c98fee7346fb", "QgZm5asemZJYKqpCJrTFxB"}, - {"a61daaac-ea00-4bba-89d9-22b97763a43a", "aCfFqp3vmiADaHuL6LufZX"}, - {"1fc9211b-c1b8-464e-ae01-1c59d1972f47", "ENBaEjcoJktWRqfBkVDNf7"}, - {"21e24536-3b3e-4166-85c4-c29ea151fbbe", "LNZqphXG6tigmWJeBt7e38"}, - {"94fac6e4-315c-4399-89c0-0c5bdd5bf206", "w6qsE9trfLSjwUMjzxzsWU"}, - {"e9ae9ba7-4fb1-4a6d-bbca-5315ed438371", "vACGXSMs5eYcfXgAAjbtaj"}, - {"39439367-6f10-4de8-883f-7ace28c3bc33", "KSbYQEttmBpDjSkUxEMkCC"}, - {"ac6250d9-6e12-4686-98b2-3e5e8ab11ecb", "ZZVXrsGQdVqLz4JGNdKFgY"}, - {"f1975e43-a054-4243-85b1-14ed27be8330", "Bb45oofgN75sPKJYWWe7zk"}, - {"9206e127-8559-4cc4-877e-5cf342aecd25", "7LppjN8wAobe3FXybT9wyT"}, - {"4aeff9a2-4ad2-4c85-abd1-95e798b2132a", "JPu3vSYW3LEGp7RTMSkyLF"}, - {"c7c541b0-d024-432e-8b84-dcc011bfb596", "ag4yKsYNczpg2gKA3TWyYd"}, - {"852fcc13-5632-4188-92a8-12909c77f83f", "tJusodB6eZxNyVrGXGgihR"}, - {"97d87c66-f983-48b7-84c4-1d521e790ecf", "jYFL8gwyq9inicFz4dmw2V"}, - {"4f800ff2-7c1a-4305-b7d5-ce4c5b08e928", "wGSD5xRu6Kc9z8PrFsNGAG"}, - {"185c8229-dbd0-4fc1-a485-04a0532a71d0", "huiUUTVakc3eBxVmQgU5M6"}, - {"0170eb09-dd9d-4682-a58f-b49eb481a40d", "YE6XcuFs8SBnRhgVcS4dG"}, - {"d11c27c7-e302-4007-8a82-a83f57da217a", "uRQsP9P54sbnWjw66uKhDf"}, - {"4ef326fe-7886-4054-b427-4cd9f48200bf", "ibgFYZiZccqvy2PrsMCg4G"}, - {"9e5366f3-6bb8-42db-b999-1dc3612be8e4", "nWdjqVaVdyt94U794eifBW"}, - {"75a8dcb5-9e11-4fbb-895b-60bb6959b6e7", "9tvqGWgZgfiq2mPAvazFwN"}, - {"2b3bd265-a475-401d-88a6-3aa8580483ba", "zdGUGgimEzGkL65LnmuTh9"}, - {"7273ea84-04a1-4d32-92ff-b0afad3eedb6", "6FBBvgSqZeKBpyxxBfFjNN"}, - {"d2af90cd-1b97-4bec-810b-562406b31470", "aTfqZJoFH5kXHiYGxoFgVf"}, - {"8ec76efb-b891-4ee4-868d-997597e390e1", "mdoaq3unkSKHuuDKc6gzQT"}, - {"431933fb-14dd-411c-8fc6-5ca57fa7979d", "ajLWxEodc6CmQLHADuKVwD"}, - {"4788fd99-a1f3-468a-bc67-ada5f80016f4", "QvqUofYurTwpHNWUG52VjE"}, - {"502f56e0-f351-4f42-b395-4dde8b8c19b6", "B8tAKsW9Zw6ZRHySjmADHG"}, - {"b3150123-4e7c-4080-a029-c7437c6513df", "JYqm5dazak2ye8hfs7DBsZ"}, - {"61714a37-a894-4ec5-a569-7e925b46e368", "no6QHS2MfYKUZ6ys4xCEMK"}, - {"8a2f74ed-8146-4f86-a50a-aa28a21c3829", "t3HZ5drXDpPRgjuEnBFRbS"}, - {"5ea5a1a8-bd7e-46fd-ae88-e2d779bc9453", "uQod4vaUSE3ciZdwbbCsqJ"}, - {"35165d02-262d-4e30-8344-c70ee9cc63ee", "DjB4ac8mxbB25FCQswyPTB"}, - {"0026636a-e9b3-4a88-9c66-bf49d8cad81f", "BcRZF3N5Bv7FcJTEsxgX3"}, - {"84973303-f7ff-47a0-8b47-c54767700622", "kzcnTJSM4nPRXJT89Q7gbR"}, - {"92faac68-0387-49ae-a219-45e7c13fd6a3", "Rw8KtoWPAvbt2EqPtAebAU"}, - {"e9f17c46-0d3d-45e8-bc36-6c793b59c91c", "QXh7kFCLxJkJjayBAXcYdj"}, - {"d39295c8-f4d8-407f-bcdf-d07911f4d997", "tWkeanmnjjupCMcjnUsfef"}, - {"a2952f3b-fba2-4926-b19d-26d550093b93", "VEaZCnxWXK6VryEoLUXqvW"}, - {"40e86d7b-77dd-4f55-aec8-29262e028c38", "3Ad8xKbmR43ud53T7Y4HZD"}, - {"c6876847-fda6-4ab5-a2c2-9d8fe9c543bc", "Bj5frkc73iykq7XVT6nPLd"}, - {"cf5c7de8-82d2-475f-a078-825b76d0a287", "PzWDnpB8hSu8cZN38AUxte"}, - {"c4560036-bd08-42d6-ba59-1a49a51643df", "zYWYB5k4sQ55k4KL7V6Awc"}, - {"ded85fd3-afe7-45a1-a4d8-90c0a5bc8901", "MDkC9BQWzG7RPvHpCGCzeh"}, - {"f8221ca8-49e2-44e5-a104-7cec6fb28d48", "Q682Tt3m3ohTTdoGZgLTAn"}, - {"c1544cac-c6ee-40a7-98c8-900a7282ae22", "43nxCsa2kHWeAK32kG4fQc"}, - {"422a2339-0950-4a68-aec1-8c4056feef2a", "SBxqULeq9wXZskuxLoV2nD"}, - {"d9f26801-08d7-42e2-adee-e178944d9ba9", "z2QKKXd38qApcjuav6eKng"}, - {"69807fd5-8bcf-4d4c-a534-ff298d4a5a0a", "fe9aUtsDhyC9ssuU2Y5xmL"}, - {"65656f1e-ae8d-48a3-825d-4499144eefab", "bGSD7rg3Xm2Y4mjNDygK4L"}, - {"0a4399e6-7fad-452b-acc8-1d6b33415019", "NzVFQCNbRxxccPCpHRK7q3"}, - {"4860e725-08f5-4ba1-87e6-1db791f183d8", "8Ka6kDcVRxniasWrb8Z3tE"}, - {"709a8e5a-6320-4649-b4c2-8aceb28502ae", "ekLbSTDNHj9XSCjo6XNy3N"}, - {"3b6aa689-ab23-4ded-932d-090e029a7a99", "4PjpHyzbdreNeUxSc3iaaC"}, - {"00302322-9d08-4394-a1ac-b25bbab774d4", "zv3wa6Hm2fK2SaaRLkhu3"}, - {"12a12ca0-0d6e-4b84-bd6f-9715d467ae76", "iCLCA6LpyQKnw3TexB9wK5"}, - {"6556f0b7-b826-4ed3-b2ef-911a1d0665c8", "RfzKJAwgPxnMD24SEVxj3L"}, - {"269ca19c-5937-4512-83f8-ab9ab82cdaab", "nUkCVCrYTu7LBY8eDPCbs8"}, - {"58f3c051-a71a-4608-bf4e-543694f65f6b", "kKorfq5sQENdZGWDPuC8qH"}, - {"13f0a717-883d-4a69-b7da-eeb91f5d5ca5", "Dke3AiNbfvWUjq6W5bfEZ5"}, - {"7d2ec191-96ef-4b3d-834e-94cf60b1467f", "6mVb7WwQ8tcas48qYJoYHQ"}, - {"831805c0-7651-4a0d-804e-d12924bb9a0c", "pZ6gS9wWUXdHr64W7jrVLR"}, - {"56a03672-74bc-418c-9964-76548fd5b209", "9qiVxV4fEdYvhaW5PBSXRH"}, - {"8c634f54-f7bf-4f39-bf84-394f06970eda", "YpGmB2LeJ6ms8jntjgTkyS"}, - {"a5d35565-a3e0-407f-ab1c-1b8a605ba172", "9bFhyhbykoBC3mdQcu4jWX"}, - {"48443c48-0632-4b72-ba41-f4bdd0cd8ef5", "8ZmSNTgRwuf3qD5ZuLptrE"}, - {"1e86f5b0-b479-4dd2-9d3c-0c0b9a63db30", "WbphNvGKPP8bQE9y65jbS7"}, - {"7178fac6-27b6-473d-801a-63be24d75fb2", "bTdfo4UL4NWDXoMttdcnCN"}, - {"8e03626b-9c23-4032-9ee2-ae6ca661b7d1", "zvvZNCeKsWEQwYrP4dyEHT"}, - {"51f7acb3-2a82-4cc6-8601-523ed6d5909b", "EdQ8N465wYULNARFAfbHbG"}, - {"676fcb0c-730c-4875-9c0b-62b0bc2f4b9e", "J7DMkkwPsVJnt6frUnD2RL"}, - {"2ab244e0-4e34-494f-8c1a-d91051a4c3bf", "E4VoERm26o5Rkfsp6NK2c9"}, - {"4c8c949d-5bef-4d56-82f9-2041859b1dc6", "sEsXtdJXEnq9cLJuCrSLdF"}, - {"ca887b94-e90a-4143-b498-b0f517677e5a", "bLBXoAmYhoJvTHv2FVUz3e"}, - {"eb9ccaea-9569-4688-a40a-96fe3dd3d6eb", "89hHCpRTfBuhi7hxJDWUvj"}, - {"00000000-0000-0000-0000-000000000000", "2222222222222"}, - {"00000000-0000-0000-8000-000000000000", "z7C8BNkRBVT22"}, - {"00000000-0000-0001-0000-000000000000", "yDNELiVqLxt22"}, + {"00000000-0000-0000-0000-000000000000", "2222222222222222222222"}, + {"00000000-0000-0000-8000-000000000000", "22222222222TVBRkNB8C7z"}, + {"00000000-0000-0001-0000-000000000000", "22222222222txLqViLENDy"}, + {"0026636a-e9b3-4a88-9c66-bf49d8cad81f", "23XgxsETJcF7vB5N3FZRcB"}, + {"00302322-9d08-4394-a1ac-b25bbab774d4", "23uhkLRaaS2Kf2mH6aw3vz"}, + {"0170eb09-dd9d-4682-a58f-b49eb481a40d", "2Gd4ScVghRnBS8sFucX6EY"}, + {"02f3da16-b995-445a-877b-2319f0c06b41", "2XwmfbG9HcicRRB9t5CQa5"}, + {"07dcc180-1323-4985-8359-296261dd53c8", "3QjwhwGAAWbJruhPuZD7wQ"}, + {"08c79281-f45e-4463-b26d-1dc84ece1a05", "3a4BuxdZV5sXHXKmBFLbgV"}, + {"0a4399e6-7fad-452b-acc8-1d6b33415019", "3q7KRHpCPccxxRbNCQFVzN"}, + {"12a12ca0-0d6e-4b84-bd6f-9715d467ae76", "5Kw9BxeT3wnKQypL6ACLCi"}, + {"13f0a717-883d-4a69-b7da-eeb91f5d5ca5", "5ZEfb5W6qjUWvfbNiA3ekD"}, + {"185c8229-dbd0-4fc1-a485-04a0532a71d0", "6M5UgQmVxBe3ckaVTUUiuh"}, + {"1e86f5b0-b479-4dd2-9d3c-0c0b9a63db30", "7Sbj56y9EQb8PPKGvNhpbW"}, + {"1fc9211b-c1b8-464e-ae01-1c59d1972f47", "7fNDVkBfqRWtkJocjEaBNE"}, + {"21e24536-3b3e-4166-85c4-c29ea151fbbe", "83e7tBeJWmgit6GXhpqZNL"}, + {"22eac9a7-b0b7-4c8b-9e88-4a2c4a48eef4", "8E8Qu3GcbJQivscyhKNMKP"}, + {"241d6b4e-81a7-439a-896d-b645ec223eb5", "8SGoRZ8p6ngvj7FqCdJTuf"}, + {"269ca19c-5937-4512-83f8-ab9ab82cdaab", "8sbCPDe8YBL7uTYrCVCkUn"}, + {"2ab244e0-4e34-494f-8c1a-d91051a4c3bf", "9c2KN6psfkR5o62mREoV4E"}, + {"2c301095-3f99-4fc8-88e3-a2be83fd39fc", "9s9SGreyXZoi9pVptkdJAY"}, + {"2f56ebd5-373f-478f-afab-1142b74b75bc", "AS7NiY8gezxKjbcYM4d7iH"}, + {"35165d02-262d-4e30-8344-c70ee9cc63ee", "BTPywsQCF52Bbxm8ca4BjD"}, + {"36a06807-8c07-4e65-8b99-855b3628c155", "BizmDiAy2soYEpWRwZzuXL"}, + {"37eea0c0-ec18-42e8-a152-c98fee7346fb", "BxFTrJCpqKYJZmesa5mZgQ"}, + {"39439367-6f10-4de8-883f-7ace28c3bc33", "CCkMExUkSjDpBmttEQYbSK"}, + {"3b6aa689-ab23-4ded-932d-090e029a7a99", "Caai3cSxUeNerdbzyHpjP4"}, + {"3bf87639-ba74-463e-9455-bf7bcb8fd898", "CgCvZPhTgVY3GTHFRNYUp4"}, + {"3c9886b3-cabc-4854-8fe3-d394c0901830", "CnYNSJhx3SbpWbUjnWAPLE"}, + {"40e86d7b-77dd-4f55-aec8-29262e028c38", "DZH4Y7T35du34RmbKx8dA3"}, + {"422a2339-0950-4a68-aec1-8c4056feef2a", "Dn2VoLxuksZXw9qeLUqxBS"}, + {"431933fb-14dd-411c-8fc6-5ca57fa7979d", "DwVKuDAHLQmC6cdoExWLja"}, + {"464a919f-54e9-435e-a029-a3b942b07134", "EWrz2L3LzLos9tQRXuwvHT"}, + {"4788fd99-a1f3-468a-bc67-ada5f80016f4", "EjV25GUWNHpwTruYfoUqvQ"}, + {"48443c48-0632-4b72-ba41-f4bdd0cd8ef5", "ErtpLuZ5Dq3fuwRgTNSmZ8"}, + {"4860e725-08f5-4ba1-87e6-1db791f183d8", "Et3Z8brWsainxRVcDk6aK8"}, + {"48610926-01fb-4ef8-ae6b-ba9b45569525", "Et3rE6R9NndYve6EHELcY4"}, + {"4aeff9a2-4ad2-4c85-abd1-95e798b2132a", "FLykSMTR7pGEL3WYSv3uPJ"}, + {"4ef326fe-7886-4054-b427-4cd9f48200bf", "G4gCMsrP2yvqccZiZYFgbi"}, + {"502f56e0-f351-4f42-b395-4dde8b8c19b6", "GHDAmjSyHRZ6wZ9WsKAt8B"}, + {"503c91b0-6a52-4b26-be71-b96c1d4d908b", "GHj3aCtTKuuGgmUoe5q2qf"}, + {"51f7acb3-2a82-4cc6-8601-523ed6d5909b", "GbHbfAFRANLUYw564N8QdE"}, + {"52600a3d-a12a-4041-aa9c-afd5e5923a70", "GfRGXRYgzqMgxXdrgmWhHZ"}, + {"52fa1417-02e9-4656-96ec-5cf44fdcd3c2", "GmX6obVNjxbzgpNmdU2FyR"}, + {"56a03672-74bc-418c-9964-76548fd5b209", "HRXSBP5WahvYdEf4VxViq9"}, + {"582dd24f-beda-42cf-b751-7c7e9827b7d1", "HhHGPYkG7ZSiQZhBfJuhjc"}, + {"58f3c051-a71a-4608-bf4e-543694f65f6b", "Hq8CuPDWGZdNEQs5qfroKk"}, + {"61714a37-a894-4ec5-a569-7e925b46e368", "KMECx4sy6ZUKYfM2SHQ6on"}, + {"63815548-e46f-441a-8bdf-3153db75e56b", "Ki9ZNo5CDmk2vTRW7nrmnQ"}, + {"63ac6e18-e0c9-477d-b08f-039b9538e577", "KjqsNx43BesCQBZgscd3hQ"}, + {"64d1355f-d052-4bd9-83f4-39b93fb1c01f", "KwSysDpxcBU9FNhGkn2dCf"}, + {"6556f0b7-b826-4ed3-b2ef-911a1d0665c8", "L3jxVES42DMnxPgwAJKzfR"}, + {"65656f1e-ae8d-48a3-825d-4499144eefab", "L4KgyDNjm4Y2mX3gr7DSGb"}, + {"6611ce43-fe22-47ef-879e-de3fbbd4d9f6", "LB9uvEKNdUUDxCEyxgWsHH"}, + {"676fcb0c-730c-4875-9c0b-62b0bc2f4b9e", "LR2DnUrf6tnJVsPwkkMD7J"}, + {"67cdb44b-f0fb-47c1-9060-025216c14067", "LUjH6MQibnaB9cuXp6n4Dn"}, + {"68252941-638b-4e0d-807a-3e8cd04f2493", "LYCkenaotvTFnuLvXmfPRi"}, + {"69807fd5-8bcf-4d4c-a534-ff298d4a5a0a", "Lmx5Y2Uuss9CyhDstUa9ef"}, + {"6dfacd19-5cfd-4b95-92be-7e9fb0fe343e", "MaNVyTNhnAXWL64gXxrw6C"}, + {"709a8e5a-6320-4649-b4c2-8aceb28502ae", "N3yNX6ojCSX9jHNDTSbLke"}, + {"7178fac6-27b6-473d-801a-63be24d75fb2", "NCncdttMoXDWN4LU4ofdTb"}, + {"7227d320-fd77-4430-8e9c-ac3f93e07c51", "NKiRwULs6zretmpJypPnrc"}, + {"7273ea84-04a1-4d32-92ff-b0afad3eedb6", "NNjFfBxxypBKeZqSgvBBF6"}, + {"748374a4-43c4-42a4-92be-f70daffe5d58", "NjdUFi8oPRTzeNT2J3976h"}, + {"75a8dcb5-9e11-4fbb-895b-60bb6959b6e7", "NwFzavAPm2qifgZgWGqvt9"}, + {"77eee831-5e48-400b-b1e1-31bc8d28876e", "PMKJYoQxvihyx7KNSZWGnh"}, + {"7b80853c-a9f3-4acd-b735-17d29b3b9122", "PyWJgkLnvQeVMVo6TQmpGg"}, + {"7c24ef71-f4eb-4000-afb6-710c7f9e0942", "Q72ZX4v7KuwxJax3gVMXt9"}, + {"7c37b0a5-9d63-4d91-a79e-85a480fd2348", "Q7kuSGAQ8Sb9PEwomu3sog"}, + {"7d2ec191-96ef-4b3d-834e-94cf60b1467f", "QHYoJYq84sact8QwW7bVm6"}, + {"81fa1f63-389e-44ae-906d-4c1f4a715a61", "R9BHaDtdyYBniPRHQJvVQm"}, + {"84973303-f7ff-47a0-8b47-c54767700622", "Rbg7Q98TJXRPn4MSJTnczk"}, + {"8a95bedb-0592-4329-87be-8affdf5f2e97", "SfUDm49oppsBcpVWb394kc"}, + {"8c634f54-f7bf-4f39-bf84-394f06970eda", "SykTgjtnj8sm6JeL2BmGpY"}, + {"8ec76efb-b891-4ee4-868d-997597e390e1", "TQzg6cKDuuHKSknu3qaodm"}, + {"9206e127-8559-4cc4-877e-5cf342aecd25", "Tyw9TbyXF3eboAw8NjppL7"}, + {"92faac68-0387-49ae-a219-45e7c13fd6a3", "UAbeAtPqE2tbvAPWotK8wR"}, + {"97d87c66-f983-48b7-84c4-1d521e790ecf", "V2wmd4zFcini9qywg8LFYj"}, + {"9cbfe3da-dc50-4d07-9d3a-3d161e5a82b1", "VtgZctJUu6M3Vtcyn9vRhd"}, + {"9da4fb93-9260-46a7-b6df-f04218560fe0", "W4ks8eJyfojFeKqTELVBxj"}, + {"9dc996f5-2dfb-4e60-96a2-f11f59eb71de", "W6DXoPVDRwps6zCRDdRt8B"}, + {"9e0ef764-f98d-4c66-abd8-5d5e7392bacb", "W8xCHJW9uuvGZMNfsJXnsT"}, + {"9e5366f3-6bb8-42db-b999-1dc3612be8e4", "WBfie497U49tydVaVqjdWn"}, + {"a23360e0-1caf-4275-b957-0bcd7aa109d8", "WrxfrCUdiVEVag4Mq58VRm"}, + {"a2952f3b-fba2-4926-b19d-26d550093b93", "WvqXULoEyrV6KXWxnCZaEV"}, + {"a5d35565-a3e0-407f-ab1c-1b8a605ba172", "XWj4ucQdm3CBokybhyhFb9"}, + {"a5fb9251-9373-486b-b9bd-ecf1c7cc6d9c", "XYKuwCFTTf6msjALCKWqQD"}, + {"a61daaac-ea00-4bba-89d9-22b97763a43a", "XZfuL6LuHaDAimv3pqFfCa"}, + {"ac6250d9-6e12-4686-98b2-3e5e8ab11ecb", "YgFKdNGJ4zLqVdQGsrXVZZ"}, + {"b3150123-4e7c-4080-a029-c7437c6513df", "ZsBD7sfh8ey2kazad5mqYJ"}, + {"b6f1e412-da4f-43bf-8a9f-ae4658f5b9ce", "aZMBdoduJguHtHspgUhoE7"}, + {"ba40a392-f1f6-4486-8c27-00b78db13ddc", "b9tCXujbMqGfph4TreZHHi"}, + {"c1544cac-c6ee-40a7-98c8-900a7282ae22", "cQf4Gk23KAeWHk2asCxn34"}, + {"c3d5e2c5-1bc8-4a86-96fb-bf0877c9fc03", "cr5noXJRXDT9bE3tmwNqNU"}, + {"c3eeb3e6-e577-4de2-b5bb-08371196b453", "cs4pz4NyK4A5M4MZGvHKSn"}, + {"c5232425-c634-4653-a367-0eb07235ccfc", "d6HK6dG7Wb2oDAP8FtjX6U"}, + {"c6876847-fda6-4ab5-a2c2-9d8fe9c543bc", "dLPn6TVX7qkyi37ckrf5jB"}, + {"c7c541b0-d024-432e-8b84-dcc011bfb596", "dYyWT3AKg2gpzcNYsKy4ga"}, + {"ca887b94-e90a-4143-b498-b0f517677e5a", "e3zUVF2vHTvJohYmAoXBLb"}, + {"cda34e96-188b-41b2-acac-05cd288c32e1", "ebVFH2PRLZGBpMyu76wkeC"}, + {"cf5c7de8-82d2-475f-a078-825b76d0a287", "etxUA83NZc8uSh8BpnDWzP"}, + {"d22b3035-2213-49a8-8399-a547303f29a3", "fQSLY8tdfjzxGhK68a94K9"}, + {"d2af90cd-1b97-4bec-810b-562406b31470", "fVgFoxGYiHXk5HFoJZqfTa"}, + {"dbc3f7d2-5f4b-4fb9-b473-2ca74cf7e2ef", "h7kuXcwCaAVwKSnUe6iGRW"}, + {"ded85fd3-afe7-45a1-a4d8-90c0a5bc8901", "hezCGCpHvPR7GzWQB9CkDM"}, + {"e63d7da2-7f8d-4954-9c2d-d46b324d10f2", "ixyyBTCRsdXRvsrnwrYb3P"}, + {"e9f17c46-0d3d-45e8-bc36-6c793b59c91c", "jdYcXAByajJkJxLCFk7hXQ"}, + {"eb9ccaea-9569-4688-a40a-96fe3dd3d6eb", "jvUWDJxh7ihuBfTRpCHh98"}, + {"eda9eacb-d698-41af-8790-4f26ecbd3a39", "kJHGx6rK2FJetgWVqErX92"}, + {"ee2d3de2-4ad7-4f32-9071-f8aa4b46dc0b", "kPUojQWnRSWd4pc8CraKrX"}, + {"eff670a0-75f5-4458-afd4-9aa442dcc507", "khbCh2ACgUZ7pPJBxSiVef"}, + {"f1975e43-a054-4243-85b1-14ed27be8330", "kz7eWWYJKPs57Ngfoo54bB"}, + {"f4c03714-aa7e-42e3-91f8-9a7a3bc05f75", "mZA6APQhgAyRM7VXPQAtTV"}, + {"f8221ca8-49e2-44e5-a104-7cec6fb28d48", "nATLgZGodTTho3m3tT286Q"}, + {"f9b2ea09-32c6-426b-bb3b-a269182e99f3", "nSLNv7fA4WVkdDSunaFr7b"}, + {"f9ee01c3-2015-4716-930e-4d5449810833", "nUfojcH2M5j9j3Tk5A8mf7"}, } func TestGeneration(t *testing.T) { @@ -219,12 +182,12 @@ func TestDecodingErrors(t *testing.T) { NotPartOfAlphabetError = "not part of alphabet" UUIDLengthOverflowError = "UUID length overflow" ) - var tests = []struct { + tests := []struct { shortuuid string error string }{ - {"6B8cwPMGnU6qLbRvo7qEZo", UUIDLengthOverflowError}, - {"SiKyfue4VDTKnynXckqVNt", UUIDLengthOverflowError}, + {"yoANdrf88xUXvwbS5GRbMN", UUIDLengthOverflowError}, + {"tWkeanmnjjupCMcjnUsfef", UUIDLengthOverflowError}, {"1lIO022222222222222222", NotPartOfAlphabetError}, {"0a6hrgRGNfQ57QMHZdNYAg", NotPartOfAlphabetError}, } @@ -241,7 +204,7 @@ func TestNewWithAlphabet(t *testing.T) { enc := base57{newAlphabet(abc)} u1, _ := uuid.Parse("e9ae9ba7-4fb1-4a6d-bbca-5315ed438371") u2 := enc.Encode(u1) - if u2 != "u=BFWRLr5dXbeWf==iasZi" { + if u2 != "iZsai==fWebXd5rLRWFB=u" { t.Errorf("expected uuid to be %q, got %q", "u=BFWRLr5dXbeWf==iasZi", u2) } } From c09cf66894e8dfcd4c075e5e027bd75a40f83ec1 Mon Sep 17 00:00:00 2001 From: Peter Lithammer Date: Tue, 1 Feb 2022 09:40:20 +0100 Subject: [PATCH 2/2] fix: use robuster URL check --- shortuuid.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shortuuid.go b/shortuuid.go index 68d396f..7ae1ef5 100644 --- a/shortuuid.go +++ b/shortuuid.go @@ -33,7 +33,9 @@ func NewWithNamespace(name string) string { switch { case name == "": u = uuid.New() - case strings.HasPrefix(name, "http"): + case strings.HasPrefix(strings.ToLower(name), "http://"): + u = uuid.NewSHA1(uuid.NameSpaceURL, []byte(name)) + case strings.HasPrefix(strings.ToLower(name), "https://"): u = uuid.NewSHA1(uuid.NameSpaceURL, []byte(name)) default: u = uuid.NewSHA1(uuid.NameSpaceDNS, []byte(name))