jekyll_flexible_include 2.0.8 → 2.0.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 64eb6af1f283738c8152205359b97b42081c571cc8cd16dc30d263108e21aba0
4
- data.tar.gz: 87b46d76f2f43022c458fff1dc4f3ea5523ccc0afe29ca7eb4c6c7f41554427d
3
+ metadata.gz: b71142b75599a60998290ed57afbe3231330bf42dba89c7f892e3e08e3eb07e2
4
+ data.tar.gz: e1cf42634742f63c2f6f44e4e800093003fbe9a01e47f12414c8876c9663f0d1
5
5
  SHA512:
6
- metadata.gz: 143e9c8cc4e9d5a109ce41020e46c4c8c0366e9c30bf4201263767e5276818ca32293430d6464afbea3a1925c90256219394dcf77b57735dd49ff3efa42dd940
7
- data.tar.gz: 2dd1b9df7fa2936231ef0bb85ef8ecb87fc7afa9d519a9fda3dd9167869b13671c9ece3c13b1576ac11d9c0abc1adc498e7bc66fd5fb3fdb9634e417666119a6
6
+ metadata.gz: 1456652118883acd55de272df6c00c8ce29c42031609282ffe95ff043c15f5c57f9f293d23490edf78267dc672408045018e69cb2edcd6be144cd214b180b9a4
7
+ data.tar.gz: 88a9c4d75a15fdd84980816a266fbfd12d6e1e81cfac041881393b33d015ddbcfad30c0a2d1e4ae7b5ea09048838a0fddfc7352db508a6520543b4cca67ab06a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 2.0.9 / 2022-04-15
2
+ * Displays elapsed time to scan files; only scans when the gem is first used.
3
+
1
4
  ## 2.0.8 / 2022-04-14
2
5
  * Added the ability to restrict arbitrary command execution, and specify the allowable directories to read from.
3
6
 
data/README.md CHANGED
@@ -60,7 +60,7 @@ For example, the following restricts access to only the files within:
60
60
  2. The directory tree rooted at `/var/files`.
61
61
  3. The directory tree rooted at the expanded value of the `$work` environment variable.
62
62
  ```shell
63
- export FLEXIBLE_INCLUDE_PATHS='~/my_dir/**/{*,.*}:/var/files/**/{*,.*}:$work/**/{*,.*}'
63
+ export FLEXIBLE_INCLUDE_PATHS='~/.*:$sites/.*:$work/.*'
64
64
  ```
65
65
  Note that the above matches dot (hidden) files as well as regular files.
66
66
  To just match visible files:
@@ -68,6 +68,9 @@ To just match visible files:
68
68
  export FLEXIBLE_INCLUDE_PATHS='~/my_dir/**/*:/var/files/**/*:$work/**/*'
