liquid-autoescape 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ N2JlOGEyMGM1MWQ0NWRhMjJhN2NmMjg0NjFlMjY1NWQ2MTZjNjM0MQ==
5
+ data.tar.gz: !binary |-
6
+ YTFmMDdkMGQxMWQyMzVmZmU3ZWQ5MWNmZjEwNjZlYzZlNTA2NmE4YQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ YWRmOWZlMzRmNDY1MDgzZjk1OTkyOWRiMzc5YjE3Y2Y4YjM1NDY4YTc4MTA2
10
+ MWQ1OWM2NTZmMThlN2NiMzNkOTUxMGNmMjdmYWJlNTY0NGRhMDYzYjkyNzBm
11
+ MTc1MjljN2M2ODg5MzE0NjMwYWIyNTY4Y2YxZjZhOWM2Y2RkYzY=
12
+ data.tar.gz: !binary |-
13
+ MzQ3YmQ0OWFkMWNlMzMyZjA1N2NhZjRmMjcxNTAwYjdiNGE0NDM2Y2VmYjIz
14
+ ODk1ZTQ1M2M1ZjQzZTczMTQ2N2IwMWE5NzMyOGFjODRhM2ZlZDkxYzMxNjdk
15
+ M2ZjZDc1MjhiNDFhNTVmZjk2YTM4NDI5OTc1MTBjNGQ5MDdkOWM=
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Within3
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # Liquid Autoescape
2
+
3
+ [![Build Status](https://travis-ci.org/Within3/liquid-autoescape.svg)](https://travis-ci.org/Within3/liquid-autoescape)
4
+
5
+ This adds an `{% autoescape %}` block tag to Liquid that causes all variables
6
+ referenced within it to be escaped for display in an HTML context.
7
+
8
+ ## Requirements
9
+
10
+ * Ruby 1.9.3+
11
+ * Liquid 2 or 3
12
+
13
+ ## Basic Usage
14
+
15
+ To enable the `{% autoescape %}` tag in your Liquid templates, load the tag's
16
+ files in any Ruby file that will be executed before rendering templates using
17
+ the following line:
18
+
19
+ ```ruby
20
+ require "liquid/autoescape"
21
+ ```
22
+
23
+ With the tag loaded, you can escape all variables in a Liquid template by
24
+ wrapping them in an `{% autoescape %}` tag.
25
+
26
+ ```liquid
27
+ {% autoescape %}
28
+ {{ variable_one }}
29
+ {{ variable_two }}
30
+ {% endautoescape %}
31
+ ```
32
+
33
+ To prevent a variable contained in an `{% autoescape %}` block from being
34
+ escaped, use the `skip_escape` filter.
35
+
36
+ ```liquid
37
+ {% autoescape %}
38
+ Escaped: {{ untrusted_content }}
39
+ Not Escaped: {{ trusted_content | skip_escape }}
40
+ {% endautoescape %}
41
+ ```
42
+
43
+ ## Advanced Usage
44
+
45
+ Autoescaping can be customized to work better with your environment via a
46
+ Ruby-level configuration object. To configure autoescaping, use the `config`
47
+ object exposed by `Liquid::Autoescape.configure` in any Ruby file loaded before
48
+ templates are rendered.
49
+
50
+ ```ruby
51
+ require "liquid/autoescape"
52
+
53
+ Liquid::Autoescape.configure do |config|
54
+ ...
55
+ end
56
+ ```
57
+
58
+ The autoescape options that can be configured are detailed below.
59
+
60
+ ### Trusted Filters
61
+
62
+ If you are using custom Liquid filters that always generate trusted HTML, you
63
+ can add them to the list of trusted filters. Any variables that are passed
64
+ through a trusted filter will not be escaped.
65
+
66
+ ```ruby
67
+ Liquid::Autoescape.configure do |config|
68
+ config.trusted_filters << :generate_markup
69
+ end
70
+ ```
71
+
72
+ ```liquid
73
+ {% autoescape %}
74
+ Escaped: {{ variable | downcase }}
75
+ Not Escaped: {{ variable | generate_markup }}
76
+ {% endautoescape %}
77
+ ```
78
+
79
+ ### Custom Exemptions
80
+
81
+ If there are complex conditions under which a variable should not be escaped,
82
+ you can describe these conditions by creating custom exemptions. Exemptions are
83
+ functions that receive an instance of `Liquid::Autoescape::TemplateVariable`
84
+ that represents a Liquid variable as used in a template and return a boolean
85
+ value indicating whether the variable is exempt from escaping.
86
+
87
+ #### Adding Individual Exemptions
88
+
89
+ To quickly add a single exemption, use code similar to the following:
90
+
91
+ ```ruby
92
+ Liquid::Autoescape.configure do |config|
93
+ config.exemptions.add do |variable|
94
+ ...
95
+ end
96
+ end
97
+ ```
98
+
99
+ #### Importing Exemption Functions
100
+
101
+ If you prefer to define exemptions as instance methods on a module, you can
102
+ import those methods using code similar to the following:
103
+
104
+ ```ruby
105
+ module MyExemptions
106
+
107
+ def exemption_one(variable)
108
+ ...
109
+ end
110
+
111
+ def exemption_two(variable)
112
+ ...
113
+ end
114
+
115
+ end
116
+
117
+ Liquid::Autoescape.configure do |config|
118
+ config.exemptions.import(MyExemptions)
119
+ end
120
+ ```
121
+
122
+ The names of the module methods have no bearing on determining exemptions, so
123
+ they can be whatever you want them to be.
124
+
125
+ #### Exemption Conditions
126
+
127
+ As mentioned above, each exemption function is passed an object that describes a
128
+ Liquid variable as used in a template. This object exposes the variable's name,
129
+ as well as a list of any filters that it uses. These values can be used by each
130
+ exemption function to determine whether a variable should be exempt from
131
+ autoescaping, as shown by the code below:
132
+
133
+ ```ruby
134
+ Liquid::Autoescape.configure do |config|
135
+ config.exemptions.add do |variable|
136
+ variable.name == "var_one" && variable.filters.include?(:downcase)
137
+ end
138
+ end
139
+ ```
140
+
141
+ ```liquid
142
+ {% autoescape %}
143
+ Escaped: {{ var_one }}
144
+ Escaped: {{ var_two | downcase }}
145
+ Not Escaped: {{ var_one | downcase }}
146
+ {% endautoescape %}
147
+ ```
148
+
149
+ ### Global Mode
150
+
151
+ Autoescaping can be globally enabled, which will cause all variables in all
152
+ Liquid templates to be escaped, removing the need to use the `{% autoescape %}`
153
+ tag. Trusted filters and custom exemptions still apply in global mode, so there
154
+ is always the ability to mark a variable as exempt from escaping.
155
+
156
+ ```ruby
157
+ Liquid::Autoescape.configure do |config|
158
+ config.global = true
159
+ end
160
+ ```
161
+
162
+ ```liquid
163
+ Escaped: {{ variable }}
164
+ Not Escaped: {{ variable | skip_escape }}
165
+ ```
@@ -0,0 +1,33 @@
1
+ require "liquid/autoescape/configuration"
2
+ require "liquid/autoescape/filters"
3
+ require "liquid/autoescape/tags/autoescape"
4
+
5
+ module Liquid
6
+ module Autoescape
7
+
8
+ # The context variable that stores the autoescape state
9
+ #
10
+ # @private
11
+ ENABLED_FLAG = "liquid_autoescape_enabled"
12
+
13
+ # Configure Liquid autoescaping
14
+ #
15
+ # @yieldparam [Liquid::Autoescape::Configuration] config The autoescape configuration
16
+ def self.configure
17
+ yield(configuration)
18
+ end
19
+
20
+ # Restore the configuration's default values
21
+ def self.reconfigure
22
+ configuration.reset
23
+ end
24
+
25
+ # The current autoescape configuration
26
+ #
27
+ # @return [Liquid::Autoescape::Configuration]
28
+ def self.configuration
29
+ @configuration ||= Configuration.new
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,41 @@
1
+ require "liquid/autoescape/core_exemptions"
2
+ require "liquid/autoescape/exemption_list"
3
+
4
+ module Liquid
5
+ module Autoescape
6
+
7
+ # A configuration file for setting autoescape options
8
+ class Configuration
9
+
10
+ # @return [Liquid::Autoescape::ExemptionList] The list of custom exemptions
11
+ attr_reader :exemptions
12
+
13
+ # @return [Boolean] Whether global mode is enabled
14
+ attr_writer :global
15
+
16
+ # @return [Array<Symbol>] The list of trusted filter names
17
+ attr_accessor :trusted_filters
18
+
19
+ # Create a new configuration object with default values
20
+ def initialize
21
+ reset
22
+ end
23
+
24
+ # Reset the configuration's values to their defaults
25
+ def reset
26
+ @exemptions = ExemptionList.from_module(CoreExemptions)
27
+ @global = false
28
+ @trusted_filters = []
29
+ end
30
+
31
+ # Whether global mode is enabled
32
+ #
33
+ # @return [Boolean]
34
+ def global?
35
+ @global
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,40 @@
1
+ require "liquid/autoescape"
2
+
3
+ module Liquid
4
+ module Autoescape
5
+
6
+ # Core exemptions for all Liquid variables
7
+ #
8
+ # These exemptions are used to build the default exemption list referenced
9
+ # when determining whether variables should be escaped.
10
+ module CoreExemptions
11
+
12
+ # A list of all filters that influence escaping
13
+ ESCAPING_FILTERS = [:escape, :skip_escape]
14
+
15
+ # Determine whether a Liquid variable uses an escaping filter
16
+ #
17
+ # This accounts for both filters that are known to escape the variable
18
+ # and those that should prevent the variable from being escaped.
19
+ #
20
+ # @param [Liquid::Autoescape::TemplateVariable] A Liquid variable used in a template
21
+ # @return [Boolean]
22
+ def uses_escaping_filter?(variable)
23
+ !(variable.filters & ESCAPING_FILTERS).empty?
24
+ end
25
+
26
+ # Determine whether a Liquid variable uses a trusted filters
27
+ #
28
+ # Trusted filters can be configured by the user to include any custom
29
+ # filters that are known to generate already escaped markup.
30
+ #
31
+ # @param [Liquid::Autoescape::TemplateVariable] A Liquid variable used in a template
32
+ # @return [Boolean]
33
+ def uses_trusted_filter?(variable)
34
+ !(variable.filters & Autoescape.configuration.trusted_filters).empty?
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,11 @@
1
+ module Liquid
2
+ module Autoescape
3
+
4
+ # The base error from which all other autoescape errors inherit
5
+ class AutoescapeError < StandardError; end
6
+
7
+ # An error raised when an exemption encounters an issue
8
+ class ExemptionError < AutoescapeError; end
9
+
10
+ end
11
+ end
@@ -0,0 +1,47 @@
1
+ require "liquid/autoescape/errors"
2
+
3
+ module Liquid
4
+ module Autoescape
5
+
6
+ # An exemption that may apply to a Liquid template variable
7
+ #
8
+ # Exemptions are created from functions that accept a template variable and
9
+ # and return a boolean value indicating whether or not the variable is
10
+ # exempt from autoescaping.
11
+ #
12
+ # @example An exemption based on a variable's name
13
+ # exemption = Exemption.new do |variable|
14
+ # variable.name == "safe_variable"
15
+ # end
16
+ #
17
+ # @example An exemption based on a variable's filters
18
+ # exemption = Exemption.new do |variable|
19
+ # variable.filters.include?(:trusted_filter)
20
+ # end
21
+ class Exemption
22
+
23
+ # Create a new autoescaping exemption
24
+ #
25
+ # This requires a filter function to be provided that will be passed a
26
+ # +TemplateVariable+ instance that it can use to return a boolean
27
+ # indicating whether the exemption applies to the variable.
28
+ #
29
+ # @param [Proc] filter A filter function to use for calculating the exemption
30
+ # @raise [Liquid::Autoescape::ExemptionError] if a filter function is not provided
31
+ def initialize(&filter)
32
+ raise ExemptionError, "You must provide an exemption with a block that determines if an exemption applies" unless block_given?
33
+ @filter = filter
34
+ end
35
+
36
+ # Determine whether the exemption applies to a Liquid variable
37
+ #
38
+ # @param [Liquid::Autoescape::TemplateVariable] A Liquid variable used in a template
39
+ # @return [Boolean] Whether the exemption applies to the variable
40
+ def applies?(variable)
41
+ @filter.call(variable)
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,106 @@
1
+ require "liquid/autoescape"
2
+ require "liquid/autoescape/exemption"
3
+
4
+ module Liquid
5
+ module Autoescape
6
+
7
+ # A list of exemptions that may apply to template variables
8
+ #
9
+ # Exemption lists manage one or more exemptions, and determine whether any
10
+ # managed exemptions applies to a template variable. Exemptions can be
11
+ # added as individual filter functions, or can be imported in bulk from a
12
+ # module.
13
+ #
14
+ # @example Adding exemption functions
15
+ # exemptions = ExemptionList.new
16
+ # ExemptionList.add { |variable| variable.name == "one" }
17
+ # ExemptionList.add { |variable| variable.name == "two" }
18
+ #
19
+ # @example Importing exemptions from a module
20
+ # module MyExemptions
21
+ #
22
+ # def exemption_one(variable)
23
+ # variable.name == "one"
24
+ # end
25
+ #
26
+ # def exemption_two(variable)
27
+ # variable.name == "two"
28
+ # end
29
+ #
30
+ # end
31
+ #
32
+ # exemptions = ExemptionList.new
33
+ # exemptions.import(MyExemptions)
34
+ #
35
+ class ExemptionList
36
+
37
+ # Create an exemption list from a module's instance methods
38
+ #
39
+ # @param [Module] source The module providing exemptions as methods
40
+ # @return [Liquid::Autoescape::ExemptionList]
41
+ def self.from_module(source)
42
+ exemptions = new
43
+ exemptions.import(source)
44
+ exemptions
45
+ end
46
+
47
+ # Create a new exemption list
48
+ def initialize
49
+ @exemptions = []
50
+ end
51
+
52
+ # Add a single filter function to use as an exemption
53
+ #
54
+ # @param [Proc] filter A filter function to use as an exemption
55
+ # @return [Liquid::Autoescape::ExemptionList] The updated exemption list
56
+ def add(&filter)
57
+ @exemptions << Exemption.new(&filter)
58
+ self
59
+ end
60
+
61
+ # Add all instance methods of a module as exemptions
62
+ #
63
+ # @param [Module] source The module providing exemptions as methods
64
+ # @return [Liquid::Autoescape::ExemptionList] The updated exemption list
65
+ def import(source)
66
+ container = Module.new { extend source }
67
+ exemptions = source.instance_methods(false)
68
+ exemptions.each do |exemption|
69
+ @exemptions << Exemption.new(&container.method(exemption))
70
+ end
71
+ self
72
+ end
73
+
74
+ # Determine whether any of the exemptions apply to a Liquid variable
75
+ #
76
+ # @param [Liquid::Autoescape::TemplateVariable] variable A Liquid variable used in a template
77
+ # @return [Boolean] Whether any of the exemptions apply to the variable
78
+ def applies?(variable)
79
+ @exemptions.each do |exemption|
80
+ if exemption.applies?(variable)
81
+ return true
82
+ end
83
+ end
84
+ false
85
+ end
86
+
87
+ alias_method :apply?, :applies?
88
+
89
+ # Whether the exemption list has exemptions
90
+ #
91
+ # @return [Boolean]
92
+ def populated?
93
+ !@exemptions.empty?
94
+ end
95
+
96
+ # The number of exemptions in the list
97
+ #
98
+ # @return [Integer]
99
+ def size
100
+ @exemptions.size
101
+ end
102
+
103
+ end
104
+
105
+ end
106
+ end