metasploit-aggregator 0.1.2 → 0.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.
@@ -0,0 +1,13 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: metasploit/aggregator/aggregator.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ require 'metasploit/aggregator/messages_pb'
7
+ Google::Protobuf::DescriptorPool.generated_pool.build do
8
+ end
9
+
10
+ module Metasploit
11
+ module Aggregator
12
+ end
13
+ end
@@ -0,0 +1,36 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # Source: metasploit/aggregator/aggregator.proto for package 'metasploit.aggregator'
3
+
4
+ require 'grpc'
5
+ require 'metasploit/aggregator/aggregator_pb'
6
+
7
+ module Metasploit
8
+ module Aggregator
9
+ module Pb
10
+ class Service
11
+
12
+ include GRPC::GenericService
13
+
14
+ self.marshal_class_method = :encode
15
+ self.unmarshal_class_method = :decode
16
+ self.service_name = 'metasploit.aggregator.Pb'
17
+
18
+ rpc :available, Message::No_params, Message::Result
19
+ rpc :version, Message::No_params, Message::String_array
20
+ rpc :sessions, Message::No_params, Message::Result_map
21
+ rpc :cables, Message::No_params, Message::String_array
22
+ rpc :obtain_session, Message::String_array, Message::Result
23
+ rpc :release_session, Message::String_array, Message::Result
24
+ rpc :session_details, Message::String_array, Message::Result_map
25
+ rpc :add_cable, Message::Cable_def, Message::Result
26
+ rpc :remove_cable, Message::String_array, Message::Result
27
+ rpc :register_default, Message::Register, Message::Result
28
+ rpc :default, Message::No_params, Message::String_array
29
+ rpc :available_addresses, Message::No_params, Message::String_array
30
+ rpc :process, stream(Message::Response), stream(Message::Request)
31
+ end
32
+
33
+ Stub = Service.rpc_stub_class
34
+ end
35
+ end
36
+ end
@@ -1,4 +1,5 @@
1
1
  require 'openssl'
2
+ require 'singleton'
2
3
  require 'socket'
3
4
 
4
5
  require 'metasploit/aggregator/logger'
@@ -10,6 +11,7 @@ module Metasploit
10
11
  module Aggregator
11
12
 
12
13
  class ConnectionManager
14
+ include Singleton
13
15
 
14
16
  def initialize
15
17
  @cables = []
@@ -119,7 +121,7 @@ module Metasploit
119
121
  next unless cable.forwarder.connections.include?(payload)
120
122
  # TODO: improve how time is exposed for live connections
121
123
  time = cable.forwarder.connection_info(payload)['TIME']
122
- detail_map['LAST_SEEN'] = Time.now - time unless time.nil?
124
+ detail_map['LAST_SEEN'] = (Time.now - time).to_s unless time.nil?
123
125
  end
124
126
  detail_map
125
127
  end
@@ -0,0 +1,9 @@
1
+ module Metasploit
2
+ module Aggregator
3
+ class Error < RuntimeError
4
+ end
5
+
6
+ class CompatibilityError < Error
7
+ end
8
+ end
9
+ end
@@ -21,7 +21,7 @@ module Metasploit
21
21
  @time = Time.now
22
22
  @router = Router.instance
23
23
  @session_service = SessionDetailService.instance
24
- @pending_requests = nil
24
+ @pending_request = nil
25
25
  end
26
26
 
27
27
  def process_requests
