ronin-support 1.0.4 → 1.0.6
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/.github/workflows/ruby.yml +1 -0
- data/.rubocop.yml +8 -0
- data/ChangeLog.md +19 -1
- data/lib/ronin/support/binary/stream/methods.rb +5 -1
- data/lib/ronin/support/encoding/base64.rb +2 -2
- data/lib/ronin/support/network/http.rb +5 -2
- data/lib/ronin/support/network/ip_range/cidr.rb +4 -15
- data/lib/ronin/support/network/ip_range/glob.rb +29 -26
- data/lib/ronin/support/network/ip_range/range.rb +3 -20
- data/lib/ronin/support/network/ip_range.rb +27 -18
- data/lib/ronin/support/network/pop3/mixin.rb +5 -2
- data/lib/ronin/support/network/smtp/mixin.rb +5 -2
- data/lib/ronin/support/network/ssl/mixin.rb +3 -3
- data/lib/ronin/support/network/tcp.rb +5 -2
- data/lib/ronin/support/network/tls/mixin.rb +3 -3
- data/lib/ronin/support/network/udp.rb +5 -2
- data/lib/ronin/support/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04b9f7e7aa3d25c5742621faaeba6ce51150d3959d82867d41901c7cd1a2af06
|
4
|
+
data.tar.gz: 4e081a47953f762edca8e267c6a31fc168cf8a91f93ce464f7586a1d3e81b2dc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5611fdbe096f30f8ad9a4d828b722c221e90b93a9e217e6fb9c3ca3eb54dc7103cb0d39e7b5b98f5a74192c6339adedad97c5c11f69bb5019b2ebc7ca0ef3b03
|
7
|
+
data.tar.gz: 107956428d0b34d47378c338143e70820cee6a62fedf24927157d5f06f16b4b978957fb02f945f7eabb75e897dc81a2ab58665fbcf56b072a7f7ad4493bb116a
|
data/.github/workflows/ruby.yml
CHANGED
data/.rubocop.yml
CHANGED
@@ -107,3 +107,11 @@ Naming/BinaryOperatorParameterName:
|
|
107
107
|
Lint/RescueException:
|
108
108
|
Exclude:
|
109
109
|
- 'lib/ronin/support/core_ext/kernel.rb'
|
110
|
+
|
111
|
+
# make an exception when we need to test the #each method directly
|
112
|
+
Style/MapIntoArray:
|
113
|
+
Exclude:
|
114
|
+
- 'spec/archive/zip/reader_spec.rb'
|
115
|
+
- 'spec/network/ip_range/cidr_spec.rb'
|
116
|
+
- 'spec/network/ip_range/glob_spec.rb'
|
117
|
+
- 'spec/network/ip_range_spec.rb'
|
data/ChangeLog.md
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
### 1.0.6 / 2024-06-19
|
2
|
+
|
3
|
+
* Fixed error messages in {Ronin::Support::Encoding::Base64.encode} and
|
4
|
+
{Ronin::Support::Encoding::Base64.decode}.
|
5
|
+
* Fixed {Ronin::Support::Network::IPRange::Glob#each} to support `*` in IPv6
|
6
|
+
glob ranges.
|
7
|
+
* {Ronin::Support::Network::TCP.connect},
|
8
|
+
{Ronin::Support::Network::UDP.connect}, and
|
9
|
+
{Ronin::Support::Network::HTTP.connect}, when given a block, now returns the
|
10
|
+
block's return value.
|
11
|
+
* {Ronin::Support::Network::TCP.connect} and
|
12
|
+
{Ronin::Support::Network::UDP.connect} properly closes the socket when passed
|
13
|
+
a block that raises an exception.
|
14
|
+
|
15
|
+
### 1.0.5 / 2023-12-27
|
16
|
+
|
17
|
+
* Fixed a bug in {Ronin::Support::Binary::Stream::Methods#read_string} on Ruby
|
18
|
+
3.3.0.
|
19
|
+
|
1
20
|
### 1.0.4 / 2023-12-15
|
2
21
|
|
3
22
|
* Fixed a bug in {Array#pack} where complex types (ex: `[[:uint32, 4], 10]`)
|
@@ -699,4 +718,3 @@
|
|
699
718
|
* Require combinatorics ~> 0.3.
|
700
719
|
* Require uri-query_params ~> 0.5, >= 0.5.2.
|
701
720
|
* Require data_paths ~> 0.2, >= 0.2.1.
|
702
|
-
|
@@ -111,7 +111,11 @@ module Ronin
|
|
111
111
|
# @api public
|
112
112
|
#
|
113
113
|
def read_string(length=nil)
|
114
|
-
new_string =
|
114
|
+
new_string = if (encoding = external_encoding)
|
115
|
+
String.new('', encoding: encoding)
|
116
|
+
else
|
117
|
+
String.new('')
|
118
|
+
end
|
115
119
|
|
116
120
|
if length
|
117
121
|
length.times do
|
@@ -52,7 +52,7 @@ module Ronin
|
|
52
52
|
when :url_safe then ::Base64.urlsafe_encode64(data)
|
53
53
|
when nil then ::Base64.encode64(data)
|
54
54
|
else
|
55
|
-
raise(ArgumentError,"Base64 mode must be either :string, :
|
55
|
+
raise(ArgumentError,"Base64 mode must be either :string, :url_safe, or nil: #{mode.inspect}")
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
@@ -74,7 +74,7 @@ module Ronin
|
|
74
74
|
when :url_safe then ::Base64.urlsafe_decode64(data)
|
75
75
|
when nil then ::Base64.decode64(data)
|
76
76
|
else
|
77
|
-
raise(ArgumentError,"Base64 mode must be either :string, :
|
77
|
+
raise(ArgumentError,"Base64 mode must be either :string, :url_safe, or nil: #{mode.inspect}")
|
78
78
|
end
|
79
79
|
end
|
80
80
|
end
|
@@ -31,7 +31,6 @@ module Ronin
|
|
31
31
|
# cidr.each { |ip puts }
|
32
32
|
# # 10.0.0.0
|
33
33
|
# # 10.0.0.1
|
34
|
-
# # 10.0.0.2
|
35
34
|
# # ...
|
36
35
|
# # 10.0.0.254
|
37
36
|
# # 10.0.0.255
|
@@ -151,8 +150,8 @@ module Ronin
|
|
151
150
|
#
|
152
151
|
# @example
|
153
152
|
# IPRange::CIDR.each('10.0.0.1/24') { |ip| puts ip }
|
153
|
+
# # 10.0.0.0
|
154
154
|
# # 10.0.0.1
|
155
|
-
# # 10.0.0.2
|
156
155
|
# # ...
|
157
156
|
# # 10.0.0.254
|
158
157
|
# # 10.0.0.255
|
@@ -174,17 +173,14 @@ module Ronin
|
|
174
173
|
#
|
175
174
|
# @return [self]
|
176
175
|
#
|
177
|
-
# @note
|
178
|
-
# This method will skip IPv4 addresses ending in `.0` or `.255`.
|
179
|
-
#
|
180
176
|
# @example
|
181
177
|
# cidr = IPAddr.new('10.1.1.1/24')
|
182
178
|
# cidr.each { |ip| puts ip }
|
179
|
+
# # 10.0.0.0
|
183
180
|
# # 10.0.0.1
|
184
|
-
# # 10.0.0.2
|
185
181
|
# # ...
|
186
|
-
# # 10.0.0.253
|
187
182
|
# # 10.0.0.254
|
183
|
+
# # 10.0.0.255
|
188
184
|
#
|
189
185
|
def each
|
190
186
|
return enum_for(__method__) unless block_given?
|
@@ -192,14 +188,7 @@ module Ronin
|
|
192
188
|
family_mask = MASKS[@family]
|
193
189
|
|
194
190
|
(0..((~@mask_addr) & family_mask)).each do |i|
|
195
|
-
|
196
|
-
|
197
|
-
# skip IPv4 addresses ending in .0 or .255
|
198
|
-
if (ipv4? && ((ip_uint & 0xff) == 0 || (ip_uint & 0xff) == 0xff))
|
199
|
-
next
|
200
|
-
end
|
201
|
-
|
202
|
-
yield _to_string(ip_uint)
|
191
|
+
yield _to_string(@addr | i)
|
203
192
|
end
|
204
193
|
|
205
194
|
return self
|
@@ -29,23 +29,23 @@ module Ronin
|
|
29
29
|
#
|
30
30
|
# ip_range = IPRange::Glob.new('10.0.1-3.*/24')
|
31
31
|
# ip_range.each { |ip| puts ip }
|
32
|
+
# # 10.0.1.0
|
32
33
|
# # 10.0.1.1
|
33
|
-
# # 10.0.1.2
|
34
34
|
# # ...
|
35
|
-
# # 10.0.1.253
|
36
35
|
# # 10.0.1.254
|
36
|
+
# # 10.0.1.255
|
37
37
|
# # ...
|
38
|
+
# # 10.0.2.0
|
38
39
|
# # 10.0.2.1
|
39
|
-
# # 10.0.2.2
|
40
40
|
# # ...
|
41
|
-
# # 10.0.2.253
|
42
41
|
# # 10.0.2.254
|
42
|
+
# # 10.0.2.255
|
43
43
|
# # ...
|
44
|
+
# # 10.0.3.0
|
44
45
|
# # 10.0.3.1
|
45
|
-
# # 10.0.3.2
|
46
46
|
# # ...
|
47
|
-
# # 10.0.3.253
|
48
47
|
# # 10.0.3.254
|
48
|
+
# # 10.0.3.255
|
49
49
|
#
|
50
50
|
# @api public
|
51
51
|
#
|
@@ -71,22 +71,25 @@ module Ronin
|
|
71
71
|
|
72
72
|
if @string.include?(':') # IPv6
|
73
73
|
@version = 6
|
74
|
-
@separator = ':'
|
75
74
|
@base = 16
|
76
75
|
@formatter = method(:format_ipv6_address)
|
76
|
+
|
77
|
+
separator = ':'
|
78
|
+
octet_range = (0..0xffff)
|
77
79
|
else # IPv4
|
78
80
|
@version = 4
|
79
|
-
@separator = '.'
|
80
81
|
@base = 10
|
81
82
|
@formatter = method(:format_ipv4_address)
|
83
|
+
|
84
|
+
separator = '.'
|
85
|
+
octet_range = (0..255)
|
82
86
|
end
|
83
87
|
|
84
|
-
@ranges = @string.split(
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
else [segment]
|
88
|
+
@ranges = @string.split(separator).map do |segment|
|
89
|
+
if segment == '*' then octet_range
|
90
|
+
elsif segment.include?(',') then parse_list(segment)
|
91
|
+
elsif segment.include?('-') then parse_range(segment)
|
92
|
+
else [segment]
|
90
93
|
end
|
91
94
|
end
|
92
95
|
end
|
@@ -123,23 +126,23 @@ module Ronin
|
|
123
126
|
#
|
124
127
|
# @example Enumerate through a IPv4 glob range:
|
125
128
|
# IPRange::Glob.each('10.0.1-3.*') { |ip| puts ip }
|
129
|
+
# # 10.0.1.0
|
126
130
|
# # 10.0.1.1
|
127
|
-
# # 10.0.1.2
|
128
131
|
# # ...
|
129
|
-
# # 10.0.1.253
|
130
132
|
# # 10.0.1.254
|
133
|
+
# # 10.0.1.255
|
131
134
|
# # ...
|
135
|
+
# # 10.0.2.0
|
132
136
|
# # 10.0.2.1
|
133
|
-
# # 10.0.2.2
|
134
137
|
# # ...
|
135
|
-
# # 10.0.2.253
|
136
138
|
# # 10.0.2.254
|
139
|
+
# # 10.0.2.255
|
137
140
|
# # ...
|
141
|
+
# # 10.0.3.0
|
138
142
|
# # 10.0.3.1
|
139
|
-
# # 10.0.3.2
|
140
143
|
# # ...
|
141
|
-
# # 10.0.3.253
|
142
144
|
# # 10.0.3.254
|
145
|
+
# # 10.0.3.255
|
143
146
|
#
|
144
147
|
# @example Enumerate through a globbed IPv6 range:
|
145
148
|
# IPRange::Glob.each('::ff::02-0a::c3') { |ip| puts ip }
|
@@ -181,23 +184,23 @@ module Ronin
|
|
181
184
|
# @example Enumerate through a IPv4 glob range:
|
182
185
|
# ip_range = IPRange::Glob.new('10.0.1-3.*')
|
183
186
|
# ip_range.each { |ip| puts ip }
|
187
|
+
# # 10.0.1.0
|
184
188
|
# # 10.0.1.1
|
185
|
-
# # 10.0.1.2
|
186
189
|
# # ...
|
187
|
-
# # 10.0.1.253
|
188
190
|
# # 10.0.1.254
|
191
|
+
# # 10.0.1.255
|
189
192
|
# # ...
|
193
|
+
# # 10.0.2.0
|
190
194
|
# # 10.0.2.1
|
191
|
-
# # 10.0.2.2
|
192
195
|
# # ...
|
193
|
-
# # 10.0.2.253
|
194
196
|
# # 10.0.2.254
|
197
|
+
# # 10.0.2.255
|
195
198
|
# # ...
|
199
|
+
# # 10.0.3.0
|
196
200
|
# # 10.0.3.1
|
197
|
-
# # 10.0.3.2
|
198
201
|
# # ...
|
199
|
-
# # 10.0.3.253
|
200
202
|
# # 10.0.3.254
|
203
|
+
# # 10.0.3.255
|
201
204
|
#
|
202
205
|
# @example Enumerate through a globbed IPv6 range:
|
203
206
|
# ip_range = IPRange::Glob.new('::ff::02-0a::c3')
|
@@ -171,26 +171,14 @@ module Ronin
|
|
171
171
|
# @return [Enumerator]
|
172
172
|
# If no block is given, an Enumerator will be returned.
|
173
173
|
#
|
174
|
-
# @note
|
175
|
-
# This method will skip IPv4 addresses ending in `.0` or `.255`.
|
176
|
-
#
|
177
174
|
# @example
|
178
|
-
# range = IPRange::Range.new('1.1.1.
|
175
|
+
# range = IPRange::Range.new('1.1.1.1','1.1.3.42')
|
179
176
|
# range.each { |ip| puts ip }
|
180
177
|
# # 1.1.1.1
|
181
178
|
# # 1.1.1.2
|
182
179
|
# # ...
|
183
|
-
# # 1.1.
|
184
|
-
# # 1.1.
|
185
|
-
#
|
186
|
-
# @example
|
187
|
-
# range IPRange::Range.new('1.1.1.100','1.1.3.200')
|
188
|
-
# range.each { |ip| puts ip }
|
189
|
-
# # 1.1.1.100
|
190
|
-
# # 1.1.1.101
|
191
|
-
# # ...
|
192
|
-
# # 1.1.3.199
|
193
|
-
# # 1.1.3.200
|
180
|
+
# # 1.1.3.41
|
181
|
+
# # 1.1.3.42
|
194
182
|
#
|
195
183
|
def each
|
196
184
|
return enum_for(__method__) unless block_given?
|
@@ -198,11 +186,6 @@ module Ronin
|
|
198
186
|
ipaddr = @begin.clone
|
199
187
|
|
200
188
|
(@begin_uint..@end_uint).each do |ip_uint|
|
201
|
-
# skip IPv4 addresses ending in .0 or .255
|
202
|
-
if (ipv4? && ((ip_uint & 0xff) == 0 || (ip_uint & 0xff) == 0xff))
|
203
|
-
next
|
204
|
-
end
|
205
|
-
|
206
189
|
ipaddr.send(:set,ip_uint)
|
207
190
|
yield ipaddr.to_s
|
208
191
|
end
|
@@ -41,23 +41,23 @@ module Ronin
|
|
41
41
|
# Enumerating over a IP-glob range:
|
42
42
|
#
|
43
43
|
# IPRange.each('10.0.1-3.*') { |ip| puts ip }
|
44
|
+
# # 10.0.1.0
|
44
45
|
# # 10.0.1.1
|
45
|
-
# # 10.0.1.2
|
46
46
|
# # ...
|
47
|
-
# # 10.0.1.253
|
48
47
|
# # 10.0.1.254
|
48
|
+
# # 10.0.1.255
|
49
49
|
# # ...
|
50
|
+
# # 10.0.2.0
|
50
51
|
# # 10.0.2.1
|
51
|
-
# # 10.0.2.2
|
52
52
|
# # ...
|
53
|
-
# # 10.0.2.253
|
54
53
|
# # 10.0.2.254
|
54
|
+
# # 10.0.2.255
|
55
55
|
# # ...
|
56
|
+
# # 10.0.3.0
|
56
57
|
# # 10.0.3.1
|
57
|
-
# # 10.0.3.2
|
58
58
|
# # ...
|
59
|
-
# # 10.0.3.253
|
60
59
|
# # 10.0.3.254
|
60
|
+
# # 10.0.3.255
|
61
61
|
#
|
62
62
|
# @api public
|
63
63
|
#
|
@@ -126,23 +126,23 @@ module Ronin
|
|
126
126
|
#
|
127
127
|
# @example Enumerating over a IP-glob range:
|
128
128
|
# IPRange.each('10.0.1-3.*') { |ip| puts ip }
|
129
|
+
# # 10.0.1.0
|
129
130
|
# # 10.0.1.1
|
130
|
-
# # 10.0.1.2
|
131
131
|
# # ...
|
132
|
-
# # 10.0.1.253
|
133
132
|
# # 10.0.1.254
|
133
|
+
# # 10.0.1.255
|
134
134
|
# # ...
|
135
|
+
# # 10.0.2.0
|
135
136
|
# # 10.0.2.1
|
136
|
-
# # 10.0.2.2
|
137
137
|
# # ...
|
138
|
-
# # 10.0.2.253
|
139
138
|
# # 10.0.2.254
|
139
|
+
# # 10.0.2.255
|
140
140
|
# # ...
|
141
|
+
# # 10.0.3.0
|
141
142
|
# # 10.0.3.1
|
142
|
-
# # 10.0.3.2
|
143
143
|
# # ...
|
144
|
-
# # 10.0.3.253
|
145
144
|
# # 10.0.3.254
|
145
|
+
# # 10.0.3.255
|
146
146
|
#
|
147
147
|
# @see #each
|
148
148
|
#
|
@@ -181,6 +181,9 @@ module Ronin
|
|
181
181
|
#
|
182
182
|
# @return [String]
|
183
183
|
#
|
184
|
+
# @see CIDR#string
|
185
|
+
# @see Glob#string
|
186
|
+
#
|
184
187
|
def string
|
185
188
|
@range.string
|
186
189
|
end
|
@@ -190,6 +193,9 @@ module Ronin
|
|
190
193
|
#
|
191
194
|
# @return [Boolean]
|
192
195
|
#
|
196
|
+
# @see CIDR#ipv4?
|
197
|
+
# @see Glob#ipv4?
|
198
|
+
#
|
193
199
|
def ipv4?
|
194
200
|
@range.ipv4?
|
195
201
|
end
|
@@ -199,6 +205,9 @@ module Ronin
|
|
199
205
|
#
|
200
206
|
# @return [Boolean]
|
201
207
|
#
|
208
|
+
# @see CIDR#ipv6?
|
209
|
+
# @see Glob#ipv6?
|
210
|
+
#
|
202
211
|
def ipv6?
|
203
212
|
@range.ipv6?
|
204
213
|
end
|
@@ -230,23 +239,23 @@ module Ronin
|
|
230
239
|
# @example Enumerating over a IP-glob range:
|
231
240
|
# ip_range = IPRange.new('10.0.1-3.*')
|
232
241
|
# ip_range.each { |ip| puts ip }
|
242
|
+
# # 10.0.1.0
|
233
243
|
# # 10.0.1.1
|
234
|
-
# # 10.0.1.2
|
235
244
|
# # ...
|
236
|
-
# # 10.0.1.253
|
237
245
|
# # 10.0.1.254
|
246
|
+
# # 10.0.1.255
|
238
247
|
# # ...
|
248
|
+
# # 10.0.2.0
|
239
249
|
# # 10.0.2.1
|
240
|
-
# # 10.0.2.2
|
241
250
|
# # ...
|
242
|
-
# # 10.0.2.253
|
243
251
|
# # 10.0.2.254
|
252
|
+
# # 10.0.2.255
|
244
253
|
# # ...
|
254
|
+
# # 10.0.3.0
|
245
255
|
# # 10.0.3.1
|
246
|
-
# # 10.0.3.2
|
247
256
|
# # ...
|
248
|
-
# # 10.0.3.253
|
249
257
|
# # 10.0.3.254
|
258
|
+
# # 10.0.3.255
|
250
259
|
#
|
251
260
|
# @see CIDR#each
|
252
261
|
# @see Glob#each
|
@@ -108,7 +108,7 @@ module Ronin
|
|
108
108
|
# Path to the CA certificate file or directory.
|
109
109
|
#
|
110
110
|
# @return [OpenSSL::SSL::SSLSocket]
|
111
|
-
#
|
111
|
+
# The new SSL Socket.
|
112
112
|
#
|
113
113
|
# @api public
|
114
114
|
#
|
@@ -246,7 +246,7 @@ module Ronin
|
|
246
246
|
# The new SSL Socket.
|
247
247
|
#
|
248
248
|
# @return [OpenSSL::SSL::SSLSocket, nil]
|
249
|
-
#
|
249
|
+
# The new SSL Socket. If a block is given, then `nil` will be
|
250
250
|
# returned.
|
251
251
|
#
|
252
252
|
# @example
|
@@ -573,7 +573,7 @@ module Ronin
|
|
573
573
|
# Path to the CA certificate file or directory.
|
574
574
|
#
|
575
575
|
# @return [OpenSSL::SSL::SSLSocket]
|
576
|
-
#
|
576
|
+
# The new SSL Socket.
|
577
577
|
#
|
578
578
|
# @api public
|
579
579
|
#
|
@@ -107,7 +107,7 @@ module Ronin
|
|
107
107
|
# Path to the CA certificate file or directory.
|
108
108
|
#
|
109
109
|
# @return [OpenSSL::SSL::SSLSocket]
|
110
|
-
#
|
110
|
+
# The new SSL Socket.
|
111
111
|
#
|
112
112
|
# @api public
|
113
113
|
#
|
@@ -233,7 +233,7 @@ module Ronin
|
|
233
233
|
# The new SSL Socket.
|
234
234
|
#
|
235
235
|
# @return [OpenSSL::SSL::SSLSocket, nil]
|
236
|
-
#
|
236
|
+
# The new SSL Socket. If a block is given, then `nil` will be
|
237
237
|
# returned.
|
238
238
|
#
|
239
239
|
# @example
|
@@ -519,7 +519,7 @@ module Ronin
|
|
519
519
|
# * `:client_once`
|
520
520
|
#
|
521
521
|
# @return [OpenSSL::SSL::SSLSocket]
|
522
|
-
#
|
522
|
+
# The new SSL Socket.
|
523
523
|
#
|
524
524
|
# @api public
|
525
525
|
#
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ronin-support
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Postmodern
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-06-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chars
|
@@ -470,7 +470,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
470
470
|
- !ruby/object:Gem::Version
|
471
471
|
version: '0'
|
472
472
|
requirements: []
|
473
|
-
rubygems_version: 3.3.
|
473
|
+
rubygems_version: 3.3.27
|
474
474
|
signing_key:
|
475
475
|
specification_version: 4
|
476
476
|
summary: A support library for ronin-rb.
|