jekyll_flexible_include 2.0.8 → 2.0.9

Sign up to get free protection for your applications and to get access to all the features.
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