asciidoctor 1.5.6.2 → 1.5.7

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of asciidoctor might be problematic. Click here for more details.

Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +330 -143
  3. data/README-fr.adoc +441 -0
  4. data/README-jp.adoc +418 -0
  5. data/README-zh_CN.adoc +430 -0
  6. data/README.adoc +454 -0
  7. data/Rakefile +57 -0
  8. data/asciidoctor.gemspec +7 -1
  9. data/data/locale/attributes-ar.adoc +22 -0
  10. data/data/locale/attributes-bg.adoc +22 -0
  11. data/data/locale/attributes-ca.adoc +22 -0
  12. data/data/locale/attributes-cs.adoc +22 -0
  13. data/data/locale/attributes-da.adoc +22 -0
  14. data/data/locale/attributes-de.adoc +22 -0
  15. data/data/locale/attributes-en.adoc +23 -0
  16. data/data/locale/attributes-es.adoc +22 -0
  17. data/data/locale/attributes-fa.adoc +22 -0
  18. data/data/locale/attributes-fi.adoc +22 -0
  19. data/data/locale/attributes-fr.adoc +22 -0
  20. data/data/locale/attributes-hu.adoc +22 -0
  21. data/data/locale/attributes-id.adoc +22 -0
  22. data/data/locale/attributes-it.adoc +22 -0
  23. data/data/locale/attributes-ja.adoc +22 -0
  24. data/data/locale/attributes-kr.adoc +22 -0
  25. data/data/locale/attributes-nb.adoc +22 -0
  26. data/data/locale/attributes-nl.adoc +22 -0
  27. data/data/locale/attributes-nn.adoc +22 -0
  28. data/data/locale/attributes-pl.adoc +22 -0
  29. data/data/locale/attributes-pt.adoc +22 -0
  30. data/data/locale/attributes-pt_BR.adoc +22 -0
  31. data/data/locale/attributes-ro.adoc +22 -0
  32. data/data/locale/attributes-ru.adoc +22 -0
  33. data/data/locale/attributes-sr.adoc +22 -0
  34. data/data/locale/attributes-sr_Latn.adoc +22 -0
  35. data/data/locale/attributes-tr.adoc +22 -0
  36. data/data/locale/attributes-uk.adoc +22 -0
  37. data/data/locale/attributes-zh_CN.adoc +22 -0
  38. data/data/locale/attributes-zh_TW.adoc +22 -0
  39. data/data/locale/attributes.adoc +8 -649
  40. data/data/stylesheets/asciidoctor-default.css +77 -72
  41. data/features/xref.feature +366 -7
  42. data/lib/asciidoctor.rb +107 -93
  43. data/lib/asciidoctor/abstract_block.rb +247 -239
  44. data/lib/asciidoctor/abstract_node.rb +56 -58
  45. data/lib/asciidoctor/block.rb +3 -3
  46. data/lib/asciidoctor/callouts.rb +1 -1
  47. data/lib/asciidoctor/cli/invoker.rb +36 -9
  48. data/lib/asciidoctor/cli/options.rb +63 -25
  49. data/lib/asciidoctor/converter.rb +23 -13
  50. data/lib/asciidoctor/converter/base.rb +4 -0
  51. data/lib/asciidoctor/converter/docbook45.rb +16 -9
  52. data/lib/asciidoctor/converter/docbook5.rb +115 -97
  53. data/lib/asciidoctor/converter/factory.rb +29 -31
  54. data/lib/asciidoctor/converter/html5.rb +229 -192
  55. data/lib/asciidoctor/converter/manpage.rb +72 -50
  56. data/lib/asciidoctor/converter/template.rb +12 -12
  57. data/lib/asciidoctor/core_ext.rb +5 -1
  58. data/lib/asciidoctor/core_ext/1.8.7/base64/strict_encode64.rb +6 -0
  59. data/lib/asciidoctor/document.rb +168 -77
  60. data/lib/asciidoctor/extensions.rb +79 -47
  61. data/lib/asciidoctor/helpers.rb +33 -11
  62. data/lib/asciidoctor/inline.rb +3 -2
  63. data/lib/asciidoctor/list.rb +2 -1
  64. data/lib/asciidoctor/logging.rb +122 -0
  65. data/lib/asciidoctor/parser.rb +406 -382
  66. data/lib/asciidoctor/path_resolver.rb +169 -162
  67. data/lib/asciidoctor/reader.rb +166 -121
  68. data/lib/asciidoctor/section.rb +45 -28
  69. data/lib/asciidoctor/stylesheets.rb +13 -5
  70. data/lib/asciidoctor/substitutors.rb +328 -254
  71. data/lib/asciidoctor/table.rb +105 -48
  72. data/lib/asciidoctor/timings.rb +34 -6
  73. data/lib/asciidoctor/version.rb +1 -1
  74. data/man/asciidoctor.1 +41 -23
  75. data/man/asciidoctor.adoc +14 -8
  76. data/test/api_test.rb +1004 -0
  77. data/test/attributes_test.rb +241 -50
  78. data/test/blocks_test.rb +549 -124
  79. data/test/converter_test.rb +170 -78
  80. data/test/document_test.rb +208 -767
  81. data/test/extensions_test.rb +188 -53
  82. data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +1 -1
  83. data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +1 -1
  84. data/test/fixtures/file-with-missing-include.adoc +1 -0
  85. data/test/fixtures/include-file.jsx +8 -0
  86. data/test/fixtures/lists.adoc +96 -0
  87. data/test/fixtures/other-chapters.adoc +11 -0
  88. data/test/fixtures/outer-include.adoc +5 -0
  89. data/test/fixtures/sample.asciidoc +5 -1
  90. data/test/fixtures/subdir/index.adoc +3 -0
  91. data/test/fixtures/subdir/inner-include.adoc +3 -0
  92. data/test/fixtures/subdir/middle-include.adoc +5 -0
  93. data/test/fixtures/tagged-class-enclosed.rb +0 -1
  94. data/test/fixtures/unclosed-tag.adoc +3 -0
  95. data/test/fixtures/unexpected-end-tag.adoc +4 -0
  96. data/test/invoker_test.rb +101 -40
  97. data/test/links_test.rb +266 -72
  98. data/test/lists_test.rb +243 -45
  99. data/test/logger_test.rb +211 -0
  100. data/test/manpage_test.rb +124 -6
  101. data/test/options_test.rb +46 -1
  102. data/test/paragraphs_test.rb +23 -10
  103. data/test/parser_test.rb +30 -1
  104. data/test/paths_test.rb +115 -33
  105. data/test/preamble_test.rb +1 -1
  106. data/test/reader_test.rb +337 -81
  107. data/test/sections_test.rb +656 -72
  108. data/test/substitutions_test.rb +182 -57
  109. data/test/tables_test.rb +324 -57
  110. data/test/test_helper.rb +77 -32
  111. data/test/text_test.rb +7 -7
  112. metadata +67 -3
