ezcsp 0.0.1

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.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/ezcsp.rb +400 -0
  3. metadata +44 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a64098cd248945d8710812f3321c933b2369eeea
4
+ data.tar.gz: 057154fe542773f16ef047ecce002dc0882a08b0
5
+ SHA512:
6
+ metadata.gz: b8d006493d6446008a8beb09c8cd5c425365fb1583d07f8ecd152695524dbfc2859a7d6398ebd1f55107c056729a15f23ccf5701bc5faf30d377c01cedc3c739
7
+ data.tar.gz: e453772110f23a06a30f94c91465433ac36e8e8b2a1f79c1fd0dc877f830e6f439b8b9c426be7bcef38a66a03a2526f98be08b8c1f713e022d7bc5230c5e2624
data/lib/ezcsp.rb ADDED
@@ -0,0 +1,400 @@
1
+ require 'json'
2
+
3
+ #===============================================================================
4
+ # EzCSP
5
+ #
6
+
7
+ ##
8
+ # EzCSP provides a simple object-oriented way to generate
9
+ # <tt>Content-Security-Policy</tt> HTTP headers. For documentation on CSP,
10
+ # see {Mozilla's Content-Security-Policy page}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy].
11
+ #
12
+ # Basic usage:
13
+ #
14
+ # require 'ezcsp'
15
+ # csp = EzCSP.new()
16
+ #
17
+ # Then, depending on how you output HTTP headers, you could output the CSP header
18
+ # something like this:
19
+ #
20
+ # headers['Content-Security-Policy'] = csp.to_s
21
+ #
22
+ # <tt>csp.to_s</tt>, by default, returns this string:
23
+ #
24
+ # default-src 'self'; frame-src 'self'; object-src 'none'; form-action 'self'; frame-ancestors 'self'; base-uri 'none'; block-all-mixed-content;
25
+ #
26
+ # By default, the header value is very restrictive. It basically states that no
27
+ # resources — scripts, styles, images, etc. — from outside the current web site
28
+ # can be used. Expand that set of allowed resources by adding to the accessors
29
+ # listed below, usually by using the #cdn method. So, for example, to
30
+ # allow the browser to get scripts and styles from <tt>code.jquery.com</tt>,
31
+ # you would do this:
32
+ #
33
+ # csp.cdn 'code.jquery.com', 'script_src', 'style_src'
34
+ #
35
+ # which would produce this header value:
36
+ #
37
+ # default-src 'self'; script-src 'self' code.jquery.com; style-src 'self' code.jquery.com; frame-src 'self'; object-src 'none'; form-action 'self'; frame-ancestors 'self'; base-uri 'none'; block-all-mixed-content;
38
+ #
39
+ # EzCSP isn't a substitute for understanding content security policies. Make
40
+ # sure you
41
+ # {read up on CSP}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy]
42
+ # before using this class.
43
+ #
44
+ # In the array attributes listed below, if the value <tt>none</tt> is in the
45
+ # array, then all other values are ignored.
46
+
47
+ class EzCSP
48
+ # Array. Holds the list of
49
+ # {default-src}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/default-src]
50
+ # hosts.
51
+ # By default, <tt>default_src</tt> is an empty array.
52
+ attr_accessor :default_src
53
+
54
+ # By default nil. If an array, this attribute holds the list of hosts in
55
+ # {img-src}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/img-src].
56
+ attr_accessor :img_src
57
+
58
+ # By default nil. If an array, this attribute holds the list of hosts in
59
+ # {script-src}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src].
60
+ attr_accessor :script_src
61
+
62
+ # By default nil. If an array, this attribute holds the list of hosts in
63
+ # {style-src}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src].
64
+ attr_accessor :style_src
65
+
66
+ # Array. Holds the list of
67
+ # {frame-src}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src]
68
+ # hosts.
69
+ # By default, <tt>all_src</tt> consists of <tt>['self']</tt>.
70
+ attr_accessor :frame_src
71
+
72
+ # By default nil. If an array, this attribute holds the list of hosts in
73
+ # {font-src}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/font-src].
74
+ attr_accessor :font_src
75
+
76
+ # Array. Holds the list of
77
+ # {object-src}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/object-src]
78
+ # hosts.
79
+ # By default, <tt>object_src</tt> consists of <tt>['none']</tt>.
80
+ attr_accessor :object_src
81
+
82
+ # Array. <tt>all_src</tt> is a shortcut for indicating that a host is to be
83
+ # included in all other *_src arrays.
84
+ # By default, <tt>all_src</tt> consists of <tt>['self']</tt>.
85
+ attr_accessor :all_src
86
+
87
+ # Array. Holds the list of
88
+ # {form-action}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/form-action]
89
+ # hosts.
90
+ # By default, <tt>form_action</tt> consists of <tt>['self']</tt>.
91
+ attr_accessor :form_action
92
+
93
+ # Array. Holds the list of
94
+ # {frame-ancestors}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors]
95
+ # hosts.
96
+ # By default, <tt>frame_ancestors</tt> consists of <tt>['self']</tt>.
97
+ attr_accessor :frame_ancestors
98
+
99
+ # Array. Holds the list of
100
+ # {base-uri}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/base-uri]
101
+ # hosts.
102
+ # By default, <tt>base_uri</tt> consists of <tt>['none']</tt>.
103
+ attr_accessor :base_uri
104
+
105
+ # Boolean, defaults to true. Sets the value for
106
+ # {block-all-mixed-content}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/block-all-mixed-content].
107
+ attr_accessor :block_all_mixed_content
108
+
109
+ # Boolean, defaults to nil. Sets the value for
110
+ # {upgrade-insecure-requests}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/upgrade-insecure-requests].
111
+ # If this value is set then #block_all_mixed_content is ignored.
112
+ attr_accessor :upgrade_insecure_requests
113
+
114
+ # This attribute is used to set two different things. It sets the
115
+ # {report-uri}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-uri]
116
+ # value, which is being phased out. It is also used in
117
+ # #report_to_header_value to generate a
118
+ # {report-to}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-to]
119
+ # HTTP header. See details in #report_to_header_value.
120
+ attr_accessor :report_to
121
+
122
+ # Sets the name of the report-to group in the
123
+ # {report-to}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-to]
124
+ # HTTP header.
125
+ # Defaults to <tt>csp-endpoint</tt>.
126
+ # See details in #report_to_header_value.
127
+ attr_accessor :report_to_group
128
+
129
+ # Sets the maximum age of the group in the
130
+ # {report-to}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-to]
131
+ # HTTP header.
132
+ # Defaults to <tt>10886400</tt>.
133
+ attr_accessor :report_to_max_age
134
+
135
+
136
+ #---------------------------------------------------------------------------
137
+ # initialize
138
+ #
139
+
140
+ ##
141
+ # <tt>new()</tt> takes no parameters.
142
+
143
+ def initialize
144
+ # $tm.hrm
145
+
146
+ # all and default
147
+ @all_src = ['self']
148
+ @default_src = []
149
+
150
+ # inherit from default
151
+ @img_src = nil
152
+ @script_src = nil
153
+ @style_src = nil
154
+ @font_src = nil
155
+ @object_src = ['none']
156
+
157
+ # do not inherit from default
158
+ @frame_src = ['self']
159
+ @frame_ancestors = ['self']
160
+ @form_action = ['self']
161
+ @base_uri = ['none']
162
+
163
+ # booleans
164
+ @block_all_mixed_content = true
165
+ @upgrade_insecure_requests = nil
166
+ @default_to_explicit = true
167
+
168
+ # report_to
169
+ @report_to = nil
170
+ @report_to_group = 'csp-endpoint'
171
+ @report_to_max_age = 10886400
172
+ end
173
+ #
174
+ # initialize
175
+ #---------------------------------------------------------------------------
176
+
177
+
178
+ #---------------------------------------------------------------------------
179
+ # to_s
180
+ #
181
+
182
+ ##
183
+ # Returns the value of the cont
184
+ # {Content-Security-Policy}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy]
185
+ # HTTP header.
186
+ # Note that this method only returns the value, i.e., the stuff after the
187
+ # colon in the HTTP header.
188
+
189
+ def to_s
190
+ # $tm.hrm
191
+
192
+ # initialize return value
193
+ rv = []
194
+
195
+ # add some sources
196
+ src_to_str rv, 'default-src', @default_src, true
197
+ src_to_str rv, 'img-src', @img_src, true
198
+ src_to_str rv, 'script-src', @script_src, true
199
+ src_to_str rv, 'style-src', @style_src, true
200
+ src_to_str rv, 'frame-src', @frame_src, true
201
+ src_to_str rv, 'font-src', @font_src, true
202
+ src_to_str rv, 'object-src', @object_src, true
203
+ src_to_str rv, 'form-action', @form_action, false
204
+ src_to_str rv, 'frame-ancestors', @frame_ancestors, false
205
+ src_to_str rv, 'base-uri', @base_uri, false
206
+
207
+ # block all mixed content
208
+ if @upgrade_insecure_requests.nil?
209
+ if @block_all_mixed_content
210
+ rv.push 'block-all-mixed-content'
211
+ end
212
+ else
213
+ if @upgrade_insecure_requests
214
+ rv.push 'upgrade-insecure-requests'
215
+ end
216
+ end
217
+
218
+ # report-uri
219
+ if @report_to
220
+ rv.push 'report-uri ' + @report_to
221
+ rv.push 'report-to ' + @report_to_group
222
+ end
223
+
224
+ # initiilaze return string
225
+ rv_str = rv.join('; ')
226
+
227
+ # collapse rv_str
228
+ rv_str.sub!(/\A\s+/imu, '')
229
+ rv_str.sub!(/\s+\z/imu, '')
230
+ rv_str.gsub!(/\s+/imu, ' ')
231
+
232
+ # add trailing semicolon
233
+ if rv_str.length > 0
234
+ rv_str += ';'
235
+ end
236
+
237
+ # return
238
+ return rv_str
239
+ end
240
+ #
241
+ # to_s
242
+ #---------------------------------------------------------------------------
243
+
244
+
245
+ #---------------------------------------------------------------------------
246
+ # report_to_header_value
247
+ #
248
+
249
+ ##
250
+ # This method returns the value of a
251
+ # {report-to}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-to]
252
+ # HTTP header. It is only useful if you set the #report_to property. For
253
+ # example, if you set #report_to like this:
254
+ #
255
+ # csp.report_to = 'https://www.example.com/csp'
256
+ #
257
+ # Then <tt>report_to_header_value</tt> returns a value like this:
258
+ #
259
+ # {"group":"csp-endpoint","max-age":10886400,"endpoints":[{"url":"https://www.example.com/csp"}]}
260
+ #
261
+ # So, depending on how you set your HTTP headers, you might set the Report-To
262
+ # header like this:
263
+ #
264
+ # headers['Report-To'] = csp.report_to_header_value
265
+
266
+ def report_to_header_value
267
+ # $tm.hrm
268
+
269
+ # initialize value struct
270
+ struct = {}
271
+
272
+ # group name
273
+ struct['group'] = @report_to_group
274
+
275
+ # max age
276
+ struct['max-age'] = @report_to_max_age
277
+
278
+ # endpoints
279
+ struct['endpoints'] = [{'url'=>@report_to}]
280
+
281
+ # return
282
+ # return 'Report-To: ' + JSON.generate(struct)
283
+ return JSON.generate(struct)
284
+ end
285
+ #
286
+ # report_to_header_value
287
+ #---------------------------------------------------------------------------
288
+
289
+
290
+ #---------------------------------------------------------------------------
291
+ # cdn
292
+ #
293
+
294
+ ##
295
+ # This method allows you to add a host to multiple source arrays at once.
296
+ # The first param is the host you would like to set. Follow that with a
297
+ # list of arrays to add it to. The list should consist of the names of the
298
+ # arrays, e.g. <tt>img_src</tt>.
299
+ #
300
+ # So, for example, this code:
301
+ #
302
+ # csp.cdn 'code.jquery.com', 'script_src', 'style_src'
303
+ #
304
+ # adds <tt>code.jquery.com</tt> to the #script_src and #style_src arrays,
305
+ # creating those arrays if necessary.
306
+
307
+ def cdn(uri, *srcs)
308
+ # $tm.hrm
309
+
310
+ # img
311
+ if srcs.include?('img_src')
312
+ @img_src ||= []
313
+ @img_src.push uri
314
+ end
315
+
316
+ # script
317
+ if srcs.include?('script_src')
318
+ @script_src ||= []
319
+ @script_src.push uri
320
+ end
321
+
322
+ # style
323
+ if srcs.include?('style_src')
324
+ @style_src ||= []
325
+ @style_src.push uri
326
+ end
327
+
328
+ # frame
329
+ if srcs.include?('frame_src')
330
+ @frame_src ||= []
331
+ @frame_src.push uri
332
+ end
333
+
334
+ # font
335
+ if srcs.include?('font_src')
336
+ @font_src ||= []
337
+ @font_src.push uri
338
+ end
339
+ end
340
+ #
341
+ # cdn
342
+ #---------------------------------------------------------------------------
343
+
344
+
345
+ # private
346
+ private
347
+
348
+
349
+ #---------------------------------------------------------------------------
350
+ # src_to_str
351
+ #
352
+ @@quote_values = %w{self none unsafe-inline unsafe-eval}
353
+
354
+ def src_to_str(rv, key, src, use_all)
355
+ # $tm.hrm
356
+ # $tm.debug key
357
+ # $tm.debug src
358
+
359
+ # early exit: if nil, nothing to do
360
+ src.nil? and return
361
+
362
+ # new src
363
+ srcs = []
364
+
365
+ # special case: src includes "none"
366
+ if src.include?('none')
367
+ src = ['none']
368
+ else
369
+ # add @all_src if necessary
370
+ if use_all and @all_src
371
+ srcs += @all_src
372
+ end
373
+ end
374
+
375
+ # add src
376
+ srcs += src
377
+
378
+ # map some values so that they have single quotes
379
+ srcs.map! do |itm|
380
+ if @@quote_values.include?(itm)
381
+ itm = "'#{itm}'"
382
+ end
383
+
384
+ # Collapse spaces, which actually shouldn't be there to begin with.
385
+ # Doing so helps avoid HTTP header injection.
386
+ itm = itm.gsub(/\s+/mu, ' ')
387
+
388
+ itm
389
+ end
390
+
391
+ # add to return values
392
+ rv.push key + ' ' + srcs.uniq.join(' ')
393
+ end
394
+ #
395
+ # src_to_str
396
+ #---------------------------------------------------------------------------
397
+ end
398
+ #
399
+ # EzCSP
400
+ #===============================================================================
metadata ADDED
@@ -0,0 +1,44 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ezcsp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Mike O'Sullivan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-11-05 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Simplifies creating a content security policy for use as an HTTP header
14
+ email: miko@idocs.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/ezcsp.rb
20
+ homepage: https://rubygems.org/gems/ezcsp
21
+ licenses:
22
+ - MIT
23
+ metadata: {}
24
+ post_install_message:
25
+ rdoc_options: []
26
+ require_paths:
27
+ - lib
28
+ required_ruby_version: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ required_rubygems_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ requirements: []
39
+ rubyforge_project:
40
+ rubygems_version: 2.5.2.1
41
+ signing_key:
42
+ specification_version: 4
43
+ summary: Content security policy HTTP header builder
44
+ test_files: []