uuidtools 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +3 -0
- data/lib/compat/securerandom.rb +144 -142
- data/lib/uuidtools.rb +11 -14
- data/lib/uuidtools/version.rb +1 -1
- data/spec/uuidtools/uuid_parsing_spec.rb +3 -1
- metadata +1 -1
data/CHANGELOG
CHANGED
data/lib/compat/securerandom.rb
CHANGED
@@ -33,165 +33,167 @@
|
|
33
33
|
# p SecureRandom.random_bytes(10) #=> "\323U\030TO\234\357\020\a\337"
|
34
34
|
# ...
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
if !defined?(SecureRandom)
|
37
|
+
begin
|
38
|
+
require 'openssl'
|
39
|
+
rescue LoadError
|
40
|
+
end
|
40
41
|
|
41
|
-
module SecureRandom
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
42
|
+
module SecureRandom
|
43
|
+
# SecureRandom.random_bytes generates a random binary string.
|
44
|
+
#
|
45
|
+
# The argument n specifies the length of the result string.
|
46
|
+
#
|
47
|
+
# If n is not specified, 16 is assumed.
|
48
|
+
# It may be larger in future.
|
49
|
+
#
|
50
|
+
# If secure random number generator is not available,
|
51
|
+
# NotImplementedError is raised.
|
52
|
+
def self.random_bytes(n=nil)
|
53
|
+
n ||= 16
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
|
55
|
+
if defined? OpenSSL::Random
|
56
|
+
return OpenSSL::Random.random_bytes(n)
|
57
|
+
end
|
57
58
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
59
|
+
if !defined?(@has_urandom) || @has_urandom
|
60
|
+
flags = File::RDONLY
|
61
|
+
flags |= File::NONBLOCK if defined? File::NONBLOCK
|
62
|
+
flags |= File::NOCTTY if defined? File::NOCTTY
|
63
|
+
flags |= File::NOFOLLOW if defined? File::NOFOLLOW
|
64
|
+
begin
|
65
|
+
File.open("/dev/urandom", flags) {|f|
|
66
|
+
unless f.stat.chardev?
|
67
|
+
raise Errno::ENOENT
|
68
|
+
end
|
69
|
+
@has_urandom = true
|
70
|
+
ret = f.readpartial(n)
|
71
|
+
if ret.length != n
|
72
|
+
raise NotImplementedError,
|
73
|
+
"Unexpected partial read from random device"
|
74
|
+
end
|
75
|
+
return ret
|
76
|
+
}
|
77
|
+
rescue Errno::ENOENT
|
78
|
+
@has_urandom = false
|
79
|
+
end
|
78
80
|
end
|
79
|
-
end
|
80
81
|
|
81
|
-
|
82
|
-
|
83
|
-
|
82
|
+
if !defined?(@has_win32)
|
83
|
+
begin
|
84
|
+
require 'Win32API'
|
84
85
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
86
|
+
crypt_acquire_context = Win32API.new(
|
87
|
+
"advapi32", "CryptAcquireContext", 'PPPII', 'L'
|
88
|
+
)
|
89
|
+
@crypt_gen_random = Win32API.new(
|
90
|
+
"advapi32", "CryptGenRandom", 'LIP', 'L'
|
91
|
+
)
|
91
92
|
|
92
|
-
|
93
|
-
|
94
|
-
|
93
|
+
hProvStr = " " * 4
|
94
|
+
prov_rsa_full = 1
|
95
|
+
crypt_verifycontext = 0xF0000000
|
95
96
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
97
|
+
if crypt_acquire_context.call(
|
98
|
+
hProvStr, nil, nil, prov_rsa_full, crypt_verifycontext) == 0
|
99
|
+
raise SystemCallError,
|
100
|
+
"CryptAcquireContext failed: #{lastWin32ErrorMessage}"
|
101
|
+
end
|
102
|
+
@hProv, = hProvStr.unpack('L')
|
102
103
|
|
103
|
-
|
104
|
-
|
105
|
-
|
104
|
+
@has_win32 = true
|
105
|
+
rescue LoadError
|
106
|
+
@has_win32 = false
|
107
|
+
end
|
106
108
|
end
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
109
|
+
if @has_win32
|
110
|
+
bytes = " " * n
|
111
|
+
if @crypt_gen_random.call(@hProv, bytes.size, bytes) == 0
|
112
|
+
raise SystemCallError,
|
113
|
+
"CryptGenRandom failed: #{lastWin32ErrorMessage}"
|
114
|
+
end
|
115
|
+
return bytes
|
113
116
|
end
|
114
|
-
return bytes
|
115
|
-
end
|
116
117
|
|
117
|
-
|
118
|
-
|
118
|
+
raise NotImplementedError, "No random device"
|
119
|
+
end
|
119
120
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
121
|
+
# SecureRandom.hex generates a random hex string.
|
122
|
+
#
|
123
|
+
# The argument n specifies the length of the random length.
|
124
|
+
# The length of the result string is twice of n.
|
125
|
+
#
|
126
|
+
# If n is not specified, 16 is assumed.
|
127
|
+
# It may be larger in future.
|
128
|
+
#
|
129
|
+
# If secure random number generator is not available,
|
130
|
+
# NotImplementedError is raised.
|
131
|
+
def self.hex(n=nil)
|
132
|
+
random_bytes(n).unpack("H*")[0]
|
133
|
+
end
|
133
134
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
135
|
+
# SecureRandom.base64 generates a random base64 string.
|
136
|
+
#
|
137
|
+
# The argument n specifies the length of the random length.
|
138
|
+
# The length of the result string is about 4/3 of n.
|
139
|
+
#
|
140
|
+
# If n is not specified, 16 is assumed.
|
141
|
+
# It may be larger in future.
|
142
|
+
#
|
143
|
+
# If secure random number generator is not available,
|
144
|
+
# NotImplementedError is raised.
|
145
|
+
def self.base64(n=nil)
|
146
|
+
[random_bytes(n)].pack("m*").delete("\n")
|
147
|
+
end
|
147
148
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
149
|
+
# SecureRandom.random_number generates a random number.
|
150
|
+
#
|
151
|
+
# If an positive integer is given as n,
|
152
|
+
# SecureRandom.random_number returns an integer:
|
153
|
+
# 0 <= SecureRandom.random_number(n) < n.
|
154
|
+
#
|
155
|
+
# If 0 is given or an argument is not given,
|
156
|
+
# SecureRandom.random_number returns an float:
|
157
|
+
# 0.0 <= SecureRandom.random_number() < 1.0.
|
158
|
+
def self.random_number(n=0)
|
159
|
+
if 0 < n
|
160
|
+
hex = n.to_s(16)
|
161
|
+
hex = '0' + hex if (hex.length & 1) == 1
|
162
|
+
bin = [hex].pack("H*")
|
163
|
+
mask = bin[0].ord
|
164
|
+
mask |= mask >> 1
|
165
|
+
mask |= mask >> 2
|
166
|
+
mask |= mask >> 4
|
167
|
+
begin
|
168
|
+
rnd = SecureRandom.random_bytes(bin.length)
|
169
|
+
rnd[0] = (rnd[0].ord & mask).chr
|
170
|
+
end until rnd < bin
|
171
|
+
rnd.unpack("H*")[0].hex
|
172
|
+
else
|
173
|
+
# assumption: Float::MANT_DIG <= 64
|
174
|
+
i64 = SecureRandom.random_bytes(8).unpack("Q")[0]
|
175
|
+
Math.ldexp(i64 >> (64-Float::MANT_DIG), -Float::MANT_DIG)
|
176
|
+
end
|
175
177
|
end
|
176
|
-
end
|
177
178
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
179
|
+
# Following code is based on David Garamond's GUID library for Ruby.
|
180
|
+
def self.lastWin32ErrorMessage # :nodoc:
|
181
|
+
get_last_error = Win32API.new(
|
182
|
+
"kernel32", "GetLastError", '', 'L'
|
183
|
+
)
|
184
|
+
format_message = Win32API.new(
|
185
|
+
"kernel32", "FormatMessageA", 'LPLLPLPPPPPPPP', 'L'
|
186
|
+
)
|
187
|
+
format_message_ignore_inserts = 0x00000200
|
188
|
+
format_message_from_system = 0x00001000
|
188
189
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
190
|
+
code = get_last_error.call
|
191
|
+
msg = "\0" * 1024
|
192
|
+
len = format_message.call(
|
193
|
+
format_message_ignore_inserts + format_message_from_system,
|
194
|
+
0, code, 0, msg, 1024, nil, nil, nil, nil, nil, nil, nil, nil
|
195
|
+
)
|
196
|
+
msg[0, len].tr("\r", '').chomp
|
197
|
+
end
|
196
198
|
end
|
197
199
|
end
|
data/lib/uuidtools.rb
CHANGED
@@ -377,16 +377,19 @@ class UUID
|
|
377
377
|
end
|
378
378
|
return result.downcase
|
379
379
|
end
|
380
|
+
alias_method :to_str, :to_s
|
380
381
|
|
381
382
|
# Returns an integer representation for this UUID.
|
382
383
|
def to_i
|
383
|
-
|
384
|
-
(
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
384
|
+
@integer ||= (begin
|
385
|
+
bytes = (time_low << 96) + (time_mid << 80) +
|
386
|
+
(time_hi_and_version << 64) + (clock_seq_hi_and_reserved << 56) +
|
387
|
+
(clock_seq_low << 48)
|
388
|
+
for i in 0..5
|
389
|
+
bytes += (nodes[i] << (40 - (i * 8)))
|
390
|
+
end
|
391
|
+
bytes
|
392
|
+
end)
|
390
393
|
end
|
391
394
|
|
392
395
|
# Returns a URI string for this UUID.
|
@@ -396,7 +399,7 @@ class UUID
|
|
396
399
|
|
397
400
|
# Returns an integer hash value.
|
398
401
|
def hash
|
399
|
-
|
402
|
+
@hash ||= self.to_i % 0x3fffffff
|
400
403
|
end
|
401
404
|
|
402
405
|
# Returns true if this UUID is exactly equal to the other UUID.
|
@@ -584,9 +587,3 @@ UUID_DNS_NAMESPACE = UUID.parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
|
|
584
587
|
UUID_URL_NAMESPACE = UUID.parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
|
585
588
|
UUID_OID_NAMESPACE = UUID.parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
|
586
589
|
UUID_X500_NAMESPACE = UUID.parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
|
587
|
-
|
588
|
-
at_exit do
|
589
|
-
if UUID.instance_variable_get("@random_device") != nil
|
590
|
-
UUID.instance_variable_get("@random_device").close rescue nil
|
591
|
-
end
|
592
|
-
end
|
data/lib/uuidtools/version.rb
CHANGED
@@ -90,7 +90,9 @@ describe UUID, "when parsing" do
|
|
90
90
|
end
|
91
91
|
|
92
92
|
it "should produce a sane hash value for a UUID" do
|
93
|
-
UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0])
|
93
|
+
uuid = UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0])
|
94
|
+
uuid.to_i.should == 0
|
95
|
+
uuid.hash.should be_kind_of(Fixnum)
|
94
96
|
end
|
95
97
|
|
96
98
|
it "should produce the correct URI for a UUID" do
|