@@ -7,7 +7,7 @@ module Asciidoctor
7
7
  # The main emphasis of the class is on creating clean and secure paths. Clean
8
8
  # paths are void of duplicate parent and current directory references in the
9
9
  # path name. Secure paths are paths which are restricted from accessing
10
- # directories outside of a jail root, if specified.
10
+ # directories outside of a jail path, if specified.
11
11
  #
12
12
  # Since joining two paths can result in an insecure path, this class also
13
13
  # handles the task of joining a parent (start) and child (target) path.
@@ -94,13 +94,15 @@ module Asciidoctor
94
94
  # => '/path/to/docs/images'
95
95
  #
96
96
  # begin
97
- # resolver.system_path('images', '/etc', '/path/to/docs')
97
+ # resolver.system_path('images', '/etc', '/path/to/docs', recover: false)
98
98
  # rescue SecurityError => e
99
99
  # puts e.message
100
100
  # end
101
- # => Start path /etc is outside of jail: /path/to/docs'
101
+ # => start path /etc is outside of jail: /path/to/docs'
102
102
  #
103
103
  class PathResolver
104
+ include Logging
105
+
104
106
  DOT = '.'
105
107
  DOT_DOT = '..'
106
108
  DOT_SLASH = './'
@@ -118,17 +120,14 @@ class PathResolver
118
120
  # expanded to an absolute path inside the constructor.