@@ -0,0 +1,51 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: metasploit/aggregator/messages.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ Google::Protobuf::DescriptorPool.generated_pool.build do
7
+ add_message "metasploit.aggregator.message.No_params" do
8
+ end
9
+ add_message "metasploit.aggregator.message.Request" do
10
+ repeated :headers, :string, 1
11
+ optional :body, :bytes, 2
12
+ end
13
+ add_message "metasploit.aggregator.message.Cable_def" do
14
+ optional :type, :string, 1
15
+ optional :host, :string, 2
16
+ optional :port, :int32, 3
17
+ optional :pem, :bytes, 4
18
+ end
19
+ add_message "metasploit.aggregator.message.Register" do
20
+ optional :uuid, :string, 1
21
+ repeated :payloads, :string, 2
22
+ end
23
+ add_message "metasploit.aggregator.message.Response" do
24
+ optional :uuid, :string, 1
25
+ optional :response, :message, 2, "metasploit.aggregator.message.Request"
26
+ end
27
+ add_message "metasploit.aggregator.message.Result_map" do
28
+ map :map, :string, :string, 1
29
+ end
30
+ add_message "metasploit.aggregator.message.String_array" do
31
+ repeated :value, :string, 1
32
+ end
33
+ add_message "metasploit.aggregator.message.Result" do
34
+ optional :answer, :bool, 1
35
+ end
36
+ end
37
+
38
+ module Metasploit
39
+ module Aggregator
40
+ module Message
41
+ No_params = Google::Protobuf::DescriptorPool.generated_pool.lookup("metasploit.aggregator.message.No_params").msgclass
42
+ Request = Google::Protobuf::DescriptorPool.generated_pool.lookup("metasploit.aggregator.message.Request").msgclass
43
+ Cable_def = Google::Protobuf::DescriptorPool.generated_pool.lookup("metasploit.aggregator.message.Cable_def").msgclass
44
+ Register = Google::Protobuf::DescriptorPool.generated_pool.lookup("metasploit.aggregator.message.Register").msgclass
45
+ Response = Google::Protobuf::DescriptorPool.generated_pool.lookup("metasploit.aggregator.message.Response").msgclass
46
+ Result_map = Google::Protobuf::DescriptorPool.generated_pool.lookup("metasploit.aggregator.message.Result_map").msgclass
47
+ String_array = Google::Protobuf::DescriptorPool.generated_pool.lookup("metasploit.aggregator.message.String_array").msgclass
48
+ Result = Google::Protobuf::DescriptorPool.generated_pool.lookup("metasploit.aggregator.message.Result").msgclass
49
+ end
50
+ end
51
+ end
@@ -60,7 +60,6 @@ module Metasploit
60
60
  @queue_by_uuid[uuid] << request.pop
61
61
  end
62
62
  end
63
- [] unless @queue_by_uuid[uuid].length > 0
64
63
  [@queue_by_uuid[uuid], nil, uuid]
65
64
  end
66
65
  end
@@ -9,267 +9,267 @@ module Metasploit
9
9
  module Tlv
10
10
  class UUID
11
11
 
12
- include Rex::Arch
13
- #
14
- # Constants
15
- #
12
+ include Rex::Arch
13
+ #
14
+ # Constants
15
+ #
16
16
 
17
- Architectures = {
18
- 0 => nil,
19
- 1 => ARCH_X86,
20
- 2 => ARCH_X64, # removed ARCH_X86_64, now consistent across the board
21
- 3 => ARCH_X64,
22
- 4 => ARCH_MIPS,
23
- 5 => ARCH_MIPSLE,
24
- 6 => ARCH_MIPSBE,
25
- 7 => ARCH_PPC,
26
- 8 => ARCH_PPC64,
27
- 9 => ARCH_CBEA,
28
- 10 => ARCH_CBEA64,
29
- 11 => ARCH_SPARC,
30
- 12 => ARCH_ARMLE,
31
- 13 => ARCH_ARMBE,
32
- 14 => ARCH_CMD,
33
- 15 => ARCH_PHP,
34
- 16 => ARCH_TTY,
35
- 17 => ARCH_JAVA,
36
- 18 => ARCH_RUBY,
37
- 19 => ARCH_DALVIK,
38
- 20 => ARCH_PYTHON,
39
- 21 => ARCH_NODEJS,
40
- 22 => ARCH_FIREFOX,
41
- 23 => ARCH_ZARCH,
42
- 24 => ARCH_AARCH64,
43
- 25 => ARCH_MIPS64,
44
- 26 => ARCH_PPC64LE
45
- }
17
+ Architectures = {
18
+ 0 => nil,
19
+ 1 => ARCH_X86,
20
+ 2 => ARCH_X64, # removed ARCH_X86_64, now consistent across the board
21
+ 3 => ARCH_X64,
22
+ 4 => ARCH_MIPS,
23
+ 5 => ARCH_MIPSLE,
24
+ 6 => ARCH_MIPSBE,
25
+ 7 => ARCH_PPC,
26
+ 8 => ARCH_PPC64,
27
+ 9 => ARCH_CBEA,
28
+ 10 => ARCH_CBEA64,
29
+ 11 => ARCH_SPARC,
30
+ 12 => ARCH_ARMLE,
31
+ 13 => ARCH_ARMBE,
32
+ 14 => ARCH_CMD,
33
+ 15 => ARCH_PHP,
34
+ 16 => ARCH_TTY,
35
+ 17 => ARCH_JAVA,
36
+ 18 => ARCH_RUBY,
37
+ 19 => ARCH_DALVIK,
38
+ 20 => ARCH_PYTHON,
39
+ 21 => ARCH_NODEJS,
40
+ 22 => ARCH_FIREFOX,
41
+ 23 => ARCH_ZARCH,
42
+ 24 => ARCH_AARCH64,
43
+ 25 => ARCH_MIPS64,
44
+ 26 => ARCH_PPC64LE
45
+ }
46
+
47
+ Platforms = {
48
+ 0 => nil,
49
+ 1 => 'windows',
50
+ 2 => 'netware',
51
+ 3 => 'android',
52
+ 4 => 'java',
53
+ 5 => 'ruby',
54
+ 6 => 'linux',
55
+ 7 => 'cisco',
56
+ 8 => 'solaris',
57
+ 9 => 'osx',
58
+ 10 => 'bsd',
59
+ 11 => 'openbsd',
60
+ 12 => 'bsdi',
61
+ 13 => 'netbsd',
62
+ 14 => 'freebsd',
63
+ 15 => 'aix',
64
+ 16 => 'hpux',
65
+ 17 => 'irix',
66
+ 18 => 'unix',
67
+ 19 => 'php',
68
+ 20 => 'js',
69
+ 21 => 'python',
70
+ 22 => 'nodejs',
71
+ 23 => 'firefox'
72
+ }
46
73
 
