packetgen 2.1.2 → 2.1.3
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/README.md +10 -3
- data/bin/pgconsole +25 -28
- data/lib/packetgen/config.rb +47 -31
- data/lib/packetgen/header/arp.rb +1 -2
- data/lib/packetgen/header/asn1_base.rb +4 -0
- data/lib/packetgen/header/dns/question.rb +16 -30
- data/lib/packetgen/header/dot11.rb +73 -8
- data/lib/packetgen/header/dot11/control.rb +11 -1
- data/lib/packetgen/header/dot11/data.rb +14 -0
- data/lib/packetgen/header/dot11/element.rb +2 -0
- data/lib/packetgen/header/dot11/management.rb +43 -0
- data/lib/packetgen/header/dot11/sub_mngt.rb +84 -1
- data/lib/packetgen/header/dot1x.rb +8 -27
- data/lib/packetgen/header/ike.rb +10 -25
- data/lib/packetgen/header/ike/cert.rb +15 -31
- data/lib/packetgen/header/ike/notify.rb +35 -78
- data/lib/packetgen/header/ike/sa.rb +13 -25
- data/lib/packetgen/header/ike/ts.rb +4 -3
- data/lib/packetgen/inspect.rb +6 -4
- data/lib/packetgen/packet.rb +1 -1
- data/lib/packetgen/pcapng/epb.rb +1 -1
- data/lib/packetgen/pcapng/idb.rb +2 -2
- data/lib/packetgen/pcapng/shb.rb +1 -1
- data/lib/packetgen/pcapng/spb.rb +1 -1
- data/lib/packetgen/pcapng/unknown_block.rb +2 -2
- data/lib/packetgen/proto.rb +1 -1
- data/lib/packetgen/types.rb +1 -0
- data/lib/packetgen/types/enum.rb +165 -0
- data/lib/packetgen/types/fields.rb +29 -9
- data/lib/packetgen/types/int.rb +4 -0
- data/lib/packetgen/utils.rb +101 -0
- data/lib/packetgen/utils/arp_spoofer.rb +191 -0
- data/lib/packetgen/version.rb +1 -1
- data/packetgen.gemspec +1 -1
- metadata +7 -4
@@ -9,6 +9,17 @@ module PacketGen
|
|
9
9
|
class Dot11
|
10
10
|
|
11
11
|
# IEEE 802.11 control frame header
|
12
|
+
#
|
13
|
+
# This class make a {Dot11} header with {#type} set to +1+
|
14
|
+
# (control frame).
|
15
|
+
#
|
16
|
+
# A IEEE 802.11 control header consists of:
|
17
|
+
# * a {#frame_ctrl} ({Types::Int16}),
|
18
|
+
# * a {#id}/duration ({Types::Int16le}),
|
19
|
+
# * a {#mac1} ({Eth::MacAddr}).
|
20
|
+
# * sometimes a {#mac2} ({Eth::MacAddr}),
|
21
|
+
# * a {#body} (a {Types::String} or another {Base} class),
|
22
|
+
# * and a Frame check sequence ({#fcs}, of type {Types::Int32le}).
|
12
23
|
# @author Sylvain Daubert
|
13
24
|
class Control < Dot11
|
14
25
|
|
@@ -49,7 +60,6 @@ module PacketGen
|
|
49
60
|
if @applicable_fields.include? :mac2
|
50
61
|
@applicable_fields -= %i(mac2) unless SUBTYPES_WITH_MAC2.include? self.subtype
|
51
62
|
elsif SUBTYPES_WITH_MAC2.include? self.subtype
|
52
|
-
sz = self.sz
|
53
63
|
@applicable_fields[3, 0] = :mac2
|
54
64
|
end
|
55
65
|
end
|
@@ -9,6 +9,20 @@ module PacketGen
|
|
9
9
|
class Dot11
|
10
10
|
|
11
11
|
# IEEE 802.11 data frame header
|
12
|
+
#
|
13
|
+
# This class make a {Dot11} header with {#type} set to +2+
|
14
|
+
# (data frame).
|
15
|
+
#
|
16
|
+
# A IEEE 802.11 data header consists of:
|
17
|
+
# * a {#frame_ctrl} ({Types::Int16}),
|
18
|
+
# * a {#id}/duration ({Types::Int16le}),
|
19
|
+
# * a {#mac2} ({Eth::MacAddr}),
|
20
|
+
# * a {#mac3} ({Eth::MacAddr}),
|
21
|
+
# * a {#sequence_ctrl} ({Types::Int16}),
|
22
|
+
# * sometimes a {#mac4} ({Eth::MacAddr}),
|
23
|
+
# * sometimes a {#qos_ctrl} ({Types::Int16}),
|
24
|
+
# * a {#body} (a {Types::String} or another {Base} class),
|
25
|
+
# * and a Frame check sequence ({#fcs}, of type {Types::Int32le}).
|
12
26
|
# @author Sylvain Daubert
|
13
27
|
class Data < Dot11
|
14
28
|
|
@@ -9,6 +9,33 @@ module PacketGen
|
|
9
9
|
class Dot11
|
10
10
|
|
11
11
|
# IEEE 802.11 management frame header
|
12
|
+
#
|
13
|
+
# This class make a {Dot11} header with {#type} set to +0+
|
14
|
+
# (management frame).
|
15
|
+
#
|
16
|
+
# A IEEE 802.11 management header consists of:
|
17
|
+
# * a {#frame_ctrl} ({Types::Int16}),
|
18
|
+
# * a {#id}/duration ({Types::Int16le}),
|
19
|
+
# * a {#mac1} ({Eth::MacAddr}).
|
20
|
+
# * a {#mac2} ({Eth::MacAddr}),
|
21
|
+
# * a {#mac3} ({Eth::MacAddr}),
|
22
|
+
# * a {#sequence_ctrl} ({Types::Int16}),
|
23
|
+
# * a {#body} (a {Types::String} or another {Base} class),
|
24
|
+
# * and a Frame check sequence ({#fcs}, of type {Types::Int32le}).
|
25
|
+
#
|
26
|
+
# Management frames should be constructed with more headers from
|
27
|
+
# {SubMngt} subclasses.
|
28
|
+
#
|
29
|
+
# By example, build a {DeAuth} frame:
|
30
|
+
# PacketGen.gen('Dot11::Management').add('Dot11::DeAuth')
|
31
|
+
#
|
32
|
+
# Some frames need to have {Element}. By example a {Beacon} frame:
|
33
|
+
# pkt = PacketGen.gen('Dot11::Management', mac1: broadcast, mac2: bssid, mac3: bssid).
|
34
|
+
# add('Dot11::Beacon')
|
35
|
+
# pkt.dot11_beacon.add_elements(type: 'SSID', value: ssid)
|
36
|
+
# pkt.dot11_beacon.add_elements(type: 'Rates', value: "\x82\x84\x8b\x96\x12\x24\x48\x6c")
|
37
|
+
# pkt.dot11_beacon.add_elements(type: 'DSset', value: "\x06")
|
38
|
+
# pkt.dot11_beacon.add_elements(type: 'TIM', value: "\x00\x01\x00\x00")
|
12
39
|
# @author Sylvain Daubert
|
13
40
|
class Management < Dot11
|
14
41
|
|
@@ -19,6 +46,22 @@ module PacketGen
|
|
19
46
|
@applicable_fields -= %i(mac4 qos_ctrl ht_ctrl)
|
20
47
|
define_applicable_fields
|
21
48
|
end
|
49
|
+
|
50
|
+
# Add an {Element}
|
51
|
+
# @param [Integer,String] type element type
|
52
|
+
# @param [Object] value element value
|
53
|
+
# @return [self]
|
54
|
+
# @since 2.1.3
|
55
|
+
def add_element(type:, value:)
|
56
|
+
if self[:body].is_a? SubMngt
|
57
|
+
element = Element.new(type: type, value: value)
|
58
|
+
self[:body].elements << element
|
59
|
+
else
|
60
|
+
raise FormatError, 'Before adding an Element, you have to add a Dot11::SubMngt subclass instance'
|
61
|
+
end
|
62
|
+
|
63
|
+
self
|
64
|
+
end
|
22
65
|
end
|
23
66
|
end
|
24
67
|
end
|
@@ -9,6 +9,12 @@ module PacketGen
|
|
9
9
|
class Dot11
|
10
10
|
|
11
11
|
# @abstract Base class for all subtype management frames
|
12
|
+
# Subclasses of this class are used to specialize {Management}. A
|
13
|
+
# +SubMngt+ class set +subtype+ field in Dot11 header and may add some
|
14
|
+
# fields.
|
15
|
+
#
|
16
|
+
# All SubMngt subclasses have ability to have {Element}. These elements
|
17
|
+
# may be accessed through {#elements}.
|
12
18
|
# @author Sylvain Daubert
|
13
19
|
class SubMngt < Base
|
14
20
|
# @return [Array<Element>]
|
@@ -38,12 +44,23 @@ module PacketGen
|
|
38
44
|
# @return [String]
|
39
45
|
def inspect
|
40
46
|
str = super
|
41
|
-
str << Inspect.dashed_line('Dot11 Elements',
|
47
|
+
str << Inspect.dashed_line('Dot11 Elements', 3)
|
42
48
|
@elements.each do |el|
|
43
49
|
str << Inspect.shift_level(4) << el.to_human << "\n"
|
44
50
|
end
|
45
51
|
str
|
46
52
|
end
|
53
|
+
|
54
|
+
# Add an {Element} to header
|
55
|
+
# @param [Integer,String] type element type
|
56
|
+
# @param [Object] value element value
|
57
|
+
# @return [self]
|
58
|
+
# @since 2.1.3
|
59
|
+
def add_element(type:, value:)
|
60
|
+
element = Element.new(type: type, value: value)
|
61
|
+
@elements << element
|
62
|
+
self
|
63
|
+
end
|
47
64
|
|
48
65
|
private
|
49
66
|
|
@@ -59,6 +76,12 @@ module PacketGen
|
|
59
76
|
end
|
60
77
|
|
61
78
|
# IEEE 802.11 Association Request frame
|
79
|
+
#
|
80
|
+
# Specialize {Dot11::Management} with +subtype+ set to 0.
|
81
|
+
#
|
82
|
+
# Add fields:
|
83
|
+
# * {#cap} ({Types::Int16le}),
|
84
|
+
# * {#listen_interval} ({Types::Int16le}).
|
62
85
|
# @author Sylvain Daubert
|
63
86
|
class AssoReq < SubMngt
|
64
87
|
# @!attribute cap
|
@@ -72,6 +95,13 @@ module PacketGen
|
|
72
95
|
Management.bind_header AssoReq, op: :and, type: 0, subtype: 0
|
73
96
|
|
74
97
|
# IEEE 802.11 Association Response frame
|
98
|
+
#
|
99
|
+
# Specialize {Dot11::Management} with +subtype+ set to 1.
|
100
|
+
#
|
101
|
+
# Add fields:
|
102
|
+
# * {#cap} ({Types::Int16le}),
|
103
|
+
# * {#status} ({Types::Int16le}),
|
104
|
+
# * {#aid} ({Types::Int16le}).
|
75
105
|
# @author Sylvain Daubert
|
76
106
|
class AssoResp < SubMngt
|
77
107
|
# @!attribute cap
|
@@ -88,6 +118,13 @@ module PacketGen
|
|
88
118
|
Management.bind_header AssoResp, op: :and, type: 0, subtype: 1
|
89
119
|
|
90
120
|
# IEEE 802.11 ReAssociation Request frame
|
121
|
+
#
|
122
|
+
# Specialize {Dot11::Management} with +subtype+ set to 2.
|
123
|
+
#
|
124
|
+
# Add fields:
|
125
|
+
# * {#cap} ({Types::Int16le}),
|
126
|
+
# * {#listen_interval} ({Types::Int16le}),
|
127
|
+
# * {#current_ap} ({Eth::MacAddr}).
|
91
128
|
# @author Sylvain Daubert
|
92
129
|
class ReAssoReq < AssoReq
|
93
130
|
# @!attribute current_ap
|
@@ -98,6 +135,13 @@ module PacketGen
|
|
98
135
|
Management.bind_header ReAssoReq, op: :and, type: 0, subtype: 2
|
99
136
|
|
100
137
|
# IEEE 802.11 ReAssociation Response frame
|
138
|
+
#
|
139
|
+
# Specialize {Dot11::Management} with +subtype+ set to 3.
|
140
|
+
#
|
141
|
+
# Add fields:
|
142
|
+
# * {#cap} ({Types::Int16le}),
|
143
|
+
# * {#status} ({Types::Int16le}),
|
144
|
+
# * {#aid} ({Types::Int16le}).
|
101
145
|
# @author Sylvain Daubert
|
102
146
|
class ReAssoResp < AssoResp
|
103
147
|
end
|
@@ -105,6 +149,10 @@ module PacketGen
|
|
105
149
|
Management.bind_header ReAssoResp, op: :and, type: 0, subtype: 3
|
106
150
|
|
107
151
|
# IEEE 802.11 Probe Request frame
|
152
|
+
#
|
153
|
+
# Specialize {Dot11::Management} with +subtype+ set to 4.
|
154
|
+
#
|
155
|
+
# This class adds no field.
|
108
156
|
# @author Sylvain Daubert
|
109
157
|
class ProbeReq < SubMngt
|
110
158
|
end
|
@@ -112,6 +160,13 @@ module PacketGen
|
|
112
160
|
Management.bind_header ProbeReq, op: :and, type: 0, subtype: 4
|
113
161
|
|
114
162
|
# IEEE 802.11 Probe Response frame
|
163
|
+
#
|
164
|
+
# Specialize {Dot11::Management} with +subtype+ set to 5.
|
165
|
+
#
|
166
|
+
# Add fields:
|
167
|
+
# * {#timestamp} ({Types::Int64le}),
|
168
|
+
# * {#beacon_interval} ({Types::Int16le}),
|
169
|
+
# * {#cap} ({Types::Int16le}).
|
115
170
|
# @author Sylvain Daubert
|
116
171
|
class ProbeResp < SubMngt
|
117
172
|
# @!attribute timestamp
|
@@ -128,6 +183,13 @@ module PacketGen
|
|
128
183
|
Management.bind_header ProbeResp, op: :and, type: 0, subtype: 5
|
129
184
|
|
130
185
|
# IEEE 802.11 Beacon frame
|
186
|
+
#
|
187
|
+
# Specialize {Dot11::Management} with +subtype+ set to 8.
|
188
|
+
#
|
189
|
+
# Add fields:
|
190
|
+
# * {#timestamp} ({Types::Int64le}),
|
191
|
+
# * {#interval} ({Types::Int16le}),
|
192
|
+
# * {#cap} ({Types::Int16le}).
|
131
193
|
# @author Sylvain Daubert
|
132
194
|
class Beacon < SubMngt
|
133
195
|
# @!attribute timestamp
|
@@ -144,12 +206,21 @@ module PacketGen
|
|
144
206
|
Management.bind_header Beacon, op: :and, type: 0, subtype: 8
|
145
207
|
|
146
208
|
# IEEE 802.11 ATIM frame
|
209
|
+
#
|
210
|
+
# Specialize {Dot11::Management} with +subtype+ set to 9.
|
211
|
+
#
|
212
|
+
# This class defines no field.
|
147
213
|
# @author Sylvain Daubert
|
148
214
|
class ATIM < SubMngt; end
|
149
215
|
Header.add_class ATIM
|
150
216
|
Management.bind_header ATIM, op: :and, type: 0, subtype: 9
|
151
217
|
|
152
218
|
# IEEE 802.11 Disassociation frame
|
219
|
+
#
|
220
|
+
# Specialize {Dot11::Management} with +subtype+ set to 10.
|
221
|
+
#
|
222
|
+
# Add fields:
|
223
|
+
# * {#reason} ({Types::Int16le}).
|
153
224
|
# @author Sylvain Daubert
|
154
225
|
class Disas < SubMngt
|
155
226
|
# @!attribute reason
|
@@ -160,6 +231,13 @@ module PacketGen
|
|
160
231
|
Management.bind_header Disas, op: :and, type: 0, subtype: 10
|
161
232
|
|
162
233
|
# IEEE 802.11 Authentication frame
|
234
|
+
#
|
235
|
+
# Specialize {Dot11::Management} with +subtype+ set to 11.
|
236
|
+
#
|
237
|
+
# Add fields:
|
238
|
+
# * {#algo} ({Types::Int16le}),
|
239
|
+
# * {#seqnum} ({Types::Int16le}),
|
240
|
+
# * {#status} ({Types::Int16le}).
|
163
241
|
# @author Sylvain Daubert
|
164
242
|
class Auth < SubMngt
|
165
243
|
# @!attribute algo
|
@@ -176,6 +254,11 @@ module PacketGen
|
|
176
254
|
Management.bind_header Auth, op: :and, type: 0, subtype: 11
|
177
255
|
|
178
256
|
# IEEE 802.11 Deauthentication frame
|
257
|
+
#
|
258
|
+
# Specialize {Dot11::Management} with +subtype+ set to 12.
|
259
|
+
#
|
260
|
+
# Add fields:
|
261
|
+
# * {#reason} ({Types::Int16le}).
|
179
262
|
# @author Sylvain Daubert
|
180
263
|
class DeAuth < SubMngt
|
181
264
|
# @!attribute reason
|
@@ -26,19 +26,19 @@ module PacketGen
|
|
26
26
|
|
27
27
|
# IEEE 802.1X packet types
|
28
28
|
TYPES = {
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
}
|
29
|
+
'EAP Packet' => 0,
|
30
|
+
'Start' => 1,
|
31
|
+
'Logoff' => 2,
|
32
|
+
'Key' => 3,
|
33
|
+
'Encap-ASF-Alert' => 4
|
34
|
+
}.freeze
|
35
35
|
|
36
36
|
# @!attribute version
|
37
37
|
# @return [Integer] 8-bit Protocol Version
|
38
38
|
define_field :version, Types::Int8, default: 1
|
39
39
|
# @!attribute type
|
40
40
|
# @return [Integer] 8-bit Packet Type
|
41
|
-
define_field :type, Types::
|
41
|
+
define_field :type, Types::Int8Enum, enum: TYPES
|
42
42
|
# @!attribute length
|
43
43
|
# @return [Integer] 16-bit body length
|
44
44
|
define_field :length, Types::Int16
|
@@ -46,29 +46,10 @@ module PacketGen
|
|
46
46
|
# @return [Types::String,Header::Base]
|
47
47
|
define_field :body, Types::String
|
48
48
|
|
49
|
-
# @private
|
50
|
-
alias old_type= type=
|
51
|
-
|
52
|
-
# Set type attribute
|
53
|
-
# @param [String,Integer] type
|
54
|
-
# @return [Integer]
|
55
|
-
def type=(type)
|
56
|
-
case type
|
57
|
-
when Integer
|
58
|
-
self.old_type = type
|
59
|
-
else
|
60
|
-
v = TYPES.key(type.to_s)
|
61
|
-
raise ArgumentError, "unknown type #{type}" if v.nil?
|
62
|
-
self.old_type = v
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
49
|
# Get human readable type
|
67
50
|
# @return [String]
|
68
51
|
def human_type
|
69
|
-
|
70
|
-
v = self.type if v.nil?
|
71
|
-
v.to_s
|
52
|
+
self[:type].to_human
|
72
53
|
end
|
73
54
|
end
|
74
55
|
|
data/lib/packetgen/header/ike.rb
CHANGED
@@ -78,19 +78,21 @@ module PacketGen
|
|
78
78
|
PROTO_AH = 2
|
79
79
|
PROTO_ESP = 3
|
80
80
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
81
|
+
EXCHANGE_TYPES = {
|
82
|
+
'IKE_SA_INIT' => 34,
|
83
|
+
'IKE_AUTH' => 35,
|
84
|
+
'CREATE_CHILD_SA' => 36,
|
85
|
+
'INFORMATIONAL' => 37
|
86
|
+
}.freeze
|
85
87
|
|
86
88
|
# @!attribute init_spi
|
87
89
|
# 64-bit initiator SPI
|
88
90
|
# @return [Integer]
|
89
|
-
define_field :init_spi, Types::Int64
|
91
|
+
define_field :init_spi, Types::Int64
|
90
92
|
# @!attribute resp_spi
|
91
93
|
# 64-bit responder SPI
|
92
94
|
# @return [Integer]
|
93
|
-
define_field :resp_spi, Types::Int64
|
95
|
+
define_field :resp_spi, Types::Int64
|
94
96
|
# @!attribute next
|
95
97
|
# 8-bit next payload type
|
96
98
|
# @return [Integer]
|
@@ -102,7 +104,7 @@ module PacketGen
|
|
102
104
|
# @!attribute [r] exchange_type
|
103
105
|
# 8-bit exchange type
|
104
106
|
# @return [Integer]
|
105
|
-
define_field :exchange_type, Types::
|
107
|
+
define_field :exchange_type, Types::Int8Enum, enum: EXCHANGE_TYPES
|
106
108
|
# @!attribute flags
|
107
109
|
# 8-bit flags
|
108
110
|
# @return [Integer]
|
@@ -152,30 +154,13 @@ module PacketGen
|
|
152
154
|
self.type = options[:exchange_type] if options[:exchange_type]
|
153
155
|
end
|
154
156
|
|
155
|
-
# Set exchange type
|
156
|
-
# @param [Integer,String] value
|
157
|
-
# @return [Integer]
|
158
|
-
def exchange_type=(value)
|
159
|
-
type = case value
|
160
|
-
when Integer
|
161
|
-
value
|
162
|
-
else
|
163
|
-
c = self.class.constants.grep(/TYPE_#{value}/).first
|
164
|
-
c ? self.class.const_get(c) : nil
|
165
|
-
end
|
166
|
-
raise ArgumentError, "unknown exchange type #{value.inspect}" unless type
|
167
|
-
self[:exchange_type].value = type
|
168
|
-
end
|
169
157
|
alias type exchange_type
|
170
158
|
alias type= exchange_type=
|
171
159
|
|
172
160
|
# Get exchange type name
|
173
161
|
# @return [String
|
174
162
|
def human_exchange_type
|
175
|
-
|
176
|
-
select { |c| self.class.const_get(c) == type }.
|
177
|
-
first || "type #{type}"
|
178
|
-
name.to_s.sub(/TYPE_/, '')
|
163
|
+
self[:exchange_type].to_human
|
179
164
|
end
|
180
165
|
alias human_type human_exchange_type
|
181
166
|
|
@@ -39,50 +39,34 @@ module PacketGen
|
|
39
39
|
# Payload type number
|
40
40
|
PAYLOAD_TYPE = 37
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
42
|
+
ENCODINGS = {
|
43
|
+
'PKCS7_WRAPPED_X509' => 1,
|
44
|
+
'PGP' => 2,
|
45
|
+
'DNS_SIGNED_KEY' => 3,
|
46
|
+
'X509_CERT_SIG' => 4,
|
47
|
+
'KERBEROS_TOKEN' => 6,
|
48
|
+
'X509_CRL' => 7,
|
49
|
+
'X509_ARL' => 8,
|
50
|
+
'SPKI_CERT' => 9,
|
51
|
+
'X509_CERT_ATTR' => 10,
|
52
|
+
'HASH_URL_X509_CERT' => 12,
|
53
|
+
'HASH_URL_X509_BUNDLE' => 13
|
54
|
+
}.freeze
|
53
55
|
|
54
56
|
# @attribute encoding
|
55
57
|
# 8-bit certificate encoding
|
56
58
|
# @return [Integer]
|
57
|
-
define_field_before :content, :encoding, Types::
|
59
|
+
define_field_before :content, :encoding, Types::Int8Enum, enum: ENCODINGS
|
58
60
|
|
59
61
|
def initialize(options={})
|
60
62
|
super
|
61
63
|
self.encoding = options[:encoding] if options[:encoding]
|
62
64
|
end
|
63
65
|
|
64
|
-
# Set encoding
|
65
|
-
# @param [Integer,String] value
|
66
|
-
# @return [Integer]
|
67
|
-
def encoding=(value)
|
68
|
-
encoding = case value
|
69
|
-
when Integer
|
70
|
-
value
|
71
|
-
else
|
72
|
-
c = self.class.constants.grep(/ENCODING_#{value}/).first
|
73
|
-
c ? self.class.const_get(c) : nil
|
74
|
-
end
|
75
|
-
raise ArgumentError, "unknown ID encoding #{value.inspect}" unless encoding
|
76
|
-
self[:encoding].value = encoding
|
77
|
-
end
|
78
|
-
|
79
66
|
# Get encoding name
|
80
67
|
# @return [String]
|
81
68
|
def human_encoding
|
82
|
-
|
83
|
-
select { |c| self.class.const_get(c) == encoding }.
|
84
|
-
first || "encoding #{encoding}"
|
85
|
-
name.to_s.sub(/ENCODING_/, '')
|
69
|
+
self[:encoding].to_human
|
86
70
|
end
|
87
71
|
|
88
72
|
# @return [String]
|