119
121
  #
120
122
  # file_separator - the String file separator to use for path operations
121
- # (optional, default: File::SEPARATOR)
123
+ # (optional, default: File::ALT_SEPARATOR or File::SEPARATOR)
122
124
  # working_dir - the String working directory (optional, default: Dir.pwd)
123
125
  #
124
126
  def initialize file_separator = nil, working_dir = nil
125
- @file_separator = file_separator ? file_separator : (::File::ALT_SEPARATOR || ::File::SEPARATOR)
126
- if working_dir
127
- @working_dir = (root? working_dir) ? working_dir : (::File.expand_path working_dir)
128
- else
129
- @working_dir = ::File.expand_path ::Dir.pwd
130
- end
131
- @_partition_path_sys, @_partition_path_web = {}, {}
127
+ @file_separator = file_separator || ::File::ALT_SEPARATOR || ::File::SEPARATOR
128
+ @working_dir = working_dir ? ((root? working_dir) ? (posixify working_dir) : (::File.expand_path working_dir)) : ::Dir.pwd
129
+ @_partition_path_sys = {}
130
+ @_partition_path_web = {}
132
131
  end
133
132
 
134
133
  # Public: Check whether the specified path is an absolute path.
@@ -196,7 +195,26 @@ class PathResolver
196
195
  #
197
196
  # returns If path descends from base, return the offset, otherwise false.
198
197
  def descends_from? path, base
199
- base == path ? 0 : ((path.start_with? base + '/') ? base.length + 1 : false)
198
+ if base == path
199
+ 0
200
+ elsif base == SLASH
201
+ (path.start_with? SLASH) && 1
202
+ else
203
+ (path.start_with? base + SLASH) && (base.length + 1)
204
+ end
205
+ end
206
+
207
+ # Public: Calculate the relative path to this absolute path from the specified base directory
208
+ #
209
+ # If neither path or base are absolute paths, or the path is not contained
210
+ # within the base directory, no work is done.
211
+ #
212
+ # path - [String] an absolute filename.
213
+ # base - [String] an absolute base directory.
214
+ #
215
+ # Return the [String] relative path of the specified path calculated from the base directory.
216
+ def relative_path path, base
217
+ (root? path) && (offset = descends_from? path, base) ? (path.slice offset, path.length) : path
200
218
  end
201
219
 
202
220
  # Public: Normalize path by converting any backslashes to forward slashes
@@ -205,45 +223,46 @@ class PathResolver
205
223
  #
206
224
  # returns a String path with any backslashes replaced with forward slashes
207
225
  def posixify path
208
- if path.nil_or_empty?
209
- ''
210
- elsif path.include? BACKSLASH
211
- path.tr BACKSLASH, SLASH
226
+ if path
227
+ @file_separator == BACKSLASH && (path.include? BACKSLASH) ? (path.tr BACKSLASH, SLASH) : path
212
228
  else
213
- path
229
+ ''
214
230
  end
215
231
  end
216
232
  alias posixfy posixify
217
233
 
218
- # Public: Expand the path by resolving any parent references (..)
219
- # and cleaning self references (.).
220
- #
221
- # The result will be relative if the path is relative and
222
- # absolute if the path is absolute. The file separator used
223
- # in the expanded path is the one specified when the class
224
- # was constructed.
234
+ # Public: Expand the specified path by converting the path to a posix path, resolving parent
235
+ # references (..), and removing self references (.).
225
236
  #