47
- Platforms = {
48
- 0 => nil,
49
- 1 => 'windows',
50
- 2 => 'netware',
51
- 3 => 'android',
52
- 4 => 'java',
53
- 5 => 'ruby',
54
- 6 => 'linux',
55
- 7 => 'cisco',
56
- 8 => 'solaris',
57
- 9 => 'osx',
58
- 10 => 'bsd',
59
- 11 => 'openbsd',
60
- 12 => 'bsdi',
61
- 13 => 'netbsd',
62
- 14 => 'freebsd',
63
- 15 => 'aix',
64
- 16 => 'hpux',
65
- 17 => 'irix',
66
- 18 => 'unix',
67
- 19 => 'php',
68
- 20 => 'js',
69
- 21 => 'python',
70
- 22 => 'nodejs',
71
- 23 => 'firefox'
72
- }
74
+ # The raw length of the UUID structure
75
+ RawLength = 16
73
76
 
74
- # The raw length of the UUID structure
75
- RawLength = 16
77
+ # The base64url-encoded length of the UUID structure
78
+ UriLength = 22
76
79
 
77
- # The base64url-encoded length of the UUID structure
78
- UriLength = 22
80
+ # Validity constraints for UUID timestamps in UTC
81
+ TimestampMaxFuture = Time.now.utc.to_i + (30*24*3600) # Up to 30 days in the future
82
+ TimestampMaxPast = 1420070400 # Since 2015-01-01 00:00:00 UTC
79
83
 
80
- # Validity constraints for UUID timestamps in UTC
81
- TimestampMaxFuture = Time.now.utc.to_i + (30*24*3600) # Up to 30 days in the future
82
- TimestampMaxPast = 1420070400 # Since 2015-01-01 00:00:00 UTC
84
+ #
85
+ # Class Methods
86
+ #
83
87
 
84
- #
85
- # Class Methods
86
- #
88
+ #
89
+ # Parse a raw 16-byte payload UUID and return the payload ID, platform, architecture, and timestamp
90
+ #
91
+ # @param raw [String] The raw 16-byte payload UUID to parse
92
+ # @return [Hash] A hash containing the Payload ID, platform, architecture, and timestamp
93
+ #
94
+ def self.parse_raw(raw)
95
+ if raw.to_s.length < 16
96
+ raise ArgumentError, "Raw UUID must be at least 16 bytes"
97
+ end
87
98
 
