diff --git a/Gemfile b/Gemfile
index 567d4c09..d6e4e4ae 100644
--- a/Gemfile
+++ b/Gemfile
@@ -11,6 +11,7 @@ group :app do
gem 'rack'
gem 'sinatra'
gem 'sinatra-contrib'
+ gem 'rack-ssl-enforcer'
gem 'thin'
gem 'sprockets'
gem 'sprockets-helpers'
diff --git a/Gemfile.lock b/Gemfile.lock
index eb4a3210..0e177c4d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -63,6 +63,7 @@ GEM
rack (2.0.5)
rack-protection (2.0.4)
rack
+ rack-ssl-enforcer (0.2.9)
rack-test (1.1.0)
rack (>= 1.0, < 3)
rake (12.3.1)
@@ -140,6 +141,7 @@ DEPENDENCIES
progress_bar
pry (~> 0.11.0)
rack
+ rack-ssl-enforcer
rack-test
rake
rr
diff --git a/assets/javascripts/lib/page.coffee b/assets/javascripts/lib/page.coffee
index 8df7422e..5d3f6c88 100644
--- a/assets/javascripts/lib/page.coffee
+++ b/assets/javascripts/lib/page.coffee
@@ -190,7 +190,7 @@ isSameOrigin = (url) ->
updateCanonicalLink = ->
@canonicalLink ||= document.head.querySelector('link[rel="canonical"]')
- @canonicalLink.setAttribute('href', "http://#{location.host}#{location.pathname}")
+ @canonicalLink.setAttribute('href', "https://#{location.host}#{location.pathname}")
trackers = []
diff --git a/assets/javascripts/templates/pages/root_tmpl.coffee.erb b/assets/javascripts/templates/pages/root_tmpl.coffee.erb
index ef5ee8e6..b5369403 100644
--- a/assets/javascripts/templates/pages/root_tmpl.coffee.erb
+++ b/assets/javascripts/templates/pages/root_tmpl.coffee.erb
@@ -72,14 +72,3 @@ app.templates.androidWarning = """
To install DevDocs on your phone, visit devdocs.io in Chrome and select "Add to home screen" in the menu.
"""
-
-app.templates.httpWarning = """
-
-
Hi there!
-
DevDocs is migrating to HTTPS.
-
Please update your bookmarks to point to https://devdocs.io.
-
When using the HTTPS version, your preferences will carry over automatically, but your offline data will be reset. Simply re-download documentation in the Offline area, and you'll be all set to use DevDocs securely offline.
-
Sorry for the inconvenience. This migration is needed because browsers are removing support for certain DOM APIs that power DevDocs's offline mode over non-secure origins.
-
Thanks for using DevDocs, and happy coding!
-
-"""
diff --git a/assets/javascripts/views/content/root_page.coffee b/assets/javascripts/views/content/root_page.coffee
index e442887a..b48a1df3 100644
--- a/assets/javascripts/views/content/root_page.coffee
+++ b/assets/javascripts/views/content/root_page.coffee
@@ -19,10 +19,6 @@ class app.views.RootPage extends app.View
else
'intro'
- # temporary
- if location.host is 'devdocs.io' and location.protocol is 'http:'
- tmpl = 'httpWarning'
-
@append @tmpl(tmpl)
return
diff --git a/lib/app.rb b/lib/app.rb
index b5015b3a..f8ef0454 100644
--- a/lib/app.rb
+++ b/lib/app.rb
@@ -12,6 +12,8 @@ class App < Sinatra::Application
Rack::Mime::MIME_TYPES['.webapp'] = 'application/x-web-app-manifest+json'
configure do
+ use Rack::SslEnforcer, only_environments: ['production', 'test'], hsts: false, force_secure_cookies: false
+
set :sentry_dsn, ENV['SENTRY_DSN']
set :protection, except: [:frame_options, :xss_header]
diff --git a/test/app_test.rb b/test/app_test.rb
index 5401e3ae..4e836a19 100644
--- a/test/app_test.rb
+++ b/test/app_test.rb
@@ -11,6 +11,16 @@ class AppTest < MiniTest::Spec
App
end
+ before do
+ current_session.env('HTTPS', 'on')
+ end
+
+ it 'redirects to HTTPS' do
+ get 'http://example.com/test?q=1', {}, 'HTTPS' => 'off'
+ assert last_response.redirect?
+ assert_equal 'https://example.com/test?q=1', last_response['Location']
+ end
+
describe "/" do
it "works" do
get '/'
@@ -20,13 +30,13 @@ class AppTest < MiniTest::Spec
it "redirects to /#q= when there is a 'q' query param" do
get '/search', q: 'foo'
assert last_response.redirect?
- assert_equal 'http://example.org/#q=foo', last_response['Location']
+ assert_equal 'https://example.org/#q=foo', last_response['Location']
end
it "redirects without the query string" do
get '/', foo: 'bar'
assert last_response.redirect?
- assert_equal 'http://example.org/', last_response['Location']
+ assert_equal 'https://example.org/', last_response['Location']
end
it "sets default size" do
@@ -52,7 +62,7 @@ class AppTest < MiniTest::Spec
%w(offline about news help).each do |page|
get "/#{page}", {}, 'HTTP_USER_AGENT' => MODERN_BROWSER
assert last_response.redirect?
- assert_equal "http://example.org/#/#{page}", last_response['Location']
+ assert_equal "https://example.org/#/#{page}", last_response['Location']
end
end
@@ -61,7 +71,7 @@ class AppTest < MiniTest::Spec
set_cookie('foo=bar')
get "/#{page}", {}, 'HTTP_USER_AGENT' => MODERN_BROWSER
assert last_response.redirect?
- assert_equal 'http://example.org/', last_response['Location']
+ assert_equal 'https://example.org/', last_response['Location']
assert last_response['Set-Cookie'].start_with?("initial_path=%2F#{page}; path=/; expires=")
end
end
@@ -71,11 +81,11 @@ class AppTest < MiniTest::Spec
it "redirects to /#q=" do
get '/search'
assert last_response.redirect?
- assert_equal 'http://example.org/#q=', last_response['Location']
+ assert_equal 'https://example.org/#q=', last_response['Location']
get '/search', q: 'foo'
assert last_response.redirect?
- assert_equal 'http://example.org/#q=foo', last_response['Location']
+ assert_equal 'https://example.org/#q=foo', last_response['Location']
end
end
@@ -148,7 +158,7 @@ class AppTest < MiniTest::Spec
set_cookie('docs=html~5')
get '/html~5/', {}, 'HTTP_USER_AGENT' => MODERN_BROWSER
assert last_response.redirect?
- assert_equal 'http://example.org/', last_response['Location']
+ assert_equal 'https://example.org/', last_response['Location']
assert last_response['Set-Cookie'].start_with?("initial_path=%2Fhtml%7E5%2F; path=/; expires=")
end
@@ -161,13 +171,13 @@ class AppTest < MiniTest::Spec
set_cookie('docs=html~5')
get '/html/', {}, 'HTTP_USER_AGENT' => MODERN_BROWSER
assert last_response.redirect?
- assert_equal 'http://example.org/', last_response['Location']
+ assert_equal 'https://example.org/', last_response['Location']
assert last_response['Set-Cookie'].start_with?("initial_path=%2Fhtml%2F; path=/; expires=")
end
it "renders when the doc exists and is enabled, and the request is from Googlebot" do
set_cookie('docs=html')
- get '/html/', {}, 'HTTP_USER_AGENT' => 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)'
+ get '/html/', {}, 'HTTP_USER_AGENT' => 'Mozilla/5.0 (compatible; Googlebot/2.1; +https://www.google.com/bot.html)'
assert last_response.ok?
end
@@ -187,17 +197,17 @@ class AppTest < MiniTest::Spec
it "redirects with trailing slash" do
get '/html'
assert last_response.redirect?
- assert_equal 'http://example.org/html/', last_response['Location']
+ assert_equal 'https://example.org/html/', last_response['Location']
get '/html', bar: 'baz'
assert last_response.redirect?
- assert_equal 'http://example.org/html/?bar=baz', last_response['Location']
+ assert_equal 'https://example.org/html/?bar=baz', last_response['Location']
end
it "redirects old docs" do
get '/iojs/'
assert last_response.redirect?
- assert_equal 'http://example.org/node/', last_response['Location']
+ assert_equal 'https://example.org/node/', last_response['Location']
end
end
@@ -232,17 +242,17 @@ class AppTest < MiniTest::Spec
it "redirects with trailing slash" do
get '/css-foo'
assert last_response.redirect?
- assert_equal 'http://example.org/css-foo/', last_response['Location']
+ assert_equal 'https://example.org/css-foo/', last_response['Location']
get '/css-foo', bar: 'baz'
assert last_response.redirect?
- assert_equal 'http://example.org/css-foo/?bar=baz', last_response['Location']
+ assert_equal 'https://example.org/css-foo/?bar=baz', last_response['Location']
end
it "redirects old docs" do
get '/yii1-foo/'
assert last_response.redirect?
- assert_equal 'http://example.org/yii~1.1-foo/', last_response['Location']
+ assert_equal 'https://example.org/yii~1.1-foo/', last_response['Location']
end
end
@@ -263,17 +273,17 @@ class AppTest < MiniTest::Spec
it "redirects without trailing slash" do
get '/css/foo/'
assert last_response.redirect?
- assert_equal 'http://example.org/css/foo', last_response['Location']
+ assert_equal 'https://example.org/css/foo', last_response['Location']
get '/css/foo/', bar: 'baz'
assert last_response.redirect?
- assert_equal 'http://example.org/css/foo?bar=baz', last_response['Location']
+ assert_equal 'https://example.org/css/foo?bar=baz', last_response['Location']
end
it "redirects old docs" do
get '/python2/foo'
assert last_response.redirect?
- assert_equal 'http://example.org/python~2.7/foo', last_response['Location']
+ assert_equal 'https://example.org/python~2.7/foo', last_response['Location']
end
end
@@ -281,7 +291,7 @@ class AppTest < MiniTest::Spec
it "returns to the asset path" do
get '/docs.json'
assert last_response.redirect?
- assert_equal 'http://example.org/assets/docs.json', last_response['Location']
+ assert_equal 'https://example.org/assets/docs.json', last_response['Location']
end
end
@@ -289,7 +299,7 @@ class AppTest < MiniTest::Spec
it "returns to the asset path" do
get '/application.js'
assert last_response.redirect?
- assert_equal 'http://example.org/assets/application.js', last_response['Location']
+ assert_equal 'https://example.org/assets/application.js', last_response['Location']
end
end
@@ -297,7 +307,7 @@ class AppTest < MiniTest::Spec
it "returns to the asset path" do
get '/application.css'
assert last_response.redirect?
- assert_equal 'http://example.org/assets/application.css', last_response['Location']
+ assert_equal 'https://example.org/assets/application.css', last_response['Location']
end
end