226
237
  # path - the String path to expand
227
238
  #
228
- # returns a String path with any parent or self references resolved.
239
+ # returns a String path as a posix path with parent references resolved and self references removed.
240
+ # The result will be relative if the path is relative and absolute if the path is absolute.
229
241
  def expand_path path
230
- path_segments, path_root, _ = partition_path path
231
- join_path path_segments, path_root
242
+ path_segments, path_root = partition_path path
243
+ if path.include? DOT_DOT
244
+ resolved_segments = []
245
+ path_segments.each do |segment|
246
+ segment == DOT_DOT ? resolved_segments.pop : resolved_segments << segment
247
+ end
248
+ join_path resolved_segments, path_root
249
+ else
250
+ join_path path_segments, path_root
251
+ end
232
252
  end
233
253
 
234
- # Public: Partition the path into path segments and remove any empty segments
235
- # or segments that are self references (.). The path is converted to a posix
236
- # path before being partitioned.
254
+ # Public: Partition the path into path segments and remove self references (.) and the trailing
255
+ # slash, if present. Prior to being partitioned, the path is converted to a posix path.
256
+ #
257
+ # Parent references are not resolved by this method since the consumer often needs to handle this
258
+ # resolution in a certain context (checking for the breach of a jail, for instance).
237
259
  #
238
260
  # path - the String path to partition
239
261
  # web - a Boolean indicating whether the path should be handled
240
262
  # as a web path (optional, default: false)
241
263
  #
242
- # Returns a 3-item Array containing the Array of String path segments, the
243
- # path root (e.g., '/', './', 'c:/') if the path is absolute and the posix
244
- # version of the path.
245
- #--
246
- # QUESTION is it worth it to normalize slashes? it doubles the time elapsed
264
+ # Returns a 2-item Array containing the Array of String path segments and the
265
+ # path root (e.g., '/', './', 'c:/', or '//'), which is nil unless the path is absolute.
247
266
  def partition_path path, web = nil
248
267
  if (result = (cache = web ? @_partition_path_web : @_partition_path_sys)[path])
249
268
  return result
@@ -251,56 +270,36 @@ class PathResolver
251
270
 
252
271
  posix_path = posixify path
253
272
 
254
- root = if web
273
+ if web
255
274
  # ex. /sample/path
256
275
  if web_root? posix_path
257
- SLASH
276
+ root = SLASH
258
277
  # ex. ./sample/path
259
278
  elsif posix_path.start_with? DOT_SLASH
260
- DOT_SLASH
261
- # ex. sample/path
262
- else
263
- nil
279
+ root = DOT_SLASH
280
+ # else ex. sample/path
264
281
  end
265
- else
266
- if root? posix_path
267
- # ex. //sample/path
268
- if unc? posix_path
269
- DOUBLE_SLASH
270
- # ex. /sample/path
271
- elsif posix_path.start_with? SLASH
272
- SLASH
273
- # ex. C:/sample/path (or file:///sample/path in browser environment)
274
- else
275
- posix_path.slice 0, (posix_path.index SLASH) + 1
276
- end
277
- # ex. ./sample/path
278
- elsif posix_path.start_with? DOT_SLASH
279
- DOT_SLASH
280
- # ex. sample/path
282
+ elsif root? posix_path
283
+ # ex. //sample/path
284
+ if unc? posix_path
285
+ root = DOUBLE_SLASH
286
+ # ex. /sample/path
287
+ elsif posix_path.start_with? SLASH
288
+ root = SLASH
289
+ # ex. C:/sample/path (or file:///sample/path in browser environment)
281
290
  else
282
- nil
291
+ root = posix_path.slice 0, (posix_path.index SLASH) + 1
283
292
  end
293
+ # ex. ./sample/path
294
+ elsif posix_path.start_with? DOT_SLASH
295
+ root = DOT_SLASH
296
+ # else ex. sample/path
284
297
  end