88
- #
89
- # Parse a raw 16-byte payload UUID and return the payload ID, platform, architecture, and timestamp
90
- #
91
- # @param raw [String] The raw 16-byte payload UUID to parse
92
- # @return [Hash] A hash containing the Payload ID, platform, architecture, and timestamp
93
- #
94
- def self.parse_raw(raw)
95
- if raw.to_s.length < 16
96
- raise ArgumentError, "Raw UUID must be at least 16 bytes"
99
+ puid, plat_xor, arch_xor, plat_id, arch_id, tstamp = raw.unpack('a8C4N')
100
+ plat = find_platform_name(plat_xor ^ plat_id)
101
+ arch = find_architecture_name(arch_xor ^ arch_id)
102
+ time_xor = [plat_xor, arch_xor, plat_xor, arch_xor].pack('C4').unpack('N').first
103
+ time = time_xor ^ tstamp
104
+ { puid: puid, platform: plat, arch: arch, timestamp: time, xor1: plat_xor, xor2: arch_xor }
97
105
  end
98
106
 
99
- puid, plat_xor, arch_xor, plat_id, arch_id, tstamp = raw.unpack('a8C4N')
100
- plat = find_platform_name(plat_xor ^ plat_id)
101
- arch = find_architecture_name(arch_xor ^ arch_id)
102
- time_xor = [plat_xor, arch_xor, plat_xor, arch_xor].pack('C4').unpack('N').first
103
- time = time_xor ^ tstamp
104
- { puid: puid, platform: plat, arch: arch, timestamp: time, xor1: plat_xor, xor2: arch_xor }
105
- end
107
+ #
108
+ # Filter out UUIDs with obviously invalid fields and return either
109
+ # a validated UUID or a UUID with the arch, platform, and timestamp
110
+ # fields strippped out.
111
+ #
112
+ # @param uuid [Hash] The UUID in hash format
113
+ # @return [Hash] The filtered UUID in hash format
114
+ #
115
+ def self.filter_invalid(uuid)
116
+ # Verify the UUID fields and return just the Payload ID unless the
117
+ # timestamp is within our constraints and the UUID has either a
118
+ # valid architecture or platform
119
+ if uuid[:timestamp] > TimestampMaxFuture ||
120
+ uuid[:timestamp] < TimestampMaxPast ||
121
+ (uuid[:arch].nil? && uuid[:platform].nil?)
122
+ return { puid: uuid[:puid] }
123
+ end
124
+ uuid
125
+ end
106
126
 
107
- #
108
- # Filter out UUIDs with obviously invalid fields and return either
109
- # a validated UUID or a UUID with the arch, platform, and timestamp
110
- # fields strippped out.
111
- #
112
- # @param uuid [Hash] The UUID in hash format
113
- # @return [Hash] The filtered UUID in hash format
114
- #
115
- def self.filter_invalid(uuid)
116
- # Verify the UUID fields and return just the Payload ID unless the
117
- # timestamp is within our constraints and the UUID has either a
118
- # valid architecture or platform
119
- if uuid[:timestamp] > TimestampMaxFuture ||
120
- uuid[:timestamp] < TimestampMaxPast ||
121
- (uuid[:arch].nil? && uuid[:platform].nil?)
122
- return { puid: uuid[:puid] }
127
+ #
128
+ # Look up the numeric platform ID given a string or PlatformList as input
129
+ #
130
+ # @param platform [String] The name of the platform to lookup
131
+ # @return [Fixnum] The integer value of this platform
132
+ #
133
+ def self.find_platform_id(platform)
134
+ name = name.first if name.kind_of? ::Array
135
+ ( Platforms.keys.select{ |k|
136
+ Platforms[k] == name
137
+ }.first || Platforms[0] ).to_i
123
138
  end
124
- uuid
125
- end
126
139
 
127
- #
128
- # Look up the numeric platform ID given a string or PlatformList as input
129
- #
130
- # @param platform [String] The name of the platform to lookup
131
- # @return [Fixnum] The integer value of this platform
132
- #
133
- def self.find_platform_id(platform)
134
- name = name.first if name.kind_of? ::Array
135
- ( Platforms.keys.select{ |k|
136
- Platforms[k] == name
137
- }.first || Platforms[0] ).to_i
138
- end
140
+ #
141
+ # Look up the numeric architecture ID given a string as input
142
+ #
143
+ # @param name [String] The name of the architecture to lookup
144
+ # @return [Fixnum] The integer value of this architecture
145
+ #
146
+ def self.find_architecture_id(name)
147
+ name = name.first if name.kind_of? ::Array
148
+ ( Architectures.keys.select{ |k|
149
+ Architectures[k] == name
150
+ }.first || Architectures[0] ).to_i
151
+ end
139
152
 
