device-identifier 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -7,11 +7,47 @@ Rationale:
7
7
  - Hard-phones have an Ethernet MAC address.
8
8
  - Soft-phones don't. They have/need some sort of identification string
9
9
  (any sequence of bytes).
10
- - Both are device identifiers, with the MAC address being a sub-class.
10
+ - Soft-phones may use UUIDs as identifiers.
11
+ - All of them are device identifiers, with the MAC address resp. UUID being sub-classes.
11
12
 
12
13
  Author: Philipp Kempgen, [http://kempgen.net](http://kempgen.net)
13
14
 
14
15
 
16
+ ## Usage
17
+
18
+ require 'dev-id'
19
+
20
+ m = DevId::MacAddress.from_hex ""
21
+ m.valid? # => false
22
+
23
+ m = DevId::MacAddress.from_hex "001122aabbcc"
24
+ m.valid? # => true
25
+
26
+ m = DevId::MacAddress.from_hex "00:11:22:aa:bb:cc"
27
+ m.valid? # => true
28
+
29
+ m = DevId::MacAddress.from_hex "00-11-22-AA-BB-CC"
30
+ m.valid? # => true
31
+ m.ascii # => "001122aabbcc"
32
+ m.pretty # => "00:11:22:AA:BB:CC"
33
+ m.to_s # => "00:11:22:AA:BB:CC"
34
+ m.pretty({ :sep => '-', :upcase => false })
35
+ # => "00-11-22-aa-bb-cc"
36
+ m.raw # => "\x00\x11\x22\xAA\xBB\xCC"
37
+ m.bytes.to_a # => [0, 17, 34, 170, 187, 204]
38
+ m.bytesize # => 6
39
+ m.to_int # => 73596058572
40
+ m.starts_with? DevId::MacAddressOui.from_hex '00:11:22'
41
+ # => true
42
+ m.starts_with? DevId::MacAddressPartial.from_hex '00:11:22:aa'
43
+ # => true
44
+
45
+ # MacAddress specific:
46
+ m.null? # => false
47
+ m.multicast? # => false
48
+ m.oui_raw # => "\x00\x11\x22"
49
+
50
+
15
51
  ## Inheritance
16
52
 
17
53
  The class inheritance is as follows:
@@ -31,6 +67,10 @@ The class inheritance is as follows:
31
67
  - **`MacAddress`**
32
68
 
33
69
  Model for a MAC address.
70
+
71
+ - **`DeviceUuid`**
72
+
73
+ Model for a device identifier UUID.
34
74
 
35
75
  - **`MacAddressPartial`**
36
76
 
@@ -43,9 +83,9 @@ The class inheritance is as follows:
43
83
 
44
84
  ## Device identifiers
45
85
 
46
- There are 2 kinds of device identifiers: the generic `DeviceIdentifier` and the more specific `MacAddress`.
86
+ There are 3 kinds of device identifiers: the generic `DeviceIdentifier`, and the more specific `MacAddress` and `DeviceUuid`.
47
87
 
48
- Both support the methods in following (amongst others):
88
+ All of them support the methods in following (amongst others):
49
89
 
50
90
  - `bytes`
51
91
 
@@ -101,6 +141,15 @@ Instance methods:
101
141
 
102
142
  The number of bytes.
103
143
 
144
+ - `getbyte( index )`
145
+
146
+ Returns one of the raw bytes as an integer.
147
+
148
+ - `byteslice( from, len = nil )`
149
+
150
+ Returns a slice (sub-string) of the raw bytes.
151
+ `from` can be an `Integer` or a `Range` – in the latter case `len` must not be specified.
152
+
104
153
  - `length`
105
154
 
106
155
  Alias for `bytesize`.
@@ -161,7 +210,7 @@ Instance methods:
161
210
 
162
211
  - `null?`
163
212
 
164
- If it's a null address (all 6 bytes \x00: 00:00:00:00:00:00).
213
+ If it's a null address (all 6 bytes `\x00`: `00:00:00:00:00:00`).
165
214
 
166
215
  - `pretty( opts = nil )`
167
216
 
@@ -181,6 +230,38 @@ Instance methods:
181
230
  The OUI (vendor) part (first 3 bytes) in raw format.
182
231
 
183
232
 
233
+ ### `DeviceUuid`
234
+
235
+ **Inheritance**:
236
+ `Base` >
237
+ `BinaryAddress` >
238
+ `DeviceIdentifier` >
239
+ `DeviceUuid`
240
+
241
+ Model for a device UUID.
242
+
243
+ Instance methods:
244
+
245
+ - `null?`
246
+
247
+ If it's a null address (all bytes `\x00`: `00000000-0000-0000-0000-000000000000`).
248
+
249
+ - `pretty( opts = nil )`
250
+
251
+ A pretty ASCII representation (hex format).
252
+
253
+ Default options are:
254
+
255
+ {
256
+ :sep => '-', # separator, typically "-"
257
+ :upcase => false, # use uppercase?
258
+ }
259
+
260
+ If the default options are used this method returns the canonical UUID representation.
261
+
262
+ - A couple of UUID specific methods (named `uuid`...).
263
+
264
+
184
265
  ### `MacAddressPartial`
185
266
 
186
267
  **Inheritance**:
@@ -203,4 +284,3 @@ Model for the OUI (vendor) part of a MAC address.
203
284
 
204
285
  Validates that the raw address has a length of 3 bytes.
205
286
 
206
-
@@ -6,4 +6,5 @@ require 'dev-id/base'
6
6
  require 'dev-id/binary_address'
7
7
  require 'dev-id/device_identifier'
8
8
  require 'dev-id/mac_address'
9
+ require 'dev-id/device_uuid'
9
10
 
@@ -1,5 +1,21 @@
1
- require 'dev-id'
2
- require 'active_model'
1
+ #require 'dev-id' # for DevId
2
+ require 'active_model' # for ActiveModel (from the "activemodel" gem)
3
+ #if ! ::ActiveModel.const_defined?( :MassAssignmentSecurity )
4
+ # # ActiveModel::MassAssignmentSecurity is no longer part of the
5
+ # # "activemodel" gem as of version 4, but went into the
6
+ # # "protected_attributes" gem.
7
+ # begin
8
+ # require 'protected_attributes'
9
+ # rescue ::LoadError => e
10
+ # STDERR.puts "------------------------------------------------------------"
11
+ # STDERR.puts "#{e.message} (#{e.class.name})"
12
+ # STDERR.puts (e.backtrace || []).reject{|l| l.match( %r{ /lib/rake/ }x )}.map{|l| " #{l}"}
13
+ # STDERR.puts "------------------------------------------------------------"
14
+ # STDERR.puts "For ActiveModel >= 4 please add the \"protected_attributes\" gem to your bundle."
15
+ # STDERR.puts " ActiveModel version: #{::ActiveModel::VERSION::STRING}"
16
+ # STDERR.puts "------------------------------------------------------------"
17
+ # end
18
+ #end
3
19
 
4
20
  module ::DevId
5
21
 
@@ -7,7 +23,13 @@ module ::DevId
7
23
  class BasicActiveModel
8
24
  extend ::ActiveModel::Naming
9
25
  include ::ActiveModel::Validations
10
- include ::ActiveModel::MassAssignmentSecurity
26
+
27
+ if ::ActiveModel::VERSION::MAJOR <= 3
28
+ include ::ActiveModel::MassAssignmentSecurity
29
+ else
30
+ include ::ActiveModel::ForbiddenAttributesProtection
31
+ end
32
+
11
33
  include ::ActiveModel::Conversion
12
34
  # extend ::ActiveModel::Callbacks
13
35
 
@@ -24,7 +46,11 @@ module ::DevId
24
46
  attributes = new_attributes.stringify_keys
25
47
 
26
48
  unless options[:without_protection]
27
- attributes = sanitize_for_mass_assignment( attributes, options[:as] || :default )
49
+ if ::ActiveModel::VERSION::MAJOR <= 3
50
+ attributes = sanitize_for_mass_assignment( attributes, options[:as] || :default )
51
+ else
52
+ attributes = sanitize_for_mass_assignment( attributes )
53
+ end
28
54
  end
29
55
 
30
56
  attributes.each { |k, v|
@@ -36,6 +36,20 @@ module ::DevId
36
36
  end
37
37
  alias :length :bytesize
38
38
 
39
+ def byteslice( from, len=nil )
40
+ return nil if ! raw
41
+ if len
42
+ raw.byteslice( from, len )
43
+ else
44
+ raw.byteslice( from ) # from can be a Fixnum or a Range
45
+ end
46
+ end
47
+ alias :'[]' :'byteslice'
48
+
49
+ def getbyte( idx )
50
+ (raw || '').getbyte( idx )
51
+ end
52
+
39
53
  # Construct a new instance from a raw string.
40
54
  #
41
55
  def self.from_raw( str )
@@ -129,8 +143,6 @@ module ::DevId
129
143
  return ! (self =~ other)
130
144
  end
131
145
 
132
- #TODO getbyte, [], byteslice
133
-
134
146
  end
135
147
  end
136
148
 
@@ -0,0 +1,237 @@
1
+ require 'dev-id/device_identifier'
2
+ require 'dev-id/binary_address'
3
+ require 'dev-id/mac_address'
4
+
5
+ module ::DevId
6
+
7
+ # Model for a device UUID.
8
+ #
9
+ # 16 bytes.
10
+ #
11
+ class DeviceUuid < DeviceIdentifier
12
+
13
+ validates_length_of :raw, :is => 16
14
+
15
+ # Default options for conversion to ASCII in the `pretty`
16
+ # method.
17
+ DEFAULT_TO_PRETTY_OPTS = {
18
+ :sep => '-', # typically "-"
19
+ :upcase => false,
20
+ }.freeze
21
+
22
+ UUID_VARIANT_NCS = :ncs # 0b0xx, reserved, NCS backward compatibility (also used for the nil UUID)
23
+ UUID_VARIANT_RFC_4122 = :rfc4122 # 0b10x, the variant specified by RFC 4122
24
+ UUID_VARIANT_MICROSOFT = :microsoft # 0b110, reserved, Microsoft backward compatibility
25
+ UUID_VARIANT_FUTURE = :future # 0b111, reserved for future definition
26
+
27
+ # Whether the device UUID is the "nil"/"null" address (16
28
+ # NULL bytes).
29
+ #
30
+ def null?
31
+ return nil if ! valid?
32
+ return raw == (?\0.force_encoding( ::Encoding::ASCII_8BIT ) * 16)
33
+ end
34
+
35
+ # Pretty ASCII representation in UUID format (8-4-4-4-12).
36
+ #
37
+ def pretty( opts = nil )
38
+ return nil if ! valid?
39
+ opts = DEFAULT_TO_PRETTY_OPTS.merge( opts || {} )
40
+ #return ascii( opts )
41
+ #return ::Kernel.sprintf( '%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x', * self.bytes )
42
+ uuid_str = raw.unpack( 'H8H4H4H4H12' ).join( opts[:sep] )
43
+ uuid_str = uuid_str.upcase if opts[:upcase]
44
+ return uuid_str
45
+ end
46
+
47
+ # Pretty ASCII representation in UUID format (8-4-4-4-12).
48
+ #
49
+ # This is the same as .pretty with default options
50
+ # ({ :sep => '-', :upcase => false }) but slightly faster.
51
+ #
52
+ def uuid_str
53
+ return nil if ! valid?
54
+ return raw.unpack( 'H8H4H4H4H12' ).join( '-' )
55
+ end
56
+
57
+ # `to_s` is an alias for `pretty`.
58
+ #
59
+ def to_s( opts = nil )
60
+ pretty( opts )
61
+ end
62
+
63
+ def require_uuid_tools
64
+ require 'uuidtools' unless ::Module.const_defined?( :UUIDTools )
65
+ end
66
+ private :require_uuid_tools
67
+
68
+ def uuid
69
+ if @uuid == nil
70
+ if ! valid?
71
+ @uuid = false
72
+ else
73
+ require_uuid_tools()
74
+ @uuid = ::UUIDTools::UUID.parse_raw( raw )
75
+ end
76
+ end
77
+ @uuid
78
+ end
79
+
80
+ # Returns the UUID type (a.k.a. variant).
81
+ #
82
+ # Possible values:
83
+ # - 0b000: reserved, NCS backward compatibility (also used for the nil UUID)
84
+ # - 0b001: ", mapped to 0b000
85
+ # - 0b010: ", mapped to 0b000
86
+ # - 0b011: ", mapped to 0b000
87
+ # - 0b100: the variant specified by RFC 4122
88
+ # - 0b101: ", mapped to 0b100
89
+ # - 0b110: reserved, Microsoft backward compatibility
90
+ # - 0b111: reserved for future definition
91
+ #
92
+ def uuid_variant
93
+ #return nil if ! uuid
94
+ #return uuid.variant
95
+
96
+ return nil if ! valid?
97
+ var_raw = raw.getbyte(8) >> 5
98
+ ret = nil
99
+ if (var_raw >> 2) == 0
100
+ ret = 0x000
101
+ elsif (var_raw >> 1) == 2
102
+ ret = 0x100
103
+ else
104
+ ret = var_raw
105
+ end
106
+ return (ret >> 6)
107
+ end
108
+ alias :uuid_type :uuid_variant
109
+
110
+ def uuid_variant_name
111
+ v = uuid_variant
112
+ {
113
+ 0b100 => UUID_VARIANT_RFC_4122,
114
+ 0b000 => UUID_VARIANT_NCS,
115
+ 0b110 => UUID_VARIANT_MICROSOFT,
116
+ 0b111 => UUID_VARIANT_FUTURE,
117
+ }[ v ]
118
+ end
119
+ alias :uuid_type_name :uuid_variant_name
120
+
121
+ def uuid_variant_ncs?
122
+ v = uuid_variant
123
+ v ? (v == 0b000) : nil
124
+ end
125
+ alias :'uuid_type_ncs?' :'uuid_variant_ncs?'
126
+
127
+ def uuid_variant_rfc4122?
128
+ v = uuid_variant
129
+ v ? (v == 0b100) : nil
130
+ end
131
+ alias :'uuid_type_rfc4122?' :'uuid_variant_rfc4122?'
132
+
133
+ def uuid_variant_microsoft?
134
+ v = uuid_variant
135
+ v ? (v == 0b110) : nil
136
+ end
137
+ alias :'uuid_type_microsoft?' :'uuid_variant_microsoft?'
138
+
139
+ def uuid_variant_future?
140
+ v = uuid_variant
141
+ v ? (v == 0b111) : nil
142
+ end
143
+ alias :'uuid_type_future?' :'uuid_variant_future?'
144
+
145
+ # Returns the UUID sub-type (a.k.a. version).
146
+ #
147
+ # Possible values:
148
+ # - 1: time-based with unique or random host identifier
149
+ # - 2: DCE Security version, with embedded POSIX UIDs
150
+ # - 3: name-based (uses MD5 hash)
151
+ # - 4: random
152
+ # - 5: name-based (uses SHA-1 hash)
153
+ #
154
+ def uuid_version
155
+ #return nil if ! uuid
156
+ #return nil if ! uuid_variant_rfc4122?
157
+ #return uuid.version
158
+
159
+ return nil if ! valid?
160
+ return nil if ! uuid_variant_rfc4122?
161
+ #b6 = self.bytes.to_a[ 6 ]
162
+ b6 = (raw || '').getbyte( 6 )
163
+ return nil if ! b6
164
+ #b6.div( 16 ) # return value
165
+ b6 >> 4 # return value
166
+ end
167
+ alias :uuid_sub_type :uuid_version
168
+
169
+ # Returns the MAC address (lowercase, ":"-separated) used to
170
+ # generate this UUID, or nil if a MAC address was not used.
171
+ # Applies only to version 1 UUIDs with a given (i.e.
172
+ # non-random) node ID.
173
+ #
174
+ def uuid_mac_addr
175
+ #return nil if ! uuid
176
+ #return nil if ! uuid_variant_rfc4122?
177
+ #return uuid.mac_address.upcase
178
+
179
+ return nil if ! valid?
180
+ return nil if ! uuid_variant_rfc4122?
181
+ return nil if uuid_version != 1
182
+ return nil if uuid_random_node_id?
183
+ opts = ::DevId::MacAddress::DEFAULT_TO_PRETTY_OPTS
184
+ return self.byteslice( 10, 6 ).bytes.map{ |b| (opts[:upcase] ? '%02X' : '%02x') % [b] }.join( opts[:sep] )
185
+ end
186
+
187
+ # This method applies only to version 1 UUIDs. Checks if the
188
+ # node ID was generated from a random number or from a MAC
189
+ # address. Always returns `false` for UUIDs that aren't
190
+ # version 1. This should not be confused with version 4
191
+ # UUIDs where more than just the node ID is random.
192
+ #
193
+ def uuid_random_node_id?
194
+ #return nil if ! uuid
195
+ #return nil if ! uuid_variant_rfc4122?
196
+ #return uuid.random_node_id?
197
+
198
+ return nil if ! valid?
199
+ return nil if ! uuid_variant_rfc4122?
200
+ return false if uuid_version != 1
201
+ return ((raw.getbyte( 10 ) & 0x01) == 1)
202
+ end
203
+
204
+ # This method applies only to version 1 UUIDs. Returns the
205
+ # timestamp used to generate this UUID.
206
+ #
207
+ # @return `Time` instance timestamp
208
+ #
209
+ def uuid_timestamp
210
+ return nil if ! uuid
211
+ return nil if ! uuid_variant_rfc4122?
212
+ #return uuid.timestamp
213
+
214
+ return nil if ! valid?
215
+ return nil if ! uuid_variant_rfc4122?
216
+ return nil if uuid_version != 1
217
+
218
+ tlmh = raw.unpack('Nnn') # time_low, time_mid, time_hi_and_version
219
+ t_utc_100_ns = tlmh[0] + (tlmh[1] << 32) + ((tlmh[2] & 0x0FFF) << 48)
220
+
221
+ # Subtract offset between UUID time and Unix time.
222
+ # UUID UTC base time is October 15, 1582 (1582-10-15 00:00:00 Z).
223
+ # Unix UTC base time is January 1, 1970 (1970-01-01 00:00:00 Z).
224
+ return ::Time.at(
225
+ (t_utc_100_ns - 0x01B21DD213814000) / 10000000.0 )
226
+ end
227
+
228
+ # Returns an URI string ("`urn:uuid:`"...) for this UUID.
229
+ #
230
+ def uuid_to_uri
231
+ uuid ? "urn:uuid:#{self.uuid_str}" : nil
232
+ end
233
+ alias :uuid_to_urn :uuid_to_uri
234
+
235
+ end
236
+ end
237
+
@@ -18,13 +18,21 @@ module ::DevId
18
18
  :upcase => true,
19
19
  }.freeze
20
20
 
21
- # Whether the MAC address is a multicast address.
21
+ # Whether the MAC address is a group address (multicast address).
22
22
  #
23
23
  def multicast?
24
24
  return nil if ! valid?
25
25
  return (raw.getbyte(0).to_i % 2) != 0
26
26
  end
27
27
 
28
+ # Whether the MAC address is a local address (as compared to a global address).
29
+ #
30
+ def local?
31
+ return nil if ! valid?
32
+ #return raw.getbyte(0).to_s(2).rjust(8,'0')[-2] == '1'
33
+ return ((raw.getbyte(0).to_i >> 1) % 2) != 0
34
+ end
35
+
28
36
  # Whether the MAC address is the "null" address (6 NULL
29
37
  # bytes).
30
38
  #
@@ -4,7 +4,7 @@
4
4
  module ::DevId
5
5
 
6
6
  # The version of this Gem.
7
- VERSION = [ 0, 0, 1 ].freeze
7
+ VERSION = [ 0, 0, 2 ].freeze
8
8
 
9
9
  # The version of this Gem as a string.
10
10
  VERSION_STR = VERSION.map(& :to_s).join('.').freeze
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: device-identifier
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,16 +9,70 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-17 00:00:00.000000000 Z
12
+ date: 2013-11-27 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: uuidtools
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 2.1.4
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 2.1.4
14
46
  - !ruby/object:Gem::Dependency
15
47
  name: activemodel
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '3'
54
+ - - <
55
+ - !ruby/object:Gem::Version
56
+ version: '5'
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ! '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '3'
65
+ - - <
66
+ - !ruby/object:Gem::Version
67
+ version: '5'
68
+ - !ruby/object:Gem::Dependency
69
+ name: uuidtools
16
70
  requirement: !ruby/object:Gem::Requirement
17
71
  none: false
18
72
  requirements:
19
73
  - - ~>
20
74
  - !ruby/object:Gem::Version
21
- version: '3.2'
75
+ version: 2.1.4
22
76
  type: :runtime
23
77
  prerelease: false
24
78
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +80,7 @@ dependencies:
26
80
  requirements:
27
81
  - - ~>
28
82
  - !ruby/object:Gem::Version
29
- version: '3.2'
83
+ version: 2.1.4
30
84
  description: Models for device identifiers, e.g. MAC addresses for hardware clients
31
85
  and arbitrary identifier strings for software clients.
32
86
  email:
@@ -37,6 +91,7 @@ files:
37
91
  - lib/dev-id/base.rb
38
92
  - lib/dev-id/binary_address.rb
39
93
  - lib/dev-id/device_identifier.rb
94
+ - lib/dev-id/device_uuid.rb
40
95
  - lib/dev-id/mac_address.rb
41
96
  - lib/dev-id/version.rb
42
97
  - lib/dev-id.rb