Merge pull request #105 from spagalloco/x-download-options

X-Download-Options header support
This commit is contained in:
Neil Matatall 2014-08-28 11:35:41 -07:00
Родитель ff4da2f22c 7e6aae5431
Коммит e35ec69f90
9 изменённых файлов: 123 добавлений и 3 удалений

Просмотреть файл

@ -25,6 +25,11 @@ describe OtherThingsController, :type => :controller do
expect(response.headers['Strict-Transport-Security']).to eq("max-age=315576000")
end
it "sets the X-Download-Options header" do
get :index
expect(response.headers['X-Download-Options']).to eq('noopen')
end
it "sets the X-Content-Type-Options header" do
get :index
expect(response.headers['X-Content-Type-Options']).to eq("nosniff")

Просмотреть файл

@ -28,6 +28,11 @@ describe ThingsController, :type => :controller do
expect(response.headers['Strict-Transport-Security']).to eq("max-age=315576000")
end
it "sets the X-Download-Options header" do
get :index
expect(response.headers['X-Download-Options']).to eq('noopen')
end
it "sets the X-Content-Type-Options header" do
get :index
expect(response.headers['X-Content-Type-Options']).to eq("nosniff")

Просмотреть файл

@ -24,6 +24,11 @@ describe OtherThingsController, :type => :controller do
expect(response.headers['Strict-Transport-Security']).to eq(SecureHeaders::StrictTransportSecurity::Constants::DEFAULT_VALUE)
end
it "sets the X-Download-Options header" do
get :index
expect(response.headers['X-Download-Options']).to eq(SecureHeaders::XDownloadOptions::Constants::DEFAULT_VALUE)
end
it "sets the X-Content-Type-Options header" do
get :index
expect(response.headers['X-Content-Type-Options']).to eq(SecureHeaders::XContentTypeOptions::Constants::DEFAULT_VALUE)

Просмотреть файл

@ -28,6 +28,11 @@ describe ThingsController, :type => :controller do
expect(response.headers['Strict-Transport-Security']).to eq(SecureHeaders::StrictTransportSecurity::Constants::DEFAULT_VALUE)
end
it "sets the X-Download-Options header" do
get :index
expect(response.headers['X-Download-Options']).to eq(SecureHeaders::XDownloadOptions::Constants::DEFAULT_VALUE)
end
it "sets the X-Content-Type-Options header" do
get :index
expect(response.headers['X-Content-Type-Options']).to eq(SecureHeaders::XContentTypeOptions::Constants::DEFAULT_VALUE)

Просмотреть файл

@ -2,7 +2,7 @@ module SecureHeaders
module Configuration
class << self
attr_accessor :hsts, :x_frame_options, :x_content_type_options,
:x_xss_protection, :csp
:x_xss_protection, :csp, :x_download_options
def configure &block
instance_eval &block
@ -38,6 +38,7 @@ module SecureHeaders
before_filter :set_csp_header
before_filter :set_x_xss_protection_header
before_filter :set_x_content_type_options_header
before_filter :set_x_download_options_header
end
# we can't use ||= because I'm overloading false => disable, nil => default
@ -55,6 +56,7 @@ module SecureHeaders
set_x_frame_options_header(options[:x_frame_options])
set_x_xss_protection_header(options[:x_xss_protection])
set_x_content_type_options_header(options[:x_content_type_options])
set_x_download_options_header(options[:x_download_options])
end
# backwards compatibility jank, to be removed in 1.0. Old API required a request
@ -99,6 +101,10 @@ module SecureHeaders
set_a_header(:hsts, StrictTransportSecurity, options)
end
def set_x_download_options_header(options=self.class.secure_headers_options[:x_download_options])
set_a_header(:x_download_options, XDownloadOptions, options)
end
private
def set_a_header(name, klass, options=nil)
@ -128,4 +134,5 @@ require "secure_headers/headers/x_frame_options"
require "secure_headers/headers/strict_transport_security"
require "secure_headers/headers/x_xss_protection"
require "secure_headers/headers/x_content_type_options"
require "secure_headers/headers/x_download_options"
require "secure_headers/railtie"

Просмотреть файл

