ronin-exploits 1.0.0.beta2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![CI](https://github.com/ronin-rb/ronin-exploits/actions/workflows/ruby.yml/badge.svg)](https://github.com/ronin-rb/ronin-exploits/actions/workflows/ruby.yml)
|
4
4
|
[![Code Climate](https://codeclimate.com/github/ronin-rb/ronin-exploits.svg)](https://codeclimate.com/github/ronin-rb/ronin-exploits)
|
5
|
+
[![Gem Version](https://badge.fury.io/rb/ronin-exploits.svg)](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') {
|