class Jekyll::JekyllContentSecurityPolicyGenerator::ContentSecurityPolicyGenerator
Provides the ability to generate a content security policy for inline scripts and styles. Will reuse an existing CSP or generate a new one and insert in HEAD.
Public Class Methods
new(document_html)
click to toggle source
# File lib/jekyll-content-security-policy-generator/hook.rb, line 18 def initialize(document_html) @document_html = document_html @nokogiri = Nokogiri::HTML(document_html) @csp_frame_src = ['\'self\''] @csp_image_src = ['\'self\''] @csp_style_src = ['\'self\''] @csp_script_src = ['\'self\''] @csp_unknown = [] end
Public Instance Methods
convert_all_inline_styles_attributes()
click to toggle source
This function converts elements with style=“color:red” attributes into inline styles
# File lib/jekyll-content-security-policy-generator/hook.rb, line 118 def convert_all_inline_styles_attributes @nokogiri.css('*').each do |find| find_src = find.attr('style') if find_src if find.attr('id') element_id = find.attr('id') else hash = Digest::MD5.hexdigest find_src + "#{Random.rand(11)}" element_id = "csp-gen-" + hash find["id"] = element_id end new_element = "<style>#" + element_id + " { " + find_src + " } </style>" find.remove_attribute("style") if @nokogiri.at('head') @nokogiri.at('head') << new_element Jekyll.logger.info'Converting style attribute to inline style, inserted into HEAD.' else if @nokogiri.at('body') @nokogiri.at('body') << new_element Jekyll.logger.info'Converting style attribute to inline style, inserted into BODY.' else Jekyll.logger.warn'Unable to convert style attribute to inline style, no HEAD or BODY found.' end end end end end
find_iframes()
click to toggle source
Find all iframes
# File lib/jekyll-content-security-policy-generator/hook.rb, line 210 def find_iframes @nokogiri.css('iframe').each do |find| find_src = find.attr('src') if find_src and find_src.start_with?('http', 'https') @csp_frame_src.push find_src.match(/(.*\/)+(.*$)/)[1] end end end
find_images()
click to toggle source
Find all images
# File lib/jekyll-content-security-policy-generator/hook.rb, line 151 def find_images @nokogiri.css('img').each do |find| find_src = find.attr('src') if find_src and find_src.start_with?('http', 'https') @csp_image_src.push find_src.match(/(.*\/)+(.*$)/)[1] end end @nokogiri.css('style').each do |find| finds = find.content.scan(/url\(([^\)]+)\)/) finds.each do |innerFind| innerFind = innerFind[0] innerFind = innerFind.tr('\'"', '') if innerFind.start_with?('http', 'https') @csp_image_src.push self.get_domain(innerFind) end end end end
find_scripts()
click to toggle source
Find all scripts
# File lib/jekyll-content-security-policy-generator/hook.rb, line 176 def find_scripts @nokogiri.css('script').each do |find| if find.attr('src') find_src = find.attr('src') if find_src and find_src.start_with?('http', 'https') @csp_script_src.push find_src.match(/(.*\/)+(.*$)/)[1] end else @csp_script_src.push self.generate_sha256_content_hash find.content end end end
find_styles()
click to toggle source
Find all stylesheets
# File lib/jekyll-content-security-policy-generator/hook.rb, line 193 def find_styles @nokogiri.css('style').each do |find| if find.attr('src') find_src = find.attr('src') if find_src and find_src.start_with?('http', 'https') @csp_style_src.push find_src.match(/(.*\/)+(.*$)/)[1] end else @csp_style_src.push self.generate_sha256_content_hash find.content end end end
generate_convert_security_policy_meta_tag()
click to toggle source
Creates an HTML content security policy meta tag.
# File lib/jekyll-content-security-policy-generator/hook.rb, line 31 def generate_convert_security_policy_meta_tag meta_content = "" @csp_script_src = @csp_script_src.uniq @csp_image_src = @csp_image_src.uniq @csp_style_src = @csp_style_src.uniq @csp_script_src = @csp_script_src.uniq @csp_unknown = @csp_unknown.uniq if @csp_frame_src.length > 0 @csp_script_src.uniq meta_content += "frame-src " + @csp_frame_src.join(' ') + '; ' end if @csp_image_src.length > 0 meta_content += "img-src " + @csp_image_src.join(' ') + '; ' end if @csp_style_src.length > 0 meta_content += "style-src " + @csp_style_src.join(' ') + '; ' end if @csp_script_src.length > 0 meta_content += "script-src " + @csp_script_src.join(' ') + '; ' end if @csp_unknown.length > 0 @csp_unknown.each do |find| find_name = find[0] find = find.drop(1) meta_content += find_name + " " + find.join(' ') + '; ' end end if @nokogiri.at("head") Jekyll.logger.info "Generated content security policy, inserted in HEAD." @nokogiri.at("head") << "<meta http-equiv=\"Content-Security-Policy\" content=\"" + meta_content + "\">" elsif @nokogiri.at("body") Jekyll.logger.info "Generated content security policy, inserted in BODY." @nokogiri.at("body") << "<meta http-equiv=\"Content-Security-Policy\" content=\"" + meta_content + "\">" else Jekyll.logger.error "Generated content security policy but found no-where to insert it." end end
generate_sha256_content_hash(content)
click to toggle source
Generate a content hash
# File lib/jekyll-content-security-policy-generator/hook.rb, line 227 def generate_sha256_content_hash(content) hash = Digest::SHA2.base64digest content "'sha256-#{hash}'" end
get_domain(url)
click to toggle source
# File lib/jekyll-content-security-policy-generator/hook.rb, line 220 def get_domain(url) uri = URI.parse(url) "#{uri.scheme}://#{uri.host}" end
parse_existing_meta_element()
click to toggle source
Parse an existing content security policy meta tag
# File lib/jekyll-content-security-policy-generator/hook.rb, line 79 def parse_existing_meta_element() csp = @nokogiri.at('meta[http-equiv="Content-Security-Policy"]') if csp content = csp.attr('content') content = content.strip! || content policies = content.split(';') policies.each do |policy| policy = policy.strip! || policy if policy.include? ' ' policy_parts = policy.split(' ') if policy_parts[0] == 'script-src' @csp_script_src.concat(policy_parts.drop(1)) elsif policy_parts[0] == 'style-src' @csp_style_src.concat(policy_parts.drop(1)) elsif policy_parts[0] == 'img-src' @csp_image_src.concat(policy_parts.drop(1)) elsif policy_parts[0] == 'frame-src' @csp_frame_src.concat(policy_parts.drop(1)) else @csp_unknown.concat([policy_parts]) end else Jekyll.logger.warn "Incorrect existing content security policy meta tag found, skipping." end end @nokogiri.search('meta[http-equiv="Content-Security-Policy"]').each do |el| el.remove end end end
run()
click to toggle source
Builds an HTML meta tag based on the found inline scripts and style hashes
# File lib/jekyll-content-security-policy-generator/hook.rb, line 234 def run self.parse_existing_meta_element self.convert_all_inline_styles_attributes # Find elements in document self.find_images self.find_styles self.find_scripts self.find_iframes self.generate_convert_security_policy_meta_tag @nokogiri.to_html end