69
69
  ```
70
70
 
71
+ #### Note
72
+ The specified directories are traversed when the plugin starts, and the filenames are stored in memory. Directories with lots of files might take a noticable amount to time to enumerate the files.
73
+
71
74
 
72
75
  ### Restricting Arbitrary Processes
73
76
  By default, `flexible_include` can execute any command. You can disable that by setting the environment variable `DISABLE_FLEXIBLE_INCLUDE` to any non-empty value.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JekyllFlexibleIncludePluginVersion
4
- VERSION = "2.0.8"
4
+ VERSION = "2.0.9"
5
5
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "benchmark"
3
4
  require "jekyll"
4
5
  require "jekyll_plugin_logger"
5
6
  require "securerandom"
@@ -13,6 +14,35 @@ end
13
14
  class FlexibleInclude < Liquid::Tag
14
15
  FlexibleIncludeError = Class.new(Liquid::Error)
15
16
 
17
+ @read_regexes = nil
18
+
19
+ def self.normalize_path(path)
20
+ JekyllTagHelper.expand_env(path)
21
+ .gsub("~", Dir.home)
22
+ end
23
+
24
+ # If FLEXIBLE_INCLUDE_PATHS='~/lib/.*:.*:$WORK/.*'
25
+ # Then @read_regexes will be set to regexes of ["/home/my_user_id/lib/.*", "/pwd/.*", "/work/envar/path/.*"]
26
+ def self.security_check
27
+ @execution_denied = ENV['DISABLE_FLEXIBLE_INCLUDE']
28
+
29
+ unless @read_regexes
30
+ read_paths = normalize_path(ENV['FLEXIBLE_INCLUDE_PATHS'])
31
+ if read_paths
32
+ @read_regexes = read_paths.split(":").map do |path|
33
+ abs_path = path.start_with?('/') ? path : (Pathname.new(Dir.pwd) + path).to_s
34
+ Regexp.new(abs_path)
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ def self.access_allowed(path)
41
+ return true unless @read_regexes
42
+
43
+ @read_regexes.find { |regex| regex.match(normalize_path(path)) }
44
+ end
45
+
16
46
  # @param tag_name [String] the name of the tag, which we already know.
17
47
  # @param markup [String] the arguments from the tag, as a single string.
18
48
  # @param parse_context [Liquid::ParseContext] hash that stores Liquid options.
@@ -25,12 +55,7 @@ class FlexibleInclude < Liquid::Tag
25
55
  @logger = PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config)
26
56
  @helper = JekyllTagHelper.new(tag_name, markup, @logger)
27
57
 
28
- @execution_denied = ENV['DISABLE_FLEXIBLE_INCLUDE']
29
-
30
- # If FLEXIBLE_INCLUDE_PATHS='~/lib/**/*:*/**/*'
31
- # Then @read_paths will be set to ["~/lib/**/*", "*/**/*"]
32
- @read_paths = ENV['FLEXIBLE_INCLUDE_PATHS']
33
- @read_paths = @read_paths.split(":").map { |x| JekyllTagHelper.expand_env x } if @read_paths
58
+ self.class.security_check
34
59
  end
35
60
 
36
61
  # @param liquid_context [Liquid::Context]
@@ -43,6 +68,7 @@ class FlexibleInclude < Liquid::Tag
43
68
  @label_specified = @label
44
69
  @copy_button = @helper.parameter_specified? "copyButton"
45
70
  @pre = @copy_button || @dark || @download || @label_specified || @helper.parameter_specified?("pre") # Download or label implies pre
71
+
46
72
  filename = @helper.parameter_specified? "file"
47
73
  filename ||= @helper.params.first # Do this after all options have been checked for
48
74
  @label ||= filename
@@ -55,16 +81,19 @@ class FlexibleInclude < Liquid::Tag
55
81
  path = JekyllTagHelper.expand_env(filename)
56
82
  case path
57
83
  when /\A\// # Absolute path
58
- return denied("Access to #{path} denied by FLEXIBLE_INCLUDE_PATHS value.") unless access_allowed(path)
84
+ return denied("Access to #{path} denied by FLEXIBLE_INCLUDE_PATHS value.") unless self.class.access_allowed(path)
85
+
59
86
  @logger.debug { "Absolute path=#{path}, filename=#{filename}" }
60
87
  when /\A~/ # Relative path to user's home directory
61
- return denied("Access to #{path} denied by FLEXIBLE_INCLUDE_PATHS value.") unless access_allowed(path)
88
+ return denied("Access to #{path} denied by FLEXIBLE_INCLUDE_PATHS value.") unless self.class.access_allowed(path)
89
+
62
90
  @logger.debug { "User home start filename=#{filename}, path=#{path}" }
63
91
  filename.slice! "~/"
64
92
  path = File.join(ENV['HOME'], filename)
65
93
  @logger.debug { "User home end filename=#{filename}, path=#{path}" }
66
94
  when /\A!/ # Run command and return response
67
95
  return denied("Arbitrary command execution denied by DISABLE_FLEXIBLE_INCLUDE value.") if @execution_denied
96
+
68
97
  filename = JekyllTagHelper.remove_quotes(@helper.argv.first) if @helper.argv.first
69
98
  filename.slice! "!"
70
99
  contents = run(filename)
@@ -82,11 +111,6 @@ class FlexibleInclude < Liquid::Tag
82
111
 
83
112
  private
84
113
 
85
- def access_allowed(path)
86
- return true unless @read_paths
87
- Dir.glob(@read_paths).find { |x| x == path }
88
- end
89
-
90
114
  def denied(msg)
91
115
  @logger.error("#{@helper.page.path} - #{msg}")
92
116
  "<p style='color: white; background-color: red; padding: 2pt 1em 2pt 1em;'>#{msg}</p>"
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "shellwords"
4
+ require 'key_value_parser'
4
5
 
5
6
  class JekyllTagHelper
6
7
  attr_reader :argv, :liquid_context, :logger, :params, :tag_name
data/spec/glob_spec.rb ADDED
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../lib/flexible_include"
4
+
5
+ RSpec.describe(FlexibleInclude) do
6
+ it "controls access to files" do
7
+ ENV['FLEXIBLE_INCLUDE_PATHS'] = '~/.*:spec/.*'
8
+
9
+ FlexibleInclude.send(:new, 'my_tag', "", Liquid::ParseContext.new)
10
+ FlexibleInclude.security_check
11
+ expect(FlexibleInclude.access_allowed(__FILE__)).to be_truthy
12
+
13
+ expect(FlexibleInclude.access_allowed("~/.mem_settings.yaml")).to be_truthy
14
+
15
+ home_file = JekyllTagHelper.expand_env("$HOME/.mem_settings.yaml")
16
+ expect(FlexibleInclude.access_allowed(home_file)).to be_truthy
17
+
18
+ expect(FlexibleInclude.access_allowed('/asdf')).to be_falsey
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jekyll"
4
+
5
+ require_relative "../lib/flexible_include"
6
+
7
+ Jekyll.logger.log_level = :info
8
+
9
+ RSpec.configure do |config|
10
+ config.filter_run :focus
11
+ config.order = "random"
12
+ config.run_all_when_everything_filtered = true
13
+
14
+ # See https://relishapp.com/rspec/rspec-core/docs/command-line/only-failures
15
+ config.example_status_persistence_file_path = "spec/status_persistence.txt"
16
+ end
@@ -0,0 +1,3 @@
1
+ example_id | status | run_time |
2
+ ------------------------ | ------ | --------------- |
3
+ ./spec/glob_spec.rb[1:1] | passed | 0.01217 seconds |
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll_flexible_include
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.8
4
+ version: 2.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Slinn
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2022-04-14 00:00:00.000000000 Z
13
+ date: 2022-04-15 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: jekyll
@@ -88,6 +88,9 @@ files:
88
88
  - lib/flexible_include.rb
89
89
  - lib/flexible_include/version.rb
90
90
  - lib/jekyll_tag_helper.rb
91
+ - spec/glob_spec.rb
92
+ - spec/spec_helper.rb
93
+ - spec/status_persistence.txt
91
94
  homepage: https://www.mslinn.com/blog/2020/10/03/jekyll-plugins.html#flexibleInclude
92
95
  licenses:
93
96
  - MIT
@@ -120,4 +123,7 @@ signing_key:
120
123
  specification_version: 4
121
124
  summary: Jekyll plugin supports various ways to include content into the generated
122
125
  site.
123
- test_files: []
126
+ test_files:
127
+ - spec/glob_spec.rb
128
+ - spec/spec_helper.rb
129
+ - spec/status_persistence.txt