@ -0,0 +1,39 @@
module SecureHeaders
class XDOBuildError < StandardError; end
class XDownloadOptions < Header
module Constants
XDO_HEADER_NAME = "X-Download-Options"
DEFAULT_VALUE = 'noopen'
end
include Constants
def initialize(config = nil)
@config = config
validate_config unless @config.nil?
end
def name
XDO_HEADER_NAME
end
def value
case @config
when NilClass
DEFAULT_VALUE
when String
@config
else
@config[:value]
end
end
private
def validate_config
value = @config.is_a?(Hash) ? @config[:value] : @config
unless value.casecmp(DEFAULT_VALUE) == 0
raise XDOBuildError.new("Value can only be nil or 'noopen'")
end
end
end
end

Просмотреть файл

@ -0,0 +1,32 @@
module SecureHeaders
describe XDownloadOptions do
specify { expect(XDownloadOptions.new.name).to eq(XDO_HEADER_NAME)}
specify { expect(XDownloadOptions.new.value).to eq("noopen")}
specify { expect(XDownloadOptions.new('noopen').value).to eq('noopen')}
specify { expect(XDownloadOptions.new(:value => 'noopen').value).to eq('noopen') }
context "invalid configuration values" do
it "accepts noopen" do
expect {
XDownloadOptions.new("noopen")
}.not_to raise_error
expect {
XDownloadOptions.new(:value => "noopen")
}.not_to raise_error
end
it "accepts nil" do
expect {
XDownloadOptions.new
}.not_to raise_error
end
it "doesn't accept anything besides noopen" do
expect {
XContentTypeOptions.new("open")
}.to raise_error
end
end
end
end

Просмотреть файл

@ -54,6 +54,7 @@ describe SecureHeaders do
config.x_content_type_options = nil
config.x_xss_protection = nil
config.csp = nil
config.x_download_options = nil
end
end
@ -63,12 +64,13 @@ describe SecureHeaders do
subject.set_x_frame_options_header
subject.set_x_content_type_options_header
subject.set_x_xss_protection_header
subject.set_x_download_options_header
end
describe "#ensure_security_headers" do
it "sets a before filter" do
options = {}
expect(DummyClass).to receive(:before_filter).exactly(5).times
expect(DummyClass).to receive(:before_filter).exactly(6).times
DummyClass.ensure_security_headers(options)
end
end
@ -92,13 +94,14 @@ describe SecureHeaders do
USER_AGENTS.each do |name, useragent|
it "sets all default headers for #{name} (smoke test)" do
stub_user_agent(useragent)
number_of_headers = 5
number_of_headers = 6
expect(subject).to receive(:set_header).exactly(number_of_headers).times # a request for a given header
subject.set_csp_header
subject.set_x_frame_options_header
subject.set_hsts_header
subject.set_x_xss_protection_header
subject.set_x_content_type_options_header
subject.set_x_download_options_header
end
end
@ -113,6 +116,11 @@ describe SecureHeaders do
subject.set_x_xss_protection_header(false)
end
it "does not set the X-Download-Options header if disabled" do
should_not_assign_header(XDO_HEADER_NAME)
subject.set_x_download_options_header(false)
end
it "does not set the X-Frame-Options header if disabled" do
should_not_assign_header(XFO_HEADER_NAME)
subject.set_x_frame_options_header(false)
@ -143,6 +151,7 @@ describe SecureHeaders do
config.x_content_type_options = false
config.x_xss_protection = false
config.csp = false
config.x_download_options = false
end
expect(subject).not_to receive(:set_header)
set_security_headers(subject)
@ -163,6 +172,18 @@ describe SecureHeaders do
end
end
describe "#set_x_download_options_header" do
it "sets the X-Download-Options header" do
should_assign_header(XDO_HEADER_NAME, SecureHeaders::XDownloadOptions::Constants::DEFAULT_VALUE)
subject.set_x_download_options_header
end
it "allows a custom X-Download-Options header" do
should_assign_header(XDO_HEADER_NAME, "noopen")
subject.set_x_download_options_header(:value => 'noopen')
end
end
describe "#set_strict_transport_security" do
it "sets the Strict-Transport-Security header" do
should_assign_header(HSTS_HEADER_NAME, SecureHeaders::StrictTransportSecurity::Constants::DEFAULT_VALUE)

Просмотреть файл

@ -8,3 +8,4 @@ include ::SecureHeaders::ContentSecurityPolicy::Constants
include ::SecureHeaders::XFrameOptions::Constants
include ::SecureHeaders::XXssProtection::Constants
include ::SecureHeaders::XContentTypeOptions::Constants
include ::SecureHeaders::XDownloadOptions::Constants