packetgen 2.1.2 → 2.1.3
Sign up to get free protection for your applications and to get access to all the features.
- 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]
|