ronin-exploits 1.0.0.beta2 → 1.0.0
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/README.md +29 -13
- data/gemspec.yml +10 -8
- data/lib/ronin/exploits/cli/commands/new.rb +1 -1
- data/lib/ronin/exploits/cli/commands/run.rb +55 -5
- data/lib/ronin/exploits/exploit.rb +7 -5
- data/lib/ronin/exploits/lfi.rb +1 -1
- data/lib/ronin/exploits/metadata/arch.rb +1 -1
- data/lib/ronin/exploits/metadata/default_filename.rb +1 -1
- data/lib/ronin/exploits/metadata/default_port.rb +1 -1
- data/lib/ronin/exploits/mixins/file_builder.rb +2 -2
- data/lib/ronin/exploits/mixins/nops.rb +1 -1
- data/lib/ronin/exploits/params/base_url.rb +1 -1
- data/lib/ronin/exploits/version.rb +1 -1
- data/ronin-exploits.gemspec +2 -1
- metadata +24 -129
- data/spec/advisory_spec.rb +0 -71
- data/spec/cli/exploit_command_spec.rb +0 -68
- data/spec/cli/exploit_methods_spec.rb +0 -208
- data/spec/cli/ruby_shell_spec.rb +0 -14
- data/spec/client_side_web_vuln_spec.rb +0 -117
- data/spec/exploit_spec.rb +0 -538
- data/spec/exploits_spec.rb +0 -8
- data/spec/heap_overflow_spec.rb +0 -14
- data/spec/lfi_spec.rb +0 -162
- data/spec/loot/file_spec.rb +0 -131
- data/spec/loot_spec.rb +0 -138
- data/spec/memory_corruption_spec.rb +0 -22
- data/spec/metadata/arch_spec.rb +0 -82
- data/spec/metadata/cookie_param_spec.rb +0 -67
- data/spec/metadata/default_filename_spec.rb +0 -62
- data/spec/metadata/default_port_spec.rb +0 -62
- data/spec/metadata/header_name_spec.rb +0 -67
- data/spec/metadata/os_spec.rb +0 -164
- data/spec/metadata/shouts_spec.rb +0 -100
- data/spec/metadata/url_path_spec.rb +0 -67
- data/spec/metadata/url_query_param_spec.rb +0 -67
- data/spec/mixins/binary_spec.rb +0 -129
- data/spec/mixins/build_dir.rb +0 -66
- data/spec/mixins/file_builder_spec.rb +0 -67
- data/spec/mixins/format_string_spec.rb +0 -44
- data/spec/mixins/has_payload_spec.rb +0 -333
- data/spec/mixins/has_targets_spec.rb +0 -434
- data/spec/mixins/html_spec.rb +0 -772
- data/spec/mixins/http_spec.rb +0 -1227
- data/spec/mixins/loot_spec.rb +0 -20
- data/spec/mixins/nops_spec.rb +0 -165
- data/spec/mixins/remote_tcp_spec.rb +0 -217
- data/spec/mixins/remote_udp_spec.rb +0 -217
- data/spec/mixins/seh_spec.rb +0 -89
- data/spec/mixins/stack_overflow_spec.rb +0 -87
- data/spec/mixins/text_spec.rb +0 -43
- data/spec/open_redirect_spec.rb +0 -71
- data/spec/params/base_url_spec.rb +0 -71
- data/spec/params/bind_host_spec.rb +0 -34
- data/spec/params/bind_port_spec.rb +0 -35
- data/spec/params/filename_spec.rb +0 -77
- data/spec/params/host_spec.rb +0 -34
- data/spec/params/port_spec.rb +0 -77
- data/spec/rfi_spec.rb +0 -107
- data/spec/seh_overflow_spec.rb +0 -18
- data/spec/spec_helper.rb +0 -8
- data/spec/sqli_spec.rb +0 -306
- data/spec/ssti_spec.rb +0 -121
- data/spec/stack_overflow_spec.rb +0 -18
- data/spec/target_spec.rb +0 -92
- data/spec/test_result_spec.rb +0 -32
- data/spec/use_after_free_spec.rb +0 -14
- data/spec/web_spec.rb +0 -12
- data/spec/web_vuln_spec.rb +0 -854
- data/spec/xss_spec.rb +0 -69
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f4fb437a6634a2eef3dae27f5d940718e94d1e5d7839113e9b02d849daeb2f81
|
4
|
+
data.tar.gz: 661bbae01973ba0ec2e367abef7fd137534dff1597b8486dde94e64afcc6e780
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c40d3ba6b13842ddb66b762cac6aaa26a22f3feb03a8f68abf1fdc7d90696fb4cc03da0fd4472ea77af9e861eb92cf4a7165a5fc023b4ecb4e59f0ef13fa234
|
7
|
+
data.tar.gz: 8b81f266e3b256f028a01b1d10a85d0d1d09cfbcdfecab07e5bf25ebae0f96adee5b7881515eb4cfaccae5ae0e4807377315f50db9213ab5268b179db3e87640
|
data/.github/workflows/ruby.yml
CHANGED
data/README.md
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
[](https://github.com/ronin-rb/ronin-exploits/actions/workflows/ruby.yml)
|
4
4
|
[](https://codeclimate.com/github/ronin-rb/ronin-exploits)
|
5
|
+
[](https://badge.fury.io/rb/ronin-exploits)
|
5
6
|
|
6
7
|
* [Source](https://github.com/ronin-rb/ronin-exploits)
|
7
8
|
* [Issues](https://github.com/ronin-rb/ronin-exploits/issues)
|
@@ -17,27 +18,30 @@ ronin-exploits allows one to write exploits as plain old Ruby classes.
|
|
17
18
|
ronin-exploits can be distributed as Ruby files or as git repositories that can
|
18
19
|
be installed using [ronin-repos].
|
19
20
|
|
21
|
+
**tl;dr** It's like a simpler and more modular version of
|
22
|
+
[Metasploit](https://www.metasploit.com/).
|
23
|
+
|
20
24
|
ronin-exploits is part of the [ronin-rb] project, a [Ruby] toolkit for security
|
21
25
|
research and development.
|
22
26
|
|
23
27
|
## Features
|
24
28
|
|
25
|
-
* Provides a succinct syntax and API for writing
|
26
|
-
possible.
|
27
|
-
* Supports defining exploits as plain old Ruby classes.
|
29
|
+
* Provides a succinct [syntax](#examples) and [API][docs-exploit] for writing
|
30
|
+
exploits in as few lines as possible.
|
31
|
+
* Supports [defining exploits as plain old Ruby classes][docs-exploit].
|
28
32
|
* Supports loading exploits from Ruby files or from installed 3rd-party
|
29
33
|
git repositories.
|
30
34
|
* Provides base classes and mixin modules for a variety of exploit types:
|
31
|
-
* Stack Overflows
|
32
|
-
* SEH Overflows
|
33
|
-
* Heap Overflows
|
34
|
-
* Use After Free (UAF)
|
35
|
-
* Open Redirect
|
36
|
-
* Local File Inclusions (LFI)
|
37
|
-
* Remote File Inclusions (RFI)
|
38
|
-
* SQL injections (SQLi)
|
39
|
-
* Cross-Site Scripting (XSS)
|
40
|
-
* Server-Side Template Injection (SSTI)
|
35
|
+
* [Stack Overflows][docs-stack-overflow]
|
36
|
+
* [SEH Overflows][docs-seh-overflow]
|
37
|
+
* [Heap Overflows][docs-heap-overflow]
|
38
|
+
* [Use After Free (UAF)][docs-use-after-free]
|
39
|
+
* [Open Redirect][docs-open-redirect]
|
40
|
+
* [Local File Inclusions (LFI)][docs-lfi]
|
41
|
+
* [Remote File Inclusions (RFI)][docs-rfi]
|
42
|
+
* [SQL injections (SQLi)][docs-sqli]
|
43
|
+
* [Cross-Site Scripting (XSS)][docs-xss]
|
44
|
+
* [Server-Side Template Injection (SSTI)][docs-ssti]
|
41
45
|
* Uses the [ronin-payloads] library for exploit payloads.
|
42
46
|
* Uses the [ronin-post_ex] library for post-exploitation.
|
43
47
|
* Provides a simple CLI for listing, displaying, running, and generating new
|
@@ -46,6 +50,18 @@ research and development.
|
|
46
50
|
* Has 86% documentation coverage.
|
47
51
|
* Small memory footprint (~47Kb).
|
48
52
|
|
53
|
+
[docs-exploit]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/Exploit.html
|
54
|
+
[docs-stack-overflow]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/StackOverflow.html
|
55
|
+
[docs-seh-overflow]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/SEHOverflow.html
|
56
|
+
[docs-heap-overflow]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/HeapOverflow.html
|
57
|
+
[docs-use-after-free]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/UseAfterFree.html
|
58
|
+
[docs-open-redirect]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/OpenRedirect.html
|
59
|
+
[docs-lfi]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/LFI.html
|
60
|
+
[docs-rfi]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/RFI.html
|
61
|
+
[docs-sqli]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/SQLI.html
|
62
|
+
[docs-xss]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/XSS.html
|
63
|
+
[docs-ssti]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/SSTI.html
|
64
|
+
|
49
65
|
## Anti-Features
|
50
66
|
|
51
67
|
* No magic: exploits are defined as classes in files.
|
data/gemspec.yml
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
name: ronin-exploits
|
2
2
|
summary: A Ruby micro-framework for writing and running exploits and payloads.
|
3
|
-
description:
|
3
|
+
description: |
|
4
4
|
ronin-exploits is a Ruby micro-framework for writing and running exploits.
|
5
5
|
ronin-exploits allows one to write exploits as plain old Ruby classes.
|
6
6
|
ronin-exploits can be distributed as Ruby files or as git repositories that
|
7
7
|
can be installed using ronin-reps.
|
8
8
|
|
9
|
+
It's like a simpler version of Metasploit.
|
10
|
+
|
9
11
|
license: LGPL-3.0
|
10
12
|
authors: Postmodern
|
11
13
|
email: postmodern.mod3@gmail.com
|
@@ -32,13 +34,13 @@ generated_files:
|
|
32
34
|
dependencies:
|
33
35
|
uri-query_params: ~> 0.6
|
34
36
|
# Ronin dependencies:
|
35
|
-
ronin-support: ~> 1.0
|
36
|
-
ronin-code-sql: ~> 2.0
|
37
|
-
ronin-payloads: ~> 0.1
|
38
|
-
ronin-vulns: ~> 0.1
|
39
|
-
ronin-post_ex: ~> 0.1
|
40
|
-
ronin-core: ~> 0.1
|
41
|
-
ronin-repos: ~> 0.1
|
37
|
+
ronin-support: ~> 1.0
|
38
|
+
ronin-code-sql: ~> 2.0
|
39
|
+
ronin-payloads: ~> 0.1
|
40
|
+
ronin-vulns: ~> 0.1
|
41
|
+
ronin-post_ex: ~> 0.1
|
42
|
+
ronin-core: ~> 0.1
|
43
|
+
ronin-repos: ~> 0.1
|
42
44
|
|
43
45
|
development_dependencies:
|
44
46
|
bundler: ~> 2.0
|
@@ -118,7 +118,11 @@ module Ronin
|
|
118
118
|
type: /\A[^=\s]+=.+\z/,
|
119
119
|
usage: 'NAME=VALUE'
|
120
120
|
},
|
121
|
-
desc: 'Sets a param on the payload'
|
121
|
+
desc: 'Sets a param on the payload' do |param|
|
122
|
+
name, value = param.split('=',2)
|
123
|
+
|
124
|
+
@payload_params[name.to_sym] = value
|
125
|
+
end
|
122
126
|
|
123
127
|
# Encoder options
|
124
128
|
option :encoder_file, value: {
|
@@ -228,6 +232,7 @@ module Ronin
|
|
228
232
|
|
229
233
|
@load_encoders = []
|
230
234
|
@encoder_params = Hash.new { |hash,key| hash[key] = {} }
|
235
|
+
@payload_params = {}
|
231
236
|
@target_kwargs = {}
|
232
237
|
end
|
233
238
|
|
@@ -244,6 +249,7 @@ module Ronin
|
|
244
249
|
load_payload
|
245
250
|
initialize_encoders
|
246
251
|
initialize_payload
|
252
|
+
validate_payload
|
247
253
|
initialize_exploit
|
248
254
|
validate_exploit
|
249
255
|
run_exploit
|
@@ -257,6 +263,10 @@ module Ronin
|
|
257
263
|
perform_cleanup
|
258
264
|
end
|
259
265
|
|
266
|
+
#
|
267
|
+
# Loads the payload encoder classes specified by `--encoder` or
|
268
|
+
# `--encoder-file`.
|
269
|
+
#
|
260
270
|
def load_encoders
|
261
271
|
@encoder_classes = @load_encoders.map do |(type,value)|
|
262
272
|
case type
|
@@ -266,12 +276,20 @@ module Ronin
|
|
266
276
|
end
|
267
277
|
end
|
268
278
|
|
279
|
+
#
|
280
|
+
# Initializes the payload encoders specified by `--encoder` or
|
281
|
+
# `--encoder-file`.
|
282
|
+
#
|
269
283
|
def initialize_encoders
|
270
284
|
@encoders = @encoder_classes.map do |encoder_class|
|
271
285
|
encoder_class.new(params: @encoder_params[encoder_class.id])
|
272
286
|
end
|
273
287
|
end
|
274
288
|
|
289
|
+
#
|
290
|
+
# Loads the payload class specified by `--payload` or
|
291
|
+
# `--payload-file`.
|
292
|
+
#
|
275
293
|
def load_payload
|
276
294
|
@payload_class = if options[:payload]
|
277
295
|
super(options[:payload])
|
@@ -280,6 +298,10 @@ module Ronin
|
|
280
298
|
end
|
281
299
|
end
|
282
300
|
|
301
|
+
#
|
302
|
+
# Initializes the payload specified by `--payload`, `--payload-file`,
|
303
|
+
# `--read-payload`, or `--payload-string`.
|
304
|
+
#
|
283
305
|
def initialize_payload
|
284
306
|
@payload = if @payload_class
|
285
307
|
super(@payload_class, params: @payload_params,
|
@@ -291,6 +313,16 @@ module Ronin
|
|
291
313
|
end
|
292
314
|
end
|
293
315
|
|
316
|
+
#
|
317
|
+
# Validates the payload.
|
318
|
+
#
|
319
|
+
def validate_payload
|
320
|
+
super(@payload)
|
321
|
+
end
|
322
|
+
|
323
|
+
#
|
324
|
+
# Initializes the exploit.
|
325
|
+
#
|
294
326
|
def initialize_exploit
|
295
327
|
kwargs = {params: @params}
|
296
328
|
|
@@ -309,13 +341,16 @@ module Ronin
|
|
309
341
|
super(**kwargs)
|
310
342
|
end
|
311
343
|
|
344
|
+
#
|
345
|
+
# Runs the exploit.
|
346
|
+
#
|
312
347
|
def run_exploit
|
313
348
|
log_info "Running exploit #{@exploit.class_id} ..."
|
314
349
|
|
315
350
|
begin
|
316
351
|
@exploit.exploit(dry_run: options[:dry_run])
|
317
352
|
rescue ExploitError => error
|
318
|
-
print_error
|
353
|
+
print_error "failed to run exploit #{@exploit.class_id}: #{error.message}"
|
319
354
|
exit(1)
|
320
355
|
rescue => error
|
321
356
|
print_exception(error)
|
@@ -324,6 +359,9 @@ module Ronin
|
|
324
359
|
end
|
325
360
|
end
|
326
361
|
|
362
|
+
#
|
363
|
+
# Starts an interactive ruby shell within the exploit object.
|
364
|
+
#
|
327
365
|
def start_shell
|
328
366
|
log_info "Exploit #{@exploit.class_id} launched!"
|
329
367
|
log_info "Starting interactive Ruby shell ..."
|
@@ -331,12 +369,15 @@ module Ronin
|
|
331
369
|
RubyShell.start(name: @exploit_class.name, context: @exploit)
|
332
370
|
end
|
333
371
|
|
372
|
+
#
|
373
|
+
# Performs the post-exploitation stage.
|
374
|
+
#
|
334
375
|
def post_exploitation
|
335
376
|
if @exploit_class.include?(Mixins::HasPayload) &&
|
336
377
|
@exploit.payload.kind_of?(Ronin::Payloads::Payload) &&
|
337
|
-
@exploit.payload.kind_of?(Ronin::Payloads::Mixins::
|
378
|
+
@exploit.payload.kind_of?(Ronin::Payloads::Mixins::PostEx)
|
338
379
|
unless @exploit.payload.session
|
339
|
-
print_error
|
380
|
+
print_error "payload (#{@exploit.payload.class_id}) did not create a post-exploitation session"
|
340
381
|
|
341
382
|
perform_cleanup
|
342
383
|
eixt(1)
|
@@ -349,6 +390,9 @@ module Ronin
|
|
349
390
|
end
|
350
391
|
end
|
351
392
|
|
393
|
+
#
|
394
|
+
# Prints any loot collected by the exploit.
|
395
|
+
#
|
352
396
|
def print_loot
|
353
397
|
unless @exploit.loot.empty?
|
354
398
|
log_info "Exploit found the following loot:"
|
@@ -372,15 +416,21 @@ module Ronin
|
|
372
416
|
end
|
373
417
|
end
|
374
418
|
|
419
|
+
#
|
420
|
+
# Saves the collected loot to the `--save-loot` directory.
|
421
|
+
#
|
375
422
|
def save_loot
|
376
423
|
@exploit.loot.save(options.fetch(:save_loot))
|
377
424
|
end
|
378
425
|
|
426
|
+
#
|
427
|
+
# Performs the cleanup stage of the exploit.
|
428
|
+
#
|
379
429
|
def perform_cleanup
|
380
430
|
begin
|
381
431
|
@exploit.perform_cleanup
|
382
432
|
rescue ExploitError => error
|
383
|
-
print_error
|
433
|
+
print_error "failed to cleanup exploit #{@exploit.class_id}: #{error.message}"
|
384
434
|
exit(1)
|
385
435
|
rescue => error
|
386
436
|
print_exception(error)
|
@@ -52,7 +52,7 @@ module Ronin
|
|
52
52
|
# The {Exploit} class defines six key parts:
|
53
53
|
#
|
54
54
|
# 1. Metadata - defines information about the exploit.
|
55
|
-
# 2. Params - user configurable parameters.
|
55
|
+
# 2. [Params] - user configurable parameters.
|
56
56
|
# 3. {Exploit#test test} - optional method that tests whether the target is
|
57
57
|
# vulnerable or not.
|
58
58
|
# 4. {Exploit#build build} - method which builds the exploit.
|
@@ -60,6 +60,8 @@ module Ronin
|
|
60
60
|
# 6. {Exploit#cleanup cleanup} - optional Method which performs additional
|
61
61
|
# cleanup steps.
|
62
62
|
#
|
63
|
+
# [Params]: https://ronin-rb.dev/docs/ronin-core/Ronin/Core/Params/Mixin.html
|
64
|
+
#
|
63
65
|
# ## Example
|
64
66
|
#
|
65
67
|
# require 'ronin/exploits/exploit'
|
@@ -136,7 +138,7 @@ module Ronin
|
|
136
138
|
#
|
137
139
|
# ### description
|
138
140
|
#
|
139
|
-
# Defines a longer multi-paragraph
|
141
|
+
# Defines a longer multi-paragraph description of the exploit.
|
140
142
|
#
|
141
143
|
# description <<~EOS
|
142
144
|
# This is my first exploit.
|
@@ -313,7 +315,7 @@ module Ronin
|
|
313
315
|
end
|
314
316
|
|
315
317
|
#
|
316
|
-
# Determines whether the exploit has been
|
318
|
+
# Determines whether the exploit has been publicly released yet.
|
317
319
|
#
|
318
320
|
# @return [Boolean]
|
319
321
|
#
|
@@ -526,7 +528,7 @@ module Ronin
|
|
526
528
|
end
|
527
529
|
|
528
530
|
#
|
529
|
-
# Builds the exploit and then
|
531
|
+
# Builds the exploit and then launches the exploit.
|
530
532
|
#
|
531
533
|
# @param [Boolean] dry_run
|
532
534
|
# If `true` performs a dry-run by only calling {#build} and **not**
|
@@ -633,7 +635,7 @@ module Ronin
|
|
633
635
|
end
|
634
636
|
|
635
637
|
#
|
636
|
-
# Place holder method for testing whether the
|
638
|
+
# Place holder method for testing whether the target is vulnerable.
|
637
639
|
#
|
638
640
|
# @return [Test::Vulnerable, Test::NotVulnerable, Test::Unknown]
|
639
641
|
#
|
data/lib/ronin/exploits/lfi.rb
CHANGED
@@ -73,7 +73,7 @@ module Ronin
|
|
73
73
|
# Gets or sets the directory traversal depth for the LFI vulnerability.
|
74
74
|
#
|
75
75
|
# @param [Integer, nil] new_depth
|
76
|
-
# The optional new directory
|
76
|
+
# The optional new directory traversal depth to set.
|
77
77
|
#
|
78
78
|
# @return [Integer]
|
79
79
|
# The LFI vulnerability's directory traverse depth.
|
@@ -40,7 +40,7 @@ module Ronin
|
|
40
40
|
|
41
41
|
module ClassMethods
|
42
42
|
#
|
43
|
-
# Gets or sets the
|
43
|
+
# Gets or sets the exploit's targeted architecture.
|
44
44
|
#
|
45
45
|
# @param [:x86, :x86_64, :ia64, :amd64, :ppc, :ppc64, :mips, :mips_le, :mips_be, :mips64, :mips64_le, :mips64_be, :arm, :arm_le, :arm_be, :arm64, :arm64_le, :arm64_be, nil] new_arch
|
46
46
|
# The optional new architecture to set.
|
@@ -24,8 +24,8 @@ module Ronin
|
|
24
24
|
module Exploits
|
25
25
|
module Mixins
|
26
26
|
#
|
27
|
-
# Adds methods for building exploit files. Also adds a `
|
28
|
-
#
|
27
|
+
# Adds methods for building exploit files. Also adds a `filename` param
|
28
|
+
# and a
|
29
29
|
# {Metadata::DefaultFilename::ClassMethods#default_filename default_filename}
|
30
30
|
# class method.
|
31
31
|
#
|
data/ronin-exploits.gemspec
CHANGED
@@ -27,6 +27,8 @@ Gem::Specification.new do |gem|
|
|
27
27
|
gem.files = `git ls-files`.split($/)
|
28
28
|
gem.files = glob[gemspec['files']] if gemspec['files']
|
29
29
|
gem.files += Array(gemspec['generated_files'])
|
30
|
+
# exclude test files from the packages gem
|
31
|
+
gem.files -= glob[gemspec['test_files'] || 'spec/{**/}*']
|
30
32
|
|
31
33
|
gem.executables = gemspec.fetch('executables') do
|
32
34
|
glob['bin/*'].map { |path| File.basename(path) }
|
@@ -34,7 +36,6 @@ Gem::Specification.new do |gem|
|
|
34
36
|
gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
|
35
37
|
|
36
38
|
gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
|
37
|
-
gem.test_files = glob[gemspec['test_files'] || 'spec/{**/}*_spec.rb']
|
38
39
|
gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
|
39
40
|
|
40
41
|
gem.require_paths = Array(gemspec.fetch('require_paths') {
|