140
- #
141
- # Look up the numeric architecture ID given a string as input
142
- #
143
- # @param name [String] The name of the architecture to lookup
144
- # @return [Fixnum] The integer value of this architecture
145
- #
146
- def self.find_architecture_id(name)
147
- name = name.first if name.kind_of? ::Array
148
- ( Architectures.keys.select{ |k|
149
- Architectures[k] == name
150
- }.first || Architectures[0] ).to_i
151
- end
153
+ def self.find_platform_name(num)
154
+ Platforms[num]
155
+ end
152
156
 
153
- def self.find_platform_name(num)
154
- Platforms[num]
155
- end
157
+ def self.find_architecture_name(num)
158
+ Architectures[num]
159
+ end
156
160
 
157
- def self.find_architecture_name(num)
158
- Architectures[num]
159
- end
161
+ #
162
+ # Instance methods
163
+ #
160
164
 
161
- #
162
- # Instance methods
163
- #
165
+ def initialize(opts=nil)
166
+ opts = load_new if opts.nil?
167
+ opts = load_raw(opts[:raw]) if opts[:raw]
164
168
 
165
- def initialize(opts=nil)
166
- opts = load_new if opts.nil?
167
- opts = load_raw(opts[:raw]) if opts[:raw]
169
+ self.puid = opts[:puid]
170
+ self.timestamp = opts[:timestamp]
171
+ self.arch = opts[:arch]
172
+ self.platform = opts[:platform]
173
+ self.xor1 = opts[:xor1]
174
+ self.xor2 = opts[:xor2]
168
175
 
169
- self.puid = opts[:puid]
170
- self.timestamp = opts[:timestamp]
171
- self.arch = opts[:arch]
172
- self.platform = opts[:platform]
173
- self.xor1 = opts[:xor1]
174
- self.xor2 = opts[:xor2]
176
+ # Generate some sensible defaults
177
+ self.puid ||= SecureRandom.random_bytes(8)
178
+ self.xor1 ||= rand(256)
179
+ self.xor2 ||= rand(256)
180
+ self.timestamp ||= Time.now.utc.to_i
181
+ end
175
182
 
176
- # Generate some sensible defaults
177
- self.puid ||= SecureRandom.random_bytes(8)
178
- self.xor1 ||= rand(256)
179
- self.xor2 ||= rand(256)
180
- self.timestamp ||= Time.now.utc.to_i
181
- end
183
+ #
184
+ # Initializes a UUID object given a raw 16+ byte blob
185
+ #
186
+ # @param raw [String] The string containing at least 16 bytes of encoded data
187
+ # @return [Hash] The attributes encoded into this UUID
188
+ #
189
+ def load_raw(raw)
190
+ self.class.filter_invalid(self.class.parse_raw(raw))
191
+ end
182
192
 
183
- #
184
- # Initializes a UUID object given a raw 16+ byte blob
185
- #
186
- # @param raw [String] The string containing at least 16 bytes of encoded data
187
- # @return [Hash] The attributes encoded into this UUID
188
- #
189
- def load_raw(raw)
190
- self.class.filter_invalid(self.class.parse_raw(raw))
191
- end
193
+ def load_new
194
+ self.class.parse_raw(self.class.generate_raw())
195
+ end
192
196
 
193
- def load_new
194
- self.class.parse_raw(self.class.generate_raw())
195
- end
197
+ #
198
+ # Provides a string representation of a UUID
199
+ #
200
+ # @return [String] The human-readable version of the UUID data
201
+ #
202
+ def to_s
203
+ arch_id = self.class.find_architecture_id(self.arch).to_s
204
+ plat_id = self.class.find_platform_id(self.platform).to_s
205
+ [
206
+ self.puid_hex,
207
+ [ self.arch || "noarch", arch_id ].join("="),
208
+ [ self.platform || "noplatform", plat_id ].join("="),
209
+ Time.at(self.timestamp.to_i).utc.strftime("%Y-%m-%dT%H:%M:%SZ")
210
+ ].join("/")
211
+ end
196
212
 
