uuidtools-2.1.4/Rakefile 0000644 0000041 0000041 00000002071 12153751615 015250 0 ustar www-data www-data require 'rubygems'
require 'rake'
require File.join(File.dirname(__FILE__), 'lib', 'uuidtools', 'version')
PKG_DISPLAY_NAME = 'UUIDTools'
PKG_NAME = PKG_DISPLAY_NAME.downcase
PKG_VERSION = UUIDTools::VERSION::STRING
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
RELEASE_NAME = "REL #{PKG_VERSION}"
RUBY_FORGE_PROJECT = PKG_NAME
RUBY_FORGE_USER = "sporkmonger"
RUBY_FORGE_PATH = "/var/www/gforge-projects/#{RUBY_FORGE_PROJECT}"
RUBY_FORGE_URL = "http://#{RUBY_FORGE_PROJECT}.rubyforge.org/"
PKG_SUMMARY = "UUID generator"
PKG_DESCRIPTION = <<-TEXT
A simple universally unique ID generation library.
TEXT
PKG_FILES = FileList[
"lib/**/*", "spec/**/*", "vendor/**/*",
"tasks/**/*", "website/**/*",
"[A-Z]*", "Rakefile"
].exclude(/database\.yml/).exclude(/[_\.]git$/).exclude(/Gemfile/).exclude(/Gemfile\.lock/)
task :default => "spec"
WINDOWS = (RUBY_PLATFORM =~ /mswin|win32|mingw|bccwin|cygwin/) rescue false
SUDO = WINDOWS ? '' : ('sudo' unless ENV['SUDOLESS'])
Dir['tasks/**/*.rake'].each { |rake| load rake }
uuidtools-2.1.4/spec/ 0000755 0000041 0000041 00000000000 12153751615 014535 5 ustar www-data www-data uuidtools-2.1.4/spec/spec.opts 0000644 0000041 0000041 00000000011 12153751615 016366 0 ustar www-data www-data --colour
uuidtools-2.1.4/spec/uuidtools/ 0000755 0000041 0000041 00000000000 12153751615 016564 5 ustar www-data www-data uuidtools-2.1.4/spec/uuidtools/utility_spec.rb 0000644 0000041 0000041 00000001162 12153751615 021626 0 ustar www-data www-data require File.expand_path("../../spec_helper.rb", __FILE__)
describe SecureRandom do
it "should correctly obtain random bits" do
bits = []
1000.times do
bits << SecureRandom.random_bytes(16)
end
# Check to make sure that none of the 10,000 strings were duplicates
(bits.map {|x| x.to_s}).uniq.size.should == bits.size
end
it "should return the correct number of random bits" do
SecureRandom.random_bytes(16).size.should == 16
SecureRandom.random_bytes(6).size.should == 6
end
it "should return a sane random number" do
SecureRandom.random_number(5000).should < 5000
end
end
uuidtools-2.1.4/spec/uuidtools/uuid_creation_spec.rb 0000644 0000041 0000041 00000010503 12153751615 022754 0 ustar www-data www-data require File.expand_path("../../spec_helper.rb", __FILE__)
describe UUIDTools::UUID, "when generating" do
it "should correctly generate SHA1 variant UUIDs" do
UUIDTools::UUID.sha1_create(
UUIDTools::UUID_URL_NAMESPACE, 'http://sporkmonger.com'
).to_s.should == "f2d04685-b787-55da-8644-9bd28a6f5a53"
end
it "should correctly generate MD5 variant UUIDs" do
UUIDTools::UUID.md5_create(
UUIDTools::UUID_URL_NAMESPACE, 'http://sporkmonger.com'
).to_s.should == "15074785-9071-3fe3-89bd-876e4b9e919b"
end
it "should correctly generate timestamp variant UUIDs" do
UUIDTools::UUID.timestamp_create.should_not be_random_node_id
UUIDTools::UUID.timestamp_create.to_s.should_not ==
UUIDTools::UUID.timestamp_create.to_s
current_time = Time.now
UUIDTools::UUID.timestamp_create(current_time).to_s.should_not ==
UUIDTools::UUID.timestamp_create(current_time).to_s
uuids = []
1000.times do
uuids << UUIDTools::UUID.timestamp_create
end
# Check to make sure that none of the 1,000 UUIDs were duplicates
(uuids.map {|x| x.to_s}).uniq.size.should == uuids.size
end
it "should correctly generate UUIDs without a MAC address" do
mac_address = UUIDTools::UUID.mac_address
UUIDTools::UUID.mac_address = nil
UUIDTools::UUID.timestamp_create.should be_random_node_id
UUIDTools::UUID.mac_address = mac_address
end
it "should correctly generate random number variant UUIDs" do
uuids = []
1000.times do
uuids << UUIDTools::UUID.random_create
end
# Check to make sure that none of the 1,000 UUIDs were duplicates
(uuids.map {|x| x.to_s}).uniq.size.should == uuids.size
end
it "should not have internal state used in string representations" do
uuid = UUIDTools::UUID.random_create
uuid_string = uuid.to_s.dup
uuid.to_s.gsub!("-", "/")
uuid.to_s.should == uuid_string
end
it "should throw an exception if a segment has an invalid value" do
(lambda do
UUIDTools::UUID.new(-1, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0])
end).should raise_error(ArgumentError)
(lambda do
UUIDTools::UUID.new(4294967296, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0])
end).should raise_error(ArgumentError)
end
it "should throw an exception if a segment has an invalid value" do
(lambda do
UUIDTools::UUID.new(0, -1, 0, 0, 0, [0, 0, 0, 0, 0, 0])
end).should raise_error(ArgumentError)
(lambda do
UUIDTools::UUID.new(0, 65536, 0, 0, 0, [0, 0, 0, 0, 0, 0])
end).should raise_error(ArgumentError)
end
it "should throw an exception if a segment has an invalid value" do
(lambda do
UUIDTools::UUID.new(0, 0, -1, 0, 0, [0, 0, 0, 0, 0, 0])
end).should raise_error(ArgumentError)
(lambda do
UUIDTools::UUID.new(0, 0, 65536, 0, 0, [0, 0, 0, 0, 0, 0])
end).should raise_error(ArgumentError)
end
it "should throw an exception if a segment has an invalid value" do
(lambda do
UUIDTools::UUID.new(0, 0, 0, -1, 0, [0, 0, 0, 0, 0, 0])
end).should raise_error(ArgumentError)
(lambda do
UUIDTools::UUID.new(0, 0, 0, 256, 0, [0, 0, 0, 0, 0, 0])
end).should raise_error(ArgumentError)
end
it "should throw an exception if a segment has an invalid value" do
(lambda do
UUIDTools::UUID.new(0, 0, 0, 0, -1, [0, 0, 0, 0, 0, 0])
end).should raise_error(ArgumentError)
(lambda do
UUIDTools::UUID.new(0, 0, 0, 0, 256, [0, 0, 0, 0, 0, 0])
end).should raise_error(ArgumentError)
end
it "should throw an exception if nodes are not a collection" do
(lambda do
UUIDTools::UUID.new(0, 0, 0, 0, 0, :bogus)
end).should raise_error(TypeError)
end
it "should throw an exception if nodes are the wrong size" do
(lambda do
UUIDTools::UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0])
end).should raise_error(ArgumentError)
end
it "should throw an exception if any nodes have invalid values" do
(lambda do
UUIDTools::UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 256])
end).should raise_error(ArgumentError)
end
it "should throw an exception if parsing anything but a String" do
(lambda do
UUIDTools::UUID.parse(:bogus)
end).should raise_error(TypeError)
end
it "should throw an exception if raw parsing anything but a String" do
(lambda do
UUIDTools::UUID.parse_raw(:bogus)
end).should raise_error(TypeError)
end
end
uuidtools-2.1.4/spec/uuidtools/mac_address_spec.rb 0000644 0000041 0000041 00000034476 12153751615 022406 0 ustar www-data www-data require File.expand_path("../../spec_helper.rb", __FILE__)
def pending_if_root_required
if @mac_address == nil
output = `ifconfig -a 2>&1`
if output =~ /inet/ &&
output =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ &&
output =~ /Warning: cannot open/
pending("Cannot get MAC address without root?")
end
end
end
# ===========================================================================
#
# Samples of ifconfig -a output
#
# ===========================================================================
#
# solaris
#
solaris_sample = < mtu 8232 index 1
inet 127.0.0.1 netmask ff000000
igb1: flags=1000843 mtu 1500 index 2
inet 10.51.0.18 netmask ffffff00 broadcast 10.51.0.255
ether 0:21:28:fa:c6:65
igb2: flags=1000843 mtu 1500 index 3
inet 10.99.0.12 netmask ffffff00 broadcast 10.99.0.255
ether 0:21:28:fa:c6:66
EOF
solaris_mac = "00:21:28:fa:c6:65"
#
# windows
#
windows_sample = < mtu 1500
inet 10.16.187.71 netmask 255.255.252.0 broadcast 10.16.187.255
inet6 fe80::226:2dff:fef6:b94 prefixlen 64 scopeid 0x20
ether 00:26:2d:f6:0b:94 txqueuelen 1000 (Ethernet)
RX packets 172074 bytes 82784684 (78.9 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 99075 bytes 23551085 (22.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 20 memory 0xf2600000-f2620000
lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10
loop txqueuelen 0 (Local Loopback)
RX packets 20 bytes 2148 (2.0 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 20 bytes 2148 (2.0 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
EOF
linux_mac = "00:26:2d:f6:0b:94"
#
# alternate linux
#
linux_sample_2 = < mtu 65536 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:26:2d:f6:0b:94 brd ff:ff:ff:ff:ff:ff
inet 10.16.187.125/22 brd 10.16.187.255 scope global eth0
inet6 fe80::226:2dff:fef6:b94/64 scope link
valid_lft forever preferred_lft forever
3: wlan0: mtu 1500 qdisc mq state DOWN qlen 1000
link/ether 00:26:c6:c6:1a:b4 brd ff:ff:ff:ff:ff:ff
4: virbr0: mtu 1500 qdisc noqueue state DOWN
link/ether 52:54:00:e3:cf:d3 brd ff:ff:ff:ff:ff:ff
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
5: virbr0-nic: mtu 1500 qdisc pfifo_fast master virbr0 state DOWN qlen 500
link/ether 52:54:00:e3:cf:d3 brd ff:ff:ff:ff:ff:ff
EOF
linux_ip_mac = "00:26:2d:f6:0b:94"
#
# freebsd
#
freebsd_sample = < metric 0 mtu 1500
options=401bb
ether 00:25:90:2b:81:32
inet6 fe80::225:90ff:fe2b:8132%igb0 prefixlen 64 scopeid 0x1
nd6 options=29
media: Ethernet autoselect (1000baseT )
status: active
igb1: flags=8843 metric 0 mtu 1500
options=401bb
ether 00:25:90:2b:81:32
inet6 fe80::225:90ff:fe2b:8133%igb1 prefixlen 64 scopeid 0x2
nd6 options=29
media: Ethernet autoselect (1000baseT )
EOF
freebsd_mac = "00:25:90:2b:81:32"
#
# openbsd
#
openbsd_sample = < mtu 33200
priority: 0
groups: lo
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x5
vr0: flags=8843 mtu 1500
lladdr 00:0d:b9:28:ab:44
priority: 0
media: Ethernet autoselect (100baseTX full-duplex)
status: active
inet 192.168.7.2 netmask 0xffffff00 broadcast 192.168.7.255
inet6 fe80::20d:b9ff:fe28:ab44%vr0 prefixlen 64 scopeid 0x1
EOF
openbsd_mac = "00:0d:b9:28:ab:44"
#
# MacOS 10
#
macos_sample = < mtu 16384
options=3
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
gif0: flags=8010 mtu 1280
stf0: flags=0<> mtu 1280
en0: flags=8963 mtu 1500
options=27
ether 58:b0:35:a4:cd:0c
inet6 fe80::5ab0:35ff:fea4:cd0c%en0 prefixlen 64 scopeid 0x4
inet 192.168.142.136 netmask 0xfffffff0 broadcast 192.168.142.143
media: autoselect (1000baseT )
status: active
en1: flags=8823 mtu 1500
ether d8:30:62:51:dd:3d
media: autoselect ()
status: inactive
p2p0: flags=8802 mtu 2304
ether 0a:30:62:51:dd:3d
media: autoselect
status: inactive
EOF
macos_mac = "58:b0:35:a4:cd:0c"
# Gather the samples and MAC addresses for simple access
samples = {
:macos => macos_sample,
:windows => windows_sample,
:solaris => solaris_sample,
:freebsd => freebsd_sample,
:openbsd => openbsd_sample,
:linux => linux_sample,
:linux2 => linux_sample_2,
:linuxip => linux_ip_sample
}
macs = {
:macos => macos_mac,
:windows => windows_mac,
:solaris => solaris_mac,
:freebsd => freebsd_mac,
:openbsd => openbsd_mac,
:linux => linux_mac,
:linux2 => linux_mac_2,
:linuxip => linux_ip_mac
}
# --------------------------------------------------------------------------
#
# TESTS
#
# --------------------------------------------------------------------------
describe UUIDTools::UUID, "when obtaining a MAC address" do
before do
@mac_address = UUIDTools::UUID.mac_address
end
it "should obtain a MAC address" do
pending_if_root_required()
@mac_address.should_not be_nil
end
it "should cache the MAC address" do
pending_if_root_required()
@mac_address.object_id.should == UUIDTools::UUID.mac_address.object_id
end
end
describe UUIDTools::UUID, "before obtaining a MAC address" do
before do
module UUIDTools
class UUID
remove_class_variable(:@@mac_address) if defined?(@@mac_address)
end
end
end
it "should parse windows MAC addresses" do
# mock ifconfig() to return the windows sample
UUIDTools::UUID.stub(:ifconfig).and_return(samples[:windows])
mac = UUIDTools::UUID.mac_address
mac.should be == macs[:windows]
end
it "should parse solaris MAC addresses" do
UUIDTools::UUID.stub(:ifconfig).and_return(samples[:solaris])
mac = UUIDTools::UUID.mac_address
mac.should be == macs[:solaris]
end
it "should parse freebsd MAC addresses" do
UUIDTools::UUID.stub(:ifconfig).and_return(samples[:freebsd])
mac = UUIDTools::UUID.mac_address
mac.should be == macs[:freebsd]
end
it "should parse openbsd MAC addresses" do
UUIDTools::UUID.stub(:ifconfig).and_return(samples[:openbsd])
mac = UUIDTools::UUID.mac_address
mac.should be == macs[:openbsd]
end
it "should parse linux MAC addresses with ifconfig" do
UUIDTools::UUID.stub(:ifconfig).and_return(samples[:linux])
mac = UUIDTools::UUID.mac_address
mac.should be == macs[:linux]
end
it "should parse a linux HWaddr address with ifconfig" do
UUIDTools::UUID.stub(:ifconfig).and_return(samples[:linux2])
mac = UUIDTools::UUID.mac_address
mac.should be == macs[:linux2]
end
it "should parse macos MAC addresses with ifconfig" do
UUIDTools::UUID.stub(:ifconfig).and_return(samples[:macos])
mac = UUIDTools::UUID.mac_address
mac.should be == macs[:macos]
end
it "should parse linux MAC addresses with ip" do
UUIDTools::UUID.stub(:ifconfig).and_return(samples[:linuxip])
mac = UUIDTools::UUID.mac_address
mac.should be == macs[:linuxip]
end
it "should identify the default os classes" do
module RbConfig
CONFIG['target_os'] = nil
end
os_class = UUIDTools::UUID.os_class
os_class.should be == nil
RbConfig::CONFIG['target_os'] = 'linux'
os_class = UUIDTools::UUID.os_class
os_class.should be == nil
RbConfig::CONFIG['target_os'] = 'darwin'
os_class = UUIDTools::UUID.os_class
os_class.should be == nil
end
it "should identify the solaris os classes" do
module RbConfig
CONFIG['target_os'] = "solaris"
end
os_class = UUIDTools::UUID.os_class
os_class.should be == :solaris
end
it "should identify the BSD os classes" do
module RbConfig
CONFIG['target_os'] = "netbsd"
end
os_class = UUIDTools::UUID.os_class
os_class.should be == :netbsd
RbConfig::CONFIG['target_os'] = "openbsd"
os_class = UUIDTools::UUID.os_class
os_class.should be == :openbsd
end
it "should identify the Windows os classes" do
module RbConfig
CONFIG['target_os'] = "win"
end
os_class = UUIDTools::UUID.os_class
os_class.should be == :windows
RbConfig::CONFIG['target_os'] = "w32"
os_class = UUIDTools::UUID.os_class
os_class.should be == :windows
RbConfig::CONFIG['target_os'] = "darwin"
os_class = UUIDTools::UUID.os_class
os_class.should be == nil
end
it "should find the ifconfig program" do
save_ifconfig_command = UUIDTools::UUID.ifconfig_command
save_ifconfig_path = UUIDTools::UUID.ifconfig_path_default
# this should always exist
UUIDTools::UUID.ifconfig_command="sh"
UUIDTools::UUID.ifconfig_path_default="notfound"
ifconfig_path = UUIDTools::UUID.ifconfig_path
# ifconfig_path.should be == "/usr/bin/sh"
# Test what happens if it does not
UUIDTools::UUID.ifconfig_command="nosuchthing"
UUIDTools::UUID.ifconfig_path_default="default"
# ifconfig_path checks if the IFCONFIG_PATH command file exists
File.stub(:exist?).and_return(true)
ifconfig_path = UUIDTools::UUID.ifconfig_path
# ifconfig_path.should be == "default"
UUIDTools::UUID.ifconfig_command=save_ifconfig_command
UUIDTools::UUID.ifconfig_path_default=save_ifconfig_path
end
it "should find the ip program" do
save_ip_command = UUIDTools::UUID.ip_command
save_ip_path = UUIDTools::UUID.ip_path_default
# this should always exist
UUIDTools::UUID.ip_command="sh"
UUIDTools::UUID.ip_path_default="notfound"
ip_path = UUIDTools::UUID.ip_path
# ip_path.should be == "/usr/bin/sh"
# Test what happens if it does not
UUIDTools::UUID.ip_command="nosuchthing"
UUIDTools::UUID.ip_path_default="default"
# ifconfig_path checks if the IP_PATH command file exists
File.stub(:exist?).and_return(true)
ifconfig_path = UUIDTools::UUID.ip_path
# ifconfig_path.should be == "default"
UUIDTools::UUID.ip_command=save_ip_command
UUIDTools::UUID.ip_path_default=save_ip_path
end
it "should return the output of the ifconfig program" do
pending "I'm not quite sure how to mock backticks"
end
it "should be able to parse windows ipconfig output" do
mac = UUIDTools::UUID.first_mac samples[:windows]
mac.should be == macs[:windows]
end
it "should be able to parse solaris ifconfig output" do
mac = UUIDTools::UUID.first_mac samples[:solaris]
mac.should be == macs[:solaris]
end
it "should be able to parse freebsd ifconfig output" do
mac = UUIDTools::UUID.first_mac samples[:freebsd]
mac.should be == macs[:freebsd]
end
it "should be able to parse openbsd ifconfig output" do
mac = UUIDTools::UUID.first_mac samples[:openbsd]
mac.should be == macs[:openbsd]
end
it "should be able to parse linux ifconfig output" do
mac = UUIDTools::UUID.first_mac samples[:linux]
mac.should be == macs[:linux]
mac2 = UUIDTools::UUID.first_mac samples[:linux2]
mac2.should be == macs[:linux2]
end
it "should be able to parse macos ifconfig output" do
mac = UUIDTools::UUID.first_mac samples[:macos]
mac.should be == macs[:macos]
end
it "should be able to parse ip addr output" do
mac = UUIDTools::UUID.first_mac samples[:linuxip]
mac.should be == macs[:linuxip]
end
end
uuidtools-2.1.4/spec/uuidtools/uuid_parsing_spec.rb 0000644 0000041 0000041 00000011033 12153751615 022612 0 ustar www-data www-data require File.expand_path("../../spec_helper.rb", __FILE__)
describe UUIDTools::UUID, "when parsing" do
it "should correctly parse the MAC address from a timestamp version UUID" do
UUIDTools::UUID.timestamp_create.mac_address.should ==
UUIDTools::UUID.mac_address
end
it "should correctly parse the variant from a timestamp version UUID" do
UUIDTools::UUID.timestamp_create.variant.should == 0b100
end
it "should correctly parse the version from a timestamp version UUID" do
UUIDTools::UUID.timestamp_create.version.should == 1
end
it "should correctly parse the timestamp from a timestamp version UUID" do
UUIDTools::UUID.timestamp_create.timestamp.should < Time.now + 1
UUIDTools::UUID.timestamp_create.timestamp.should > Time.now - 1
end
it "should not treat a timestamp version UUID as a nil UUID" do
UUIDTools::UUID.timestamp_create.should_not be_nil_uuid
end
it "should not treat a timestamp version UUID as a random node UUID" do
UUIDTools::UUID.timestamp_create.should_not be_random_node_id
end
it "should treat a timestamp version UUID as a random node UUID " +
"if there is no MAC address" do
old_mac_address = UUIDTools::UUID.mac_address
UUIDTools::UUID.mac_address = nil
UUIDTools::UUID.timestamp_create.should be_random_node_id
UUIDTools::UUID.mac_address = old_mac_address
end
it "should correctly identify the nil UUID" do
UUIDTools::UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).should be_nil_uuid
end
it "should correctly identify timestamp version UUIDs as valid" do
UUIDTools::UUID.timestamp_create.should be_valid
end
it "should correctly identify random number version UUIDs as valid" do
UUIDTools::UUID.random_create.should be_valid
end
it "should correctly identify SHA1 hash version UUIDs as valid" do
UUIDTools::UUID.sha1_create(
UUIDTools::UUID_URL_NAMESPACE, 'http://sporkmonger.com'
).should be_valid
end
it "should correctly identify MD5 hash version UUIDs as valid" do
UUIDTools::UUID.md5_create(
UUIDTools::UUID_URL_NAMESPACE, 'http://sporkmonger.com'
).should be_valid
end
it "should not identify the nil UUID as valid" do
UUIDTools::UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).should_not be_valid
end
it "should allow for sorting of UUID arrays" do
uuids = []
1000.times do
uuids << UUIDTools::UUID.timestamp_create
end
uuids.sort!
uuids.first.should < uuids.last
uuids.last.should > uuids.first
end
it "should allow for comparison of UUIDs" do
UUIDTools::UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).should <
UUIDTools::UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 1])
UUIDTools::UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 1]).should >
UUIDTools::UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0])
UUIDTools::UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).should ==
UUIDTools::UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0])
end
it "should produce the correct hexdigest for a UUID" do
UUIDTools::UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).hexdigest.should ==
"00000000000000000000000000000000"
UUIDTools::UUID.new(1, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).hexdigest.should ==
"00000001000000000000000000000000"
UUIDTools::UUID.timestamp_create.hexdigest.size.should == 32
end
it "should produce a sane hash value for a UUID" do
uuid = UUIDTools::UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0])
uuid.to_i.should == 0
uuid.hash.should be_kind_of(Fixnum)
end
it "should produce the correct URI for a UUID" do
UUIDTools::UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).to_uri.should ==
"urn:uuid:00000000-0000-0000-0000-000000000000"
end
it "should correctly test UUID equality" do
UUIDTools::UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).should be_eql(
UUIDTools::UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0])
)
end
it "should correctly parse integers" do
UUIDTools::UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).should ==
UUIDTools::UUID.parse_int(0)
UUIDTools::UUID.parse_int(0).should be_nil_uuid
uuid = UUIDTools::UUID.timestamp_create
UUIDTools::UUID.parse_int(uuid.to_i).should == uuid
end
it "should correctly parse hexdigests" do
UUIDTools::UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).should ==
UUIDTools::UUID.parse_hexdigest("00000000000000000000000000000000")
UUIDTools::UUID.parse_hexdigest(
"00000000000000000000000000000000"
).should be_nil_uuid
uuid = UUIDTools::UUID.timestamp_create
UUIDTools::UUID.parse_hexdigest(uuid.hexdigest).should == uuid
end
end
uuidtools-2.1.4/spec/spec_helper.rb 0000644 0000041 0000041 00000000260 12153751615 017351 0 ustar www-data www-data $VERBOSE=true
spec_dir = File.expand_path(File.dirname(__FILE__))
lib_dir = File.expand_path(File.join(spec_dir, "../lib"))
$:.unshift(lib_dir)
$:.uniq!
require "uuidtools"
uuidtools-2.1.4/LICENSE.txt 0000644 0000041 0000041 00000025143 12153751615 015433 0 ustar www-data www-data
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
uuidtools-2.1.4/metadata.yml 0000644 0000041 0000041 00000005741 12153751615 016115 0 ustar www-data www-data --- !ruby/object:Gem::Specification
name: uuidtools
version: !ruby/object:Gem::Version
version: 2.1.4
prerelease:
platform: ruby
authors:
- Bob Aman
autorequire:
bindir: bin
cert_chain: []
date: 2013-04-25 00:00:00.000000000 Z
dependencies:
- !ruby/object:Gem::Dependency
name: rake
requirement: !ruby/object:Gem::Requirement
none: false
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: 0.7.3
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
none: false
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: 0.7.3
- !ruby/object:Gem::Dependency
name: rspec
requirement: !ruby/object:Gem::Requirement
none: false
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: 2.9.0
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
none: false
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: 2.9.0
- !ruby/object:Gem::Dependency
name: yard
requirement: !ruby/object:Gem::Requirement
none: false
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: 0.8.2
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
none: false
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: 0.8.2
- !ruby/object:Gem::Dependency
name: launchy
requirement: !ruby/object:Gem::Requirement
none: false
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: 2.0.0
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
none: false
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: 2.0.0
description: ! 'A simple universally unique ID generation library.
'
email: bob@sporkmonger.com
executables: []
extensions: []
extra_rdoc_files:
- README.md
files:
- lib/compat/securerandom.rb
- lib/uuidtools.rb
- lib/uuidtools/version.rb
- spec/spec.opts
- spec/spec_helper.rb
- spec/uuidtools/mac_address_spec.rb
- spec/uuidtools/utility_spec.rb
- spec/uuidtools/uuid_creation_spec.rb
- spec/uuidtools/uuid_parsing_spec.rb
- tasks/benchmark.rake
- tasks/gem.rake
- tasks/git.rake
- tasks/metrics.rake
- tasks/rspec.rake
- tasks/rubyforge.rake
- tasks/yard.rake
- website/index.html
- CHANGELOG
- LICENSE.txt
- README.md
- Rakefile
homepage: http://uuidtools.rubyforge.org/
licenses: []
post_install_message:
rdoc_options:
- --main
- README.md
require_paths:
- lib
required_ruby_version: !ruby/object:Gem::Requirement
none: false
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: '0'
required_rubygems_version: !ruby/object:Gem::Requirement
none: false
requirements:
- - ! '>='
- !ruby/object:Gem::Version
version: '0'
requirements: []
rubyforge_project:
rubygems_version: 1.8.24
signing_key:
specification_version: 3
summary: UUID generator
test_files: []
uuidtools-2.1.4/CHANGELOG 0000644 0000041 0000041 00000004353 12153751615 015022 0 ustar www-data www-data == UUIDTools 2.1.4
* various OS-specific improvements to obtaining MAC address
== UUIDTools 2.1.3
* changes to build system
== UUIDTools 2.1.2
* fixed issue with frozen objects
* fixed issue with running specs in Ruby 1.9.2
== UUIDTools 2.1.1
* fixed issue with Ruby 1.9 compatibility
== UUIDTools 2.1.0
* completely reworked the MAC address detection code
* added additional parsing methods
== UUIDTools 2.0.0
* moved to its own module to avoid collisions
== UUIDTools 1.0.7
* fixed incompatible SecureRandom implementation
== UUIDTools 1.0.6
* fixed Bignum hash issue
* added implicit to_str cast
== UUIDTools 1.0.5
* improved specs
* fixed minor bugs
* better JRuby compatibility
* uses securerandom library
* updated rake tasks
== UUIDTools 1.0.4
* calculates random node id with multicast bit if there is no MAC address
* uses RSpec instead of Test::Unit
* works in Ruby 1.9
* cleaned up some code
* removed deprecated methods
* changed version constant
* new gem file structure
== UUIDTools 1.0.3
* improved code for obtaining a MAC address within JRuby
== UUIDTools 1.0.2
* improved code for obtaining a MAC address for Solaris and OpenBSD
* added hash and eql? methods
== UUIDTools 1.0.1
* improved code for obtaining a MAC address for Solaris and NetBSD
* MAC addresses can now be set manually
* replaced random number generator, less effective on Windows, but faster
* fixed inheritance issues
* changed UUID#to_uri method to return a string instead of a URI object
* removed UUID#to_uri_string
== UUIDTools 1.0.0
* slight improvements to the random number generator
* fixed issue with failing to obtain mac address in certain environments
== UUIDTools 0.1.4
* improved speed when generating timestamp-based uuids
* fixed bug with rapid generation of timestamp uuids leading to duplicates
* improved code for detection of mac address
== UUIDTools 0.1.3
* fixed issue with UUID#raw attempting to call protected class methods
== UUIDTools 0.1.2
* fixed variant method
* added valid? method
* changed timestamp_create method to allow creation of UUIDs from
arbitrary timestamps
== UUIDTools 0.1.1
* changed helper methods to be protected like they should have been
== UUIDTools 0.1.0
* parsing and generation of UUIDs implemented
uuidtools-2.1.4/lib/ 0000755 0000041 0000041 00000000000 12153751615 014351 5 ustar www-data www-data uuidtools-2.1.4/lib/compat/ 0000755 0000041 0000041 00000000000 12153751615 015634 5 ustar www-data www-data uuidtools-2.1.4/lib/compat/securerandom.rb 0000644 0000041 0000041 00000014166 12153751615 020660 0 ustar www-data www-data # = Secure random number generator interface.
#
# This library is an interface for secure random number generator which is
# suitable for generating session key in HTTP cookies, etc.
#
# It supports following secure random number generators.
#
# * openssl
# * /dev/urandom
# * Win32
#
# == Example
#
# # random hexadecimal string.
# p SecureRandom.hex(10) #=> "52750b30ffbc7de3b362"
# p SecureRandom.hex(10) #=> "92b15d6c8dc4beb5f559"
# p SecureRandom.hex(11) #=> "6aca1b5c58e4863e6b81b8"
# p SecureRandom.hex(12) #=> "94b2fff3e7fd9b9c391a2306"
# p SecureRandom.hex(13) #=> "39b290146bea6ce975c37cfc23"
# ...
#
# # random base64 string.
# p SecureRandom.base64(10) #=> "EcmTPZwWRAozdA=="
# p SecureRandom.base64(10) #=> "9b0nsevdwNuM/w=="
# p SecureRandom.base64(10) #=> "KO1nIU+p9DKxGg=="
# p SecureRandom.base64(11) #=> "l7XEiFja+8EKEtY="
# p SecureRandom.base64(12) #=> "7kJSM/MzBJI+75j8"
# p SecureRandom.base64(13) #=> "vKLJ0tXBHqQOuIcSIg=="
# ...
#
# # random binary string.
# p SecureRandom.random_bytes(10) #=> "\016\t{\370g\310pbr\301"
# p SecureRandom.random_bytes(10) #=> "\323U\030TO\234\357\020\a\337"
# ...
if !defined?(SecureRandom)
begin
require 'openssl'
rescue LoadError
end
module SecureRandom
# SecureRandom.random_bytes generates a random binary string.
#
# The argument n specifies the length of the result string.
#
# If n is not specified, 16 is assumed.
# It may be larger in future.
#
# If secure random number generator is not available,
# NotImplementedError is raised.
def self.random_bytes(n=nil)
n ||= 16
if defined? OpenSSL::Random
return OpenSSL::Random.random_bytes(n)
end
if !defined?(@has_urandom) || @has_urandom
flags = File::RDONLY
flags |= File::NONBLOCK if defined? File::NONBLOCK
flags |= File::NOCTTY if defined? File::NOCTTY
flags |= File::NOFOLLOW if defined? File::NOFOLLOW
begin
File.open("/dev/urandom", flags) {|f|
unless f.stat.chardev?
raise Errno::ENOENT
end
@has_urandom = true
ret = f.readpartial(n)
if ret.length != n
raise NotImplementedError,
"Unexpected partial read from random device"
end
return ret
}
rescue Errno::ENOENT
@has_urandom = false
end
end
if !defined?(@has_win32)
begin
require 'Win32API'
crypt_acquire_context = Win32API.new(
"advapi32", "CryptAcquireContext", 'PPPII', 'L'
)
@crypt_gen_random = Win32API.new(
"advapi32", "CryptGenRandom", 'LIP', 'L'
)
hProvStr = " " * 4
prov_rsa_full = 1
crypt_verifycontext = 0xF0000000
if crypt_acquire_context.call(
hProvStr, nil, nil, prov_rsa_full, crypt_verifycontext) == 0
raise SystemCallError,
"CryptAcquireContext failed: #{lastWin32ErrorMessage}"
end
@hProv, = hProvStr.unpack('L')
@has_win32 = true
rescue LoadError
@has_win32 = false
end
end
if @has_win32
bytes = " " * n
if @crypt_gen_random.call(@hProv, bytes.size, bytes) == 0
raise SystemCallError,
"CryptGenRandom failed: #{lastWin32ErrorMessage}"
end
return bytes
end
raise NotImplementedError, "No random device"
end
# SecureRandom.hex generates a random hex string.
#
# The argument n specifies the length of the random length.
# The length of the result string is twice of n.
#
# If n is not specified, 16 is assumed.
# It may be larger in future.
#
# If secure random number generator is not available,
# NotImplementedError is raised.
def self.hex(n=nil)
random_bytes(n).unpack("H*")[0]
end
# SecureRandom.base64 generates a random base64 string.
#
# The argument n specifies the length of the random length.
# The length of the result string is about 4/3 of n.
#
# If n is not specified, 16 is assumed.
# It may be larger in future.
#
# If secure random number generator is not available,
# NotImplementedError is raised.
def self.base64(n=nil)
[random_bytes(n)].pack("m*").delete("\n")
end
# SecureRandom.random_number generates a random number.
#
# If an positive integer is given as n,
# SecureRandom.random_number returns an integer:
# 0 <= SecureRandom.random_number(n) < n.
#
# If 0 is given or an argument is not given,
# SecureRandom.random_number returns an float:
# 0.0 <= SecureRandom.random_number() < 1.0.
def self.random_number(n=0)
if 0 < n
hex = n.to_s(16)
hex = '0' + hex if (hex.length & 1) == 1
bin = [hex].pack("H*")
first = bin[0..0]
mask = first.respond_to?(:ord) ? first.ord : first.sum(8)
mask |= mask >> 1
mask |= mask >> 2
mask |= mask >> 4
begin
rnd = SecureRandom.random_bytes(bin.length)
first = rnd[0..0]
ordinal = first.respond_to?(:ord) ? first.ord : first.sum(8)
rnd[0..0] = (ordinal & mask).chr
end until rnd < bin
rnd.unpack("H*")[0].hex
else
# assumption: Float::MANT_DIG <= 64
i64 = SecureRandom.random_bytes(8).unpack("Q")[0]
Math.ldexp(i64 >> (64-Float::MANT_DIG), -Float::MANT_DIG)
end
end
# Following code is based on David Garamond's GUID library for Ruby.
def self.lastWin32ErrorMessage # :nodoc:
get_last_error = Win32API.new(
"kernel32", "GetLastError", '', 'L'
)
format_message = Win32API.new(
"kernel32", "FormatMessageA", 'LPLLPLPPPPPPPP', 'L'
)
format_message_ignore_inserts = 0x00000200
format_message_from_system = 0x00001000
code = get_last_error.call
msg = "\0" * 1024
len = format_message.call(
format_message_ignore_inserts + format_message_from_system,
0, code, 0, msg, 1024, nil, nil, nil, nil, nil, nil, nil, nil
)
msg[0, len].tr("\r", '').chomp
end
end
end
uuidtools-2.1.4/lib/uuidtools/ 0000755 0000041 0000041 00000000000 12153751615 016400 5 ustar www-data www-data uuidtools-2.1.4/lib/uuidtools/version.rb 0000644 0000041 0000041 00000001602 12153751615 020411 0 ustar www-data www-data # encoding:utf-8
#--
# Copyright (C) 2005-2012 Bob Aman
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#++
# Used to prevent the class/module from being loaded more than once
unless defined? UUIDTools::VERSION
module UUIDTools
module VERSION #:nodoc:
MAJOR = 2
MINOR = 1
TINY = 4
STRING = [MAJOR, MINOR, TINY].join('.')
end
end
end
uuidtools-2.1.4/lib/uuidtools.rb 0000644 0000041 0000041 00000053670 12153751615 016740 0 ustar www-data www-data # encoding:utf-8
#--
# Copyright (C) 2005-2012 Bob Aman
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#++
$:.unshift(File.dirname(__FILE__))
require 'uri'
require 'time'
require 'thread'
require 'digest/sha1'
require 'digest/md5'
require 'uuidtools/version'
begin
require 'securerandom'
rescue LoadError
require File.join(File.dirname(__FILE__), 'compat', 'securerandom')
end
module UUIDTools
##
# UUIDTools was designed to be a simple library for generating any
# of the various types of UUIDs. It conforms to RFC 4122 whenever
# possible.
#
# @example
# UUID.md5_create(UUID_DNS_NAMESPACE, "www.widgets.com")
# # => #
# UUID.sha1_create(UUID_DNS_NAMESPACE, "www.widgets.com")
# # => #
# UUID.timestamp_create
# # => #
# UUID.random_create
# # => #
class UUID
include Comparable
##
# @api private
@@last_timestamp = nil
##
# @api private
@@last_node_id = nil
##
# @api private
@@last_clock_sequence = nil
##
# @api private
@@state_file = nil
##
# @api private
@@mutex = Mutex.new
##
# Creates a new UUID structure from its component values.
# @see UUID.md5_create
# @see UUID.sha1_create
# @see UUID.timestamp_create
# @see UUID.random_create
# @api private
def initialize(time_low, time_mid, time_hi_and_version,
clock_seq_hi_and_reserved, clock_seq_low, nodes)
unless time_low >= 0 && time_low < 4294967296
raise ArgumentError,
"Expected unsigned 32-bit number for time_low, got #{time_low}."
end
unless time_mid >= 0 && time_mid < 65536
raise ArgumentError,
"Expected unsigned 16-bit number for time_mid, got #{time_mid}."
end
unless time_hi_and_version >= 0 && time_hi_and_version < 65536
raise ArgumentError,
"Expected unsigned 16-bit number for time_hi_and_version, " +
"got #{time_hi_and_version}."
end
unless clock_seq_hi_and_reserved >= 0 && clock_seq_hi_and_reserved < 256
raise ArgumentError,
"Expected unsigned 8-bit number for clock_seq_hi_and_reserved, " +
"got #{clock_seq_hi_and_reserved}."
end
unless clock_seq_low >= 0 && clock_seq_low < 256
raise ArgumentError,
"Expected unsigned 8-bit number for clock_seq_low, " +
"got #{clock_seq_low}."
end
unless nodes.kind_of?(Enumerable)
raise TypeError,
"Expected Enumerable, got #{nodes.class.name}."
end
unless nodes.size == 6
raise ArgumentError,
"Expected nodes to have size of 6."
end
for node in nodes
unless node >= 0 && node < 256
raise ArgumentError,
"Expected unsigned 8-bit number for each node, " +
"got #{node}."
end
end
@time_low = time_low
@time_mid = time_mid
@time_hi_and_version = time_hi_and_version
@clock_seq_hi_and_reserved = clock_seq_hi_and_reserved
@clock_seq_low = clock_seq_low
@nodes = nodes
end
##
# Returns the value of attribute `time_low`
attr_accessor :time_low
##
# Returns the value of attribute `time_mid`
attr_accessor :time_mid
##
# Returns the value of attribute `time_hi_and_version`
attr_accessor :time_hi_and_version
##
# Returns the value of attribute `clock_seq_hi_and_reserved`
attr_accessor :clock_seq_hi_and_reserved
##
# Returns the value of attribute `clock_seq_low`
attr_accessor :clock_seq_low
##
# Returns the value of attribute `nodes`
attr_accessor :nodes
##
# Parses a UUID from a string.
def self.parse(uuid_string)
unless uuid_string.kind_of? String
raise TypeError,
"Expected String, got #{uuid_string.class.name} instead."
end
uuid_components = uuid_string.downcase.scan(
Regexp.new("^([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-" +
"([0-9a-f]{2})([0-9a-f]{2})-([0-9a-f]{12})$")).first
raise ArgumentError, "Invalid UUID format." if uuid_components.nil?
time_low = uuid_components[0].to_i(16)
time_mid = uuid_components[1].to_i(16)
time_hi_and_version = uuid_components[2].to_i(16)
clock_seq_hi_and_reserved = uuid_components[3].to_i(16)
clock_seq_low = uuid_components[4].to_i(16)
nodes = []
for i in 0..5
nodes << uuid_components[5][(i * 2)..(i * 2) + 1].to_i(16)
end
return self.new(time_low, time_mid, time_hi_and_version,
clock_seq_hi_and_reserved, clock_seq_low, nodes)
end
##
# Parses a UUID from a raw byte string.
def self.parse_raw(raw_string)
unless raw_string.kind_of? String
raise TypeError,
"Expected String, got #{raw_string.class.name} instead."
end
integer = self.convert_byte_string_to_int(raw_string)
time_low = (integer >> 96) & 0xFFFFFFFF
time_mid = (integer >> 80) & 0xFFFF
time_hi_and_version = (integer >> 64) & 0xFFFF
clock_seq_hi_and_reserved = (integer >> 56) & 0xFF
clock_seq_low = (integer >> 48) & 0xFF
nodes = []
for i in 0..5
nodes << ((integer >> (40 - (i * 8))) & 0xFF)
end
return self.new(time_low, time_mid, time_hi_and_version,
clock_seq_hi_and_reserved, clock_seq_low, nodes)
end
##
# Parses a UUID from an Integer.
def self.parse_int(uuid_int)
unless uuid_int.kind_of?(Integer)
raise ArgumentError,
"Expected Integer, got #{uuid_int.class.name} instead."
end
return self.parse_raw(self.convert_int_to_byte_string(uuid_int, 16))
end
##
# Parse a UUID from a hexdigest String.
def self.parse_hexdigest(uuid_hexdigest)
unless uuid_hexdigest.kind_of?(String)
raise ArgumentError,
"Expected String, got #{uuid_hexdigest.class.name} instead."
end
return self.parse_int(uuid_hexdigest.to_i(16))
end
##
# Creates a UUID from a random value.
def self.random_create()
new_uuid = self.parse_raw(SecureRandom.random_bytes(16))
new_uuid.time_hi_and_version &= 0x0FFF
new_uuid.time_hi_and_version |= (4 << 12)
new_uuid.clock_seq_hi_and_reserved &= 0x3F
new_uuid.clock_seq_hi_and_reserved |= 0x80
return new_uuid
end
##
# Creates a UUID from a timestamp.
def self.timestamp_create(timestamp=nil)
# We need a lock here to prevent two threads from ever
# getting the same timestamp.
@@mutex.synchronize do
# Always use GMT to generate UUIDs.
if timestamp.nil?
gmt_timestamp = Time.now.gmtime
else
gmt_timestamp = timestamp.gmtime
end
# Convert to 100 nanosecond blocks
gmt_timestamp_100_nanoseconds = (gmt_timestamp.tv_sec * 10000000) +
(gmt_timestamp.tv_usec * 10) + 0x01B21DD213814000
mac_address = self.mac_address
node_id = 0
if mac_address != nil
nodes = mac_address.split(":").collect do |octet|
octet.to_i(16)
end
else
nodes = SecureRandom.random_bytes(6).unpack("C*")
nodes[0] |= 0b00000001
end
for i in 0..5
node_id += (nodes[i] << (40 - (i * 8)))
end
clock_sequence = @@last_clock_sequence
if clock_sequence.nil?
clock_sequence = self.convert_byte_string_to_int(
SecureRandom.random_bytes(16)
)
end
if @@last_node_id != nil && @@last_node_id != node_id
# The node id has changed. Change the clock id.
clock_sequence = self.convert_byte_string_to_int(
SecureRandom.random_bytes(16)
)
elsif @@last_timestamp != nil &&
gmt_timestamp_100_nanoseconds <= @@last_timestamp
clock_sequence = clock_sequence + 1
end
@@last_timestamp = gmt_timestamp_100_nanoseconds
@@last_node_id = node_id
@@last_clock_sequence = clock_sequence
time_low = gmt_timestamp_100_nanoseconds & 0xFFFFFFFF
time_mid = ((gmt_timestamp_100_nanoseconds >> 32) & 0xFFFF)
time_hi_and_version = ((gmt_timestamp_100_nanoseconds >> 48) & 0x0FFF)
time_hi_and_version |= (1 << 12)
clock_seq_low = clock_sequence & 0xFF;
clock_seq_hi_and_reserved = (clock_sequence & 0x3F00) >> 8
clock_seq_hi_and_reserved |= 0x80
return self.new(time_low, time_mid, time_hi_and_version,
clock_seq_hi_and_reserved, clock_seq_low, nodes)
end
end
##
# Creates a UUID using the MD5 hash. (Version 3)
def self.md5_create(namespace, name)
return self.create_from_hash(Digest::MD5, namespace, name)
end
##
# Creates a UUID using the SHA1 hash. (Version 5)
def self.sha1_create(namespace, name)
return self.create_from_hash(Digest::SHA1, namespace, name)
end
##
# This method applies only to version 1 UUIDs.
# Checks if the node ID was generated from a random number
# or from an IEEE 802 address (MAC address).
# Always returns false for UUIDs that aren't version 1.
# This should not be confused with version 4 UUIDs where
# more than just the node id is random.
def random_node_id?
return false if self.version != 1
return ((self.nodes.first & 0x01) == 1)
end
##
# Returns true if this UUID is the
# nil UUID (00000000-0000-0000-0000-000000000000).
def nil_uuid?
return false if self.time_low != 0
return false if self.time_mid != 0
return false if self.time_hi_and_version != 0
return false if self.clock_seq_hi_and_reserved != 0
return false if self.clock_seq_low != 0
self.nodes.each do |node|
return false if node != 0
end
return true
end
##
# Returns the UUID version type.
# Possible values:
# 1 - Time-based with unique or random host identifier
# 2 - DCE Security version (with POSIX UIDs)
# 3 - Name-based (MD5 hash)
# 4 - Random
# 5 - Name-based (SHA-1 hash)
def version
return (time_hi_and_version >> 12)
end
##
# Returns the UUID variant.
# Possible values:
# 0b000 - Reserved, NCS backward compatibility.
# 0b100 - The variant specified in this document.
# 0b110 - Reserved, Microsoft Corporation backward compatibility.
# 0b111 - Reserved for future definition.
def variant
variant_raw = (clock_seq_hi_and_reserved >> 5)
result = nil
if (variant_raw >> 2) == 0
result = 0x000
elsif (variant_raw >> 1) == 2
result = 0x100
else
result = variant_raw
end
return (result >> 6)
end
##
# Returns true if this UUID is valid.
def valid?
if [0b000, 0b100, 0b110, 0b111].include?(self.variant) &&
(1..5).include?(self.version)
return true
else
return false
end
end
##
# Returns the IEEE 802 address used to generate this UUID or
# nil if a MAC address was not used.
def mac_address
return nil if self.version != 1
return nil if self.random_node_id?
return (self.nodes.collect do |node|
sprintf("%2.2x", node)
end).join(":")
end
##
# Returns the timestamp used to generate this UUID
def timestamp
return nil if self.version != 1
gmt_timestamp_100_nanoseconds = 0
gmt_timestamp_100_nanoseconds +=
((self.time_hi_and_version & 0x0FFF) << 48)
gmt_timestamp_100_nanoseconds += (self.time_mid << 32)
gmt_timestamp_100_nanoseconds += self.time_low
return Time.at(
(gmt_timestamp_100_nanoseconds - 0x01B21DD213814000) / 10000000.0)
end
##
# Compares two UUIDs lexically
def <=>(other_uuid)
check = self.time_low <=> other_uuid.time_low
return check if check != 0
check = self.time_mid <=> other_uuid.time_mid
return check if check != 0
check = self.time_hi_and_version <=> other_uuid.time_hi_and_version
return check if check != 0
check = self.clock_seq_hi_and_reserved <=>
other_uuid.clock_seq_hi_and_reserved
return check if check != 0
check = self.clock_seq_low <=> other_uuid.clock_seq_low
return check if check != 0
for i in 0..5
if (self.nodes[i] < other_uuid.nodes[i])
return -1
end
if (self.nodes[i] > other_uuid.nodes[i])
return 1
end
end
return 0
end
##
# Returns a representation of the object's state
def inspect
return "#"
end
##
# Returns the hex digest of the UUID object.
def hexdigest
(self.frozen? ?
generate_hexdigest : (@hexdigest ||= generate_hexdigest)
).dup
end
##
# Returns the raw bytes that represent this UUID.
def raw
(self.frozen? ? generate_raw : (@raw ||= generate_raw)).dup
end
##
# Returns a string representation for this UUID.
def to_s
(self.frozen? ? generate_s : (@string ||= generate_s)).dup
end
alias_method :to_str, :to_s
##
# Returns an integer representation for this UUID.
def to_i
self.frozen? ? generate_i : (@integer ||= generate_i)
end
##
# Returns a URI string for this UUID.
def to_uri
return "urn:uuid:#{self.to_s}"
end
##
# Returns an integer hash value.
def hash
self.frozen? ? generate_hash : (@hash ||= generate_hash)
end
protected
##
# Generates the hex digest of the UUID object.
#
# @api private
def generate_hexdigest
return self.to_i.to_s(16).rjust(32, "0")
end
# Generates an integer hash value.
#
# @api private
def generate_hash
return self.to_i % 0x3fffffff
end
##
# Generates an integer representation for this UUID.
#
# @api private
def generate_i
return (begin
bytes = (time_low << 96) + (time_mid << 80) +
(time_hi_and_version << 64) + (clock_seq_hi_and_reserved << 56) +
(clock_seq_low << 48)
for i in 0..5
bytes += (nodes[i] << (40 - (i * 8)))
end
bytes
end)
end
##
# Generates a string representation for this UUID.
#
# @api private
def generate_s
result = sprintf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", @time_low, @time_mid,
@time_hi_and_version, @clock_seq_hi_and_reserved, @clock_seq_low);
for i in 0..5
result << sprintf("%2.2x", @nodes[i])
end
return result.downcase
end
##
# Generates the raw bytes that represent this UUID.
#
# @api private
def generate_raw
return self.class.convert_int_to_byte_string(self.to_i, 16)
end
public
##
# Returns true if this UUID is exactly equal to the other UUID.
def eql?(other)
return self == other
end
#
# Determine what OS we're running on. Helps decide how to find the MAC
#
def self.os_class
require 'rbconfig'
os_platform = RbConfig::CONFIG['target_os']
os_class = nil
if (os_platform =~ /win/i && !(os_platform =~ /darwin/i)) ||
os_platform =~ /w32/i
os_class = :windows
elsif os_platform =~ /solaris/i
os_class = :solaris
elsif os_platform =~ /netbsd/i
os_class = :netbsd
elsif os_platform =~ /openbsd/i
os_class = :openbsd
end
end
# making these class variables helps with testing
@ifconfig_command = "ifconfig"
@ifconfig_path_default = "/sbin/ifconfig"
@ip_command = "ip"
@ip_path_default = "/sbin/ip"
class << self
attr_accessor :ifconfig_command, :ifconfig_path_default
attr_accessor :ip_command, :ip_path_default
end
#
# Find the path of the ifconfig(8) command if it is present
#
def self.ifconfig_path
path = `which #{UUID.ifconfig_command} 2>/dev/null`.strip
path = UUID.ifconfig_path_default if (path == "" && File.exist?(UUID.ifconfig_path_default))
return (path === "" ? nil : path)
end
#
# Find the path of the ip(8) command if it is present
#
def self.ip_path
path = `which #{UUID.ip_command} 2>/dev/null`.strip
path = UUID.ip_path_default if (path == "" && File.exist?(UUID.ip_path_default))
return (path === "" ? nil : path)
end
#
# Call the ifconfig or ip command that is found
#
def self.ifconfig(all=nil)
# find the path of the ifconfig command
ifconfig_path = UUID.ifconfig_path
# if it does not exist, try the ip command
if ifconfig_path == nil
ifconfig_path = UUID.ip_path
# all makes no sense when using ip(1)
all = nil
end
all_switch = all == nil ? "" : "-a"
return `#{ifconfig_path} #{all_switch}` if not ifconfig_path == nil
end
# Match and return the first Mac address found
def self.first_mac(instring)
mac_regexps = [
Regexp.new("address:? (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"),
Regexp.new("addr:? (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"),
Regexp.new("ether:? (#{(["[0-9a-fA-F]{1,2}"] * 6).join(":")})"),
Regexp.new("HWaddr:? (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"),
Regexp.new("link/ether? (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"),
Regexp.new("(#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"),
Regexp.new("(#{(["[0-9a-fA-F]{2}"] * 6).join("-")})")
]
parse_mac = lambda do |output|
(mac_regexps.map do |regexp|
result = output[regexp, 1]
result.downcase.gsub(/-/, ":") if result != nil
end).compact.first
end
mac = parse_mac.call(instring)
# expand octets that were compressed (solaris)
mac.split(':').map { |c| (c.length == 1 ? "0#{c}" : c)}.join(':')
end
##
# Returns the MAC address of the current computer's network card.
# Returns nil if a MAC address could not be found.
def self.mac_address
if !defined?(@@mac_address)
require 'rbconfig'
os_class = UUID.os_class
if os_class == :windows
begin
@@mac_address = UUID.first_mac `ipconfig /all`
rescue
end
else # linux, bsd, macos, solaris
@@mac_address = UUID.first_mac(UUID.ifconfig(:all))
end
if @@mac_address != nil
if @@mac_address.respond_to?(:to_str)
@@mac_address = @@mac_address.to_str
else
@@mac_address = @@mac_address.to_s
end
@@mac_address.downcase!
@@mac_address.strip!
end
# Verify that the MAC address is in the right format.
# Nil it out if it isn't.
unless @@mac_address.respond_to?(:scan) &&
@@mac_address.scan(/#{(["[0-9a-f]{2}"] * 6).join(":")}/)
@@mac_address = nil
end
end
return @@mac_address
end
##
# Allows users to set the MAC address manually in cases where the MAC
# address cannot be obtained programatically.
def self.mac_address=(new_mac_address)
@@mac_address = new_mac_address
end
# The following methods are not part of the public API,
# and generally should not be called directly.
##
# Creates a new UUID from a SHA1 or MD5 hash
#
# @api private
def self.create_from_hash(hash_class, namespace, name)
if hash_class == Digest::MD5
version = 3
elsif hash_class == Digest::SHA1
version = 5
else
raise ArgumentError,
"Expected Digest::SHA1 or Digest::MD5, got #{hash_class.name}."
end
hash = hash_class.new
hash.update(namespace.raw)
hash.update(name)
hash_string = hash.to_s[0..31]
new_uuid = self.parse("#{hash_string[0..7]}-#{hash_string[8..11]}-" +
"#{hash_string[12..15]}-#{hash_string[16..19]}-#{hash_string[20..31]}")
new_uuid.time_hi_and_version &= 0x0FFF
new_uuid.time_hi_and_version |= (version << 12)
new_uuid.clock_seq_hi_and_reserved &= 0x3F
new_uuid.clock_seq_hi_and_reserved |= 0x80
return new_uuid
end
##
# @api private
def self.convert_int_to_byte_string(integer, size)
byte_string = ""
if byte_string.respond_to?(:force_encoding)
byte_string.force_encoding(Encoding::ASCII_8BIT)
end
for i in 0..(size - 1)
byte_string << ((integer >> (((size - 1) - i) * 8)) & 0xFF)
end
return byte_string
end
##
# @api private
def self.convert_byte_string_to_int(byte_string)
if byte_string.respond_to?(:force_encoding)
byte_string.force_encoding(Encoding::ASCII_8BIT)
end
integer = 0
size = byte_string.size
for i in 0..(size - 1)
ordinal = (byte_string[i].respond_to?(:ord) ?
byte_string[i].ord : byte_string[i])
integer += (ordinal << (((size - 1) - i) * 8))
end
return integer
end
end
##
# Constant that represents the DNS namespace.
UUID_DNS_NAMESPACE = UUID.parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
##
# Constant that represents the URL namespace.
UUID_URL_NAMESPACE = UUID.parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
##
# Constant that represents the OID namespace.
UUID_OID_NAMESPACE = UUID.parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
##
# Constant that represents the X500 namespace.
UUID_X500_NAMESPACE = UUID.parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
end