285
298
 
286
- path_segments = posix_path.split SLASH
287
- # shift twice for a UNC path
288
- if root == DOUBLE_SLASH
289
- path_segments = path_segments[2..-1]
290
- # shift twice for a file:/// path and adjust root
291
- # NOTE technically file:/// paths work without this adjustment
292
- #elsif ::RUBY_ENGINE_OPAL && ::JAVASCRIPT_IO_MODULE == 'xmlhttprequest' && root == 'file:/'
293
- # root = 'file://'
294
- # path_segments = path_segments[2..-1]
295
- # shift once for any other root
296
- elsif root
297
- path_segments.shift
298
- end
299
+ path_segments = (root ? (posix_path.slice root.length, posix_path.length) : posix_path).split SLASH
299
300
  # strip out all dot entries
300
301
  path_segments.delete DOT
301
- # QUESTION should we chop trailing /? (we pay a small fraction)
302
- #posix_path = posix_path.chop if posix_path.end_with? SLASH
303
- cache[path] = [path_segments, root, posix_path]
302
+ cache[path] = [path_segments, root]
304
303
  end
305
304
 
306
305
  # Public: Join the segments using the posix file separator (since Ruby knows
@@ -317,110 +316,135 @@ class PathResolver
317
316
  root ? %(#{root}#{segments * SLASH}) : segments * SLASH
318
317
  end
319
318
 
320
- # Public: Resolve a system path from the target and start paths. If a jail
321
- # path is specified, enforce that the resolved directory is contained within
322
- # the jail path. If a jail path is not provided, the resolved path may be
323
- # any location on the system. If the resolved path is absolute, use it as is.
324
- # If the resolved path is relative, resolve it relative to the working_dir
325
- # specified in the constructor.
319
+ # Public: Securely resolve a system path
320
+ #
321
+ # Resolve a system path from the target relative to the start path, jail path, or working
322
+ # directory (specified in the constructor), in that order. If a jail path is specified, enforce
323
+ # that the resolved path descends from the jail path. If a jail path is not provided, the resolved
324
+ # path may be any location on the system. If the resolved path is absolute, use it as is (unless
325
+ # it breaches the jail path). Expand all parent and self references in the resolved path.
326
326
  #
327
327
  # target - the String target path
328
- # start - the String start (i.e., parent) path (default: nil)
329
- # jail - the String jail path to confine the resolved path (default: nil)
328
+ # start - the String start path from which to resolve a relative target; falls back to jail, if
329
+ # specified, or the working directory specified in the constructor (default: nil)
330
+ # jail - the String jail path to which to confine the resolved path, if specified; must be an
331
+ # absolute path (default: nil)
330
332
  # opts - an optional Hash of options to control processing (default: {}):
331
- # * :recover is used to control whether the processor should auto-recover
332
- # when an illegal path is encountered
333
+ # * :recover is used to control whether the processor should
334
+ # automatically recover when an illegal path is encountered
333
335
  # * :target_name is used in messages to refer to the path being resolved
334
336
  #
335
- # returns a String path that joins the target path with the start path with
336
- # any parent references resolved and self references removed and enforces
337
- # that the resolved path be contained within the jail, if provided
337
+ # returns a String path relative to the start path, if specified, and confined to the jail path,
338
+ # if specified. The path is posixified and all parent and self references in the path are expanded.
338
339
  def system_path target, start = nil, jail = nil, opts = {}
339
340
  if jail
340
- unless root? jail
341
- raise ::SecurityError, %(Jail is not an absolute path: #{jail})
342
- end
341
+ raise ::SecurityError, %(Jail is not an absolute path: #{jail}) unless root? jail
342
+ #raise ::SecurityError, %(Jail is not a canonical path: #{jail}) if jail.include? DOT_DOT
343
343
  jail = posixify jail
344
344
  end
345
345
 
346
- if target.nil_or_empty?
347
- target_segments = []
346
+ if target
347
+ if root? target
348
+ target_path = expand_path target
349
+ if jail && !(descends_from? target_path, jail)
350
+ if opts.fetch :recover, true
351
+ logger.warn %(#{opts[:target_name] || 'path'} is outside of jail; recovering automatically)
352
+ target_segments, _ = partition_path target_path
353
+ jail_segments, jail_root = partition_path jail
354
+ return join_path jail_segments + target_segments, jail_root
355
+ else
356
+ raise ::SecurityError, %(#{opts[:target_name] || 'path'} #{target} is outside of jail: #{jail} (disallowed in safe mode))
357
+ end
358
+ end
359
+ return target_path
360
+ else
361
+ target_segments, _ = partition_path target
362
+ end
348
363
  else
349
- target_segments, target_root, _ = partition_path target
364
+ target_segments = []
350
365
  end
351
366
 
352
367
  if target_segments.empty?
353
368
  if start.nil_or_empty?
354
- return jail ? jail : @working_dir
369
+ return jail || @working_dir
355
370
  elsif root? start
356
- unless jail
371
+ if jail
372
+ start = posixify start
373
+ else
357
374
  return expand_path start
358
375
  end
359
376
  else
360
- return system_path start, jail, jail, opts
377
+ target_segments, _ = partition_path start
378
+ start = jail || @working_dir
361
379
  end
362
- end
363
-
364
- if target_root && target_root != DOT_SLASH
365
- resolved_target = join_path target_segments, target_root
366
- # if target is absolute and a sub-directory of jail, or
367
- # a jail is not in place, let it slide
368
- if !jail || (resolved_target.start_with? jail)
369
- return resolved_target
370
- end
371
- end
372
-
373
- if start.nil_or_empty?
374
- start = jail ? jail : @working_dir
380
+ elsif start.nil_or_empty?
381
+ start = jail || @working_dir
375
382
  elsif root? start
376
- start = posixify start
383
+ start = posixify start if jail
377
384
  else
378
- start = system_path start, jail, jail, opts
385
+ #start = system_path start, jail, jail, opts
386
+ start = %(#{(jail || @working_dir).chomp '/'}/#{start})
379
387
  end
380
388
 
381
- # both jail and start have been posixfied at this point
382
- if jail == start
383
- jail_segments, jail_root, _ = partition_path jail
384
- start_segments = jail_segments.dup
385
- elsif jail
386
- unless start.start_with? jail
387
- raise ::SecurityError, %(#{opts[:target_name] || 'Start path'} #{start} is outside of jail: #{jail} (disallowed in safe mode))
389
+ # both jail and start have been posixified at this point if jail is set
390
+ if jail && (recheck = !(descends_from? start, jail)) && @file_separator == BACKSLASH
391
+ start_segments, start_root = partition_path start
392
+ jail_segments, jail_root = partition_path jail
393
+ if start_root != jail_root
394
+ if opts.fetch :recover, true
395
+ logger.warn %(start path for #{opts[:target_name] || 'path'} is outside of jail root; recovering automatically)
396
+ start_segments = jail_segments
397
+ recheck = false
398
+ else
399
+ raise ::SecurityError, %(start path for #{opts[:target_name] || 'path'} #{start} refers to location outside jail root: #{jail} (disallowed in safe mode))
400
+ end
388
401
  end
389
-
390
- start_segments, start_root, _ = partition_path start
391
- jail_segments, jail_root, _ = partition_path jail
392
-
393
- # Already checked for this condition
394
- #if start_root != jail_root
395
- # raise ::SecurityError, %(Jail root #{jail_root} does not match root of #{opts[:target_name] || 'start path'}: #{start_root})
396
- #end
397
402
  else
398
- start_segments, start_root, _ = partition_path start
399
- jail_root = start_root
403
+ start_segments, jail_root = partition_path start
400
404
  end
401
405
 
402
- resolved_segments = start_segments.dup
403
- warned = false
404
- target_segments.each do |segment|
405
- if segment == DOT_DOT
406
- if jail
407
- if resolved_segments.size > jail_segments.size
408
- resolved_segments.pop
409
- elsif !(recover ||= (opts.fetch :recover, true))
410
- raise ::SecurityError, %(#{opts[:target_name] || 'path'} #{target} refers to location outside jail: #{jail} (disallowed in safe mode))
411
- elsif !warned
412
- warn %(asciidoctor: WARNING: #{opts[:target_name] || 'path'} has illegal reference to ancestor of jail, auto-recovering)
413
- warned = true
406
+ if (resolved_segments = start_segments + target_segments).include? DOT_DOT
407
+ unresolved_segments, resolved_segments = resolved_segments, []
408
+ if jail
409
+ jail_segments, _ = partition_path jail unless jail_segments
410
+ warned = false
411
+ unresolved_segments.each do |segment|
412
+ if segment == DOT_DOT
413
+ if resolved_segments.size > jail_segments.size
414
+ resolved_segments.pop
415
+ elsif opts.fetch :recover, true
416
+ unless warned
417
+ logger.warn %(#{opts[:target_name] || 'path'} has illegal reference to ancestor of jail; recovering automatically)
418
+ warned = true
419
+ end
420
+ else
421
+ raise ::SecurityError, %(#{opts[:target_name] || 'path'} #{target} refers to location outside jail: #{jail} (disallowed in safe mode))
422
+ end
423
+ else
424
+ resolved_segments << segment
414
425
  end
415
- else
416
- resolved_segments.pop
417
426
  end
418
427
  else
419
- resolved_segments << segment
428
+ unresolved_segments.each do |segment|
429
+ segment == DOT_DOT ? resolved_segments.pop : resolved_segments << segment
430
+ end
420
431
  end
421
432
  end
422
433
 
423
- join_path resolved_segments, jail_root
434
+ if recheck
435
+ target_path = join_path resolved_segments, jail_root
436
+ if descends_from? target_path, jail
437
+ target_path
438
+ elsif opts.fetch :recover, true
439
+ logger.warn %(#{opts[:target_name] || 'path'} is outside of jail; recovering automatically)
440
+ jail_segments, _ = partition_path jail unless jail_segments
441
+ join_path jail_segments + target_segments, jail_root
442
+ else
443
+ raise ::SecurityError, %(#{opts[:target_name] || 'path'} #{target} is outside of jail: #{jail} (disallowed in safe mode))
444
+ end
445
+ else
446
+ join_path resolved_segments, jail_root
447
+ end
424
448
  end
425
449
 
426
450
  # Public: Resolve a web path from the target and start paths.
@@ -460,7 +484,7 @@ class PathResolver
460
484
  # end
461
485
  #end
462
486
 
463
- target_segments, target_root, _ = partition_path target, true
487
+ target_segments, target_root = partition_path target, true
464
488
  resolved_segments = []
465
489
  target_segments.each do |segment|
466
490
  if segment == DOT_DOT
@@ -484,22 +508,5 @@ class PathResolver
484
508
 
485
509
  uri_prefix ? %(#{uri_prefix}#{resolved_path}) : resolved_path
486
510
  end
487
-
488
- # Public: Calculate the relative path to this absolute filename from the specified base directory
489
- #
490
- # If either the filename or the base_directory are not absolute paths, or the
491
- # filename is not contained within the base directory, no work is done.
492
- #
493
- # filename - [String] an absolute filename.
494
- # base_directory - [String] an absolute base directory.
495
- #
496
- # Return the [String] relative path of the filename calculated from the base directory.
497
- def relative_path filename, base_directory
498
- if (root? filename) && (filename.start_with? base_directory)
499
- filename.slice base_directory.length + 1, filename.length
500
- else
501
- filename
502
- end
503
- end
504
511
  end
505
512
  end