Merge pull request #105 from spagalloco/x-download-options
X-Download-Options header support
This commit is contained in:
Коммит
e35ec69f90
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче