This repository has been archived by the owner on Jul 23, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
/
slugid.go
113 lines (106 loc) · 4.59 KB
/
slugid.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// Licensed under the Mozilla Public Licence 2.0.
// https://www.mozilla.org/en-US/MPL/2.0
//
// **************
// * Slugid API *
// **************
//
// @)@)
// _|_| ( )
// _(___,`\ _,--------------._ (( /`, ))
// `==` `*-_,' O `~._ ( ( _/ | ) )
// `, : o } `~._.~` * ',
// \ - _ O - ,'
// | ; - - " ; o /
// | O o ,-`
// \ _,-:""""""'`:-._ - . O /
// `""""""~'` `._ _,-`
// """"""
// A go (golang) module for generating v4 UUIDs and encoding them into 22
// character URL-safe base64 slug representation (see [RFC 4648 sec.
// 5](http://tools.ietf.org/html/rfc4648#section-5)).
//
// Slugs are url-safe base64 encoded v4 uuids, stripped of base64 `=` padding.
//
// There are two methods for generating slugs - `slugid.V4()` and
// `slugid.Nice()`.
//
// V4 Slugs
//
// The `slugid.V4()` method returns a slug from a randomly generated v4 uuid.
//
// Nice slugs
//
// The `slugid.Nice()` method returns a v4 slug which conforms to a set of
// "nice" properties. At the moment the only "nice" property is that the slug
// starts with `[A-Za-f]`, which in turn implies that the first (most
// significant) bit of its associated uuid is set to 0.
//
// The purpose of the `slugid.Nice()` method is to support having slugids which
// can be used in more contexts safely. Regular slugids can safely be used in
// urls, and for example in AMQP routing keys. However, slugs beginning with `-`
// may cause problems when used as command line parameters.
//
// In contrast, slugids generated by the `slugid.Nice()` method can safely be
// used as command line parameters. This comes at a cost to entropy (121 bits vs
// 122 bits for regular v4 slugs).
//
// Choosing which slug generation method to use
//
// Slug consumers should consider carefully which of these two slug generation
// methods to call. Is it more important to have maximum entropy, or to have
// slugids that do not need special treatment when used as command line
// parameters? This is especially important if you are providing a service which
// supplies slugs to unexpecting tool developers downstream, who may not realise
// the risks of using your regular v4 slugs as command line parameters, especially
// since this would arise only as an intermittent issue (one time in 64).
//
// Generated slugs take the form `[A-Za-z0-9_-]{22}`, or more precisely:
//
// `slugid.V4()` slugs conform to
// `[A-Za-z0-9_-]{8}[Q-T][A-Za-z0-9_-][CGKOSWaeimquy26-][A-Za-z0-9_-]{10}[AQgw]`
//
// `slugid.Nice()` slugs conform to
// `[A-Za-f][A-Za-z0-9_-]{7}[Q-T][A-Za-z0-9_-][CGKOSWaeimquy26-][A-Za-z0-9_-]{10}[AQgw]`
//
// RFC 4122 defines the setting of 6 bits of the v4 UUID which implies v4 slugs
// provide 128 - 6 = 122 bits entropy. Due to the (un)setting of the first bit
// of "nice" slugs, nice slugs provide therefore 121 bits entropy.
package slugid
import (
"encoding/base64"
"github.com/pborman/uuid"
)
// Returns the given uuid.UUID object as a 22 character slug. This can be a
// regular v4 slug or a "nice" slug.
func Encode(uuid_ uuid.UUID) string {
return base64.URLEncoding.EncodeToString(uuid_)[:22] // Drop '==' padding
}
// Returns the uuid.UUID object represented by the given v4 or "nice" slug, or
// nil if it cannot be decoded
func Decode(slug string) uuid.UUID {
uuid_, err := base64.URLEncoding.DecodeString(slug + "==") // b64 padding
if err != nil {
return nil
}
return uuid_
}
// Returns a randomly generated uuid v4 compliant slug
func V4() string {
return base64.URLEncoding.EncodeToString(uuid.NewRandom())[:22] // Drop '==' padding
}
// Returns a randomly generated uuid v4 compliant slug which conforms to a set
// of "nice" properties, at the cost of some entropy. Currently this means one
// extra fixed bit (the first bit of the uuid is set to 0) which guarantees the
// slug will begin with [A-Za-f]. For example such slugs don't require special
// handling when used as command line parameters (whereas non-nice slugs may
// start with `-` which can confuse command line tools).
//
// Potentially other "nice" properties may be added in future to further
// restrict the range of potential uuids that may be generated.
func Nice() string {
rawBytes := uuid.NewRandom()
// unset most significant bit of first byte to ensure slug starts with [A-Za-f]
rawBytes[0] &= 0x7f
return base64.URLEncoding.EncodeToString(rawBytes)[:22] // Drop '==' padding
}