197
- #
198
- # Provides a string representation of a UUID
199
- #
200
- # @return [String] The human-readable version of the UUID data
201
- #
202
- def to_s
203
- arch_id = self.class.find_architecture_id(self.arch).to_s
204
- plat_id = self.class.find_platform_id(self.platform).to_s
205
- [
206
- self.puid_hex,
207
- [ self.arch || "noarch", arch_id ].join("="),
208
- [ self.platform || "noplatform", plat_id ].join("="),
209
- Time.at(self.timestamp.to_i).utc.strftime("%Y-%m-%dT%H:%M:%SZ")
210
- ].join("/")
211
- end
213
+ #
214
+ # Return a string that represents the Meterpreter arch/platform
215
+ #
216
+ def session_type
217
+ # mini-patch for x86 so that it renders x64 instead. This is
218
+ # mostly to keep various external modules happy.
219
+ arch = self.arch
220
+ if arch == ARCH_X86_64
221
+ arch = ARCH_X64
222
+ end
223
+ "#{arch}/#{self.platform}"
224
+ end
212
225
 
213
- #
214
- # Return a string that represents the Meterpreter arch/platform
215
- #
216
- def session_type
217
- # mini-patch for x86 so that it renders x64 instead. This is
218
- # mostly to keep various external modules happy.
219
- arch = self.arch
220
- if arch == ARCH_X86_64
221
- arch = ARCH_X64
226
+ #
227
+ # Provides a hash representation of a UUID
228
+ #
229
+ # @return [Hash] The hash representation of the UUID suitable for creating a new one
230
+ #
231
+ def to_h
232
+ {
233
+ puid: self.puid,
234
+ arch: self.arch, platform: self.platform,
235
+ timestamp: self.timestamp,
236
+ xor1: self.xor1, xor2: self.xor2
237
+ }
222
238
  end
223
- "#{arch}/#{self.platform}"
224
- end
225
239
 
226
- #
227
- # Provides a hash representation of a UUID
228
- #
229
- # @return [Hash] The hash representation of the UUID suitable for creating a new one
230
- #
231
- def to_h
232
- {
233
- puid: self.puid,
234
- arch: self.arch, platform: self.platform,
235
- timestamp: self.timestamp,
236
- xor1: self.xor1, xor2: self.xor2
237
- }
238
- end
240
+ #
241
+ # Provides a raw byte representation of a UUID
242
+ #
243
+ # @return [String] The 16-byte raw encoded version of the UUID
244
+ #
245
+ def to_raw
246
+ self.class.generate_raw(self.to_h)
247
+ end
239
248
 
240
- #
241
- # Provides a raw byte representation of a UUID
242
- #
243
- # @return [String] The 16-byte raw encoded version of the UUID
244
- #
245
- def to_raw
246
- self.class.generate_raw(self.to_h)
247
- end
249
+ #
250
+ # Provides a hex representation of the Payload UID of the UUID
251
+ #
252
+ # @return [String] The 16-byte hex string representing the Payload UID
253
+ #
254
+ def puid_hex
255
+ self.puid.unpack('H*').first
256
+ end
248
257
 
249
- #
250
- # Provides a hex representation of the Payload UID of the UUID
251
- #
252
- # @return [String] The 16-byte hex string representing the Payload UID
253
- #
254
- def puid_hex
255
- self.puid.unpack('H*').first
256
- end
258
+ #
259
+ # Clears the two random XOR keys used for obfuscation
260
+ #
261
+ def xor_reset
262
+ self.xor1 = self.xor2 = nil
263
+ self
264
+ end
257
265
 
258
- #
259
- # Clears the two random XOR keys used for obfuscation
260
- #
261
- def xor_reset
262
- self.xor1 = self.xor2 = nil
263
- self
266
+ attr_accessor :arch
267
+ attr_accessor :platform
268
+ attr_accessor :timestamp
269
+ attr_accessor :puid
270
+ attr_accessor :xor1
271
+ attr_accessor :xor2
264
272
  end
265
-
266
- attr_accessor :arch
267
- attr_accessor :platform
268
- attr_accessor :timestamp
269
- attr_accessor :puid
270
- attr_accessor :xor1
271
- attr_accessor :xor2
272
- end
273
273
  end
274
274
  end
275
275
  end