Merge branch 'next-minor' into develop
This commit is contained in:
commit
c41fd52f1d
14 changed files with 129 additions and 43 deletions
|
|
@ -50,6 +50,7 @@ Note: Although this is a minor release, the configuration file changed because t
|
|||
* Don't federate to pods that have been offline for an extended period of time [#7120](https://github.com/diaspora/diaspora/pull/7120)
|
||||
* Add In-Reply-To and References headers to notification mails [#7122](https://github.com/diaspora/diaspora/pull/7122)
|
||||
* Directly link to a comment in commented notification mails [#7124](https://github.com/diaspora/diaspora/pull/7124)
|
||||
* Add optional `Content-Security-Policy` header [#7128](https://github.com/diaspora/diaspora/pull/7128)
|
||||
|
||||
# 0.6.0.1
|
||||
|
||||
|
|
|
|||
8
Gemfile
8
Gemfile
|
|
@ -137,6 +137,10 @@ gem "twitter-text", "1.14.0"
|
|||
gem "ruby-oembed", "0.10.1"
|
||||
gem "open_graph_reader", "0.6.1"
|
||||
|
||||
# Security Headers
|
||||
|
||||
gem "secure_headers", "3.4.1"
|
||||
|
||||
# Services
|
||||
|
||||
gem "omniauth", "1.3.1"
|
||||
|
|
@ -211,10 +215,6 @@ group :production do # we don"t install these on travis to speed up test runs
|
|||
gem "rack-google-analytics", "1.2.0"
|
||||
gem "rack-piwik", "0.3.0", require: "rack/piwik"
|
||||
|
||||
# Click-jacking protection
|
||||
|
||||
gem "rack-protection", "1.5.3"
|
||||
|
||||
# Process management
|
||||
|
||||
gem "eye", "0.8.1"
|
||||
|
|
|
|||
|
|
@ -780,6 +780,8 @@ GEM
|
|||
scss_lint (0.49.0)
|
||||
rake (>= 0.9, < 12)
|
||||
sass (~> 3.4.20)
|
||||
secure_headers (3.4.1)
|
||||
useragent
|
||||
securecompare (1.0.0)
|
||||
shellany (0.0.1)
|
||||
shoulda-matchers (3.1.1)
|
||||
|
|
@ -877,6 +879,7 @@ GEM
|
|||
get_process_mem (~> 0)
|
||||
unicorn (>= 4, < 6)
|
||||
url_safe_base64 (0.2.2)
|
||||
useragent (0.16.8)
|
||||
uuid (2.3.8)
|
||||
macaddr (~> 1.0)
|
||||
valid (1.2.0)
|
||||
|
|
@ -993,7 +996,6 @@ DEPENDENCIES
|
|||
rack-cors (= 0.4.0)
|
||||
rack-google-analytics (= 1.2.0)
|
||||
rack-piwik (= 0.3.0)
|
||||
rack-protection (= 1.5.3)
|
||||
rack-rewrite (= 1.5.1)
|
||||
rack-ssl (= 1.4.1)
|
||||
rails (= 4.2.7.1)
|
||||
|
|
@ -1026,6 +1028,7 @@ DEPENDENCIES
|
|||
ruby-oembed (= 0.10.1)
|
||||
rubyzip (= 1.2.0)
|
||||
sass-rails (= 5.0.6)
|
||||
secure_headers (= 3.4.1)
|
||||
shoulda-matchers (= 3.1.1)
|
||||
sidekiq (= 4.1.4)
|
||||
sidekiq-cron (= 0.4.2)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
module AnalyticsHelper
|
||||
def include_mixpanel
|
||||
include_analytics "mixpanel" do
|
||||
javascript_tag do
|
||||
nonced_javascript_tag do
|
||||
<<-JS.html_safe
|
||||
(function(d,c){var a,b,g,e;a=d.createElement('script');a.type='text/javascript';a.async=!0;a.src=('https:'===d.location.protocol?'https:':'http:')+'//api.mixpanel.com/site_media/js/api/mixpanel.2.js';b=d.getElementsByTagName('script')[0];b.parentNode.insertBefore(a,b);c._i=[];c.init=function(a,d,f){var b=c;'undefined'!==typeof f?b=c[f]=[]:f='mixpanel';g='disable track track_pageview track_links track_forms register register_once unregister identify name_tag set_config'.split(' ');
|
||||
for(e=0;e<g.length;e++)(function(a){b[a]=function(){b.push([a].concat(Array.prototype.slice.call(arguments,0)))}})(g[e]);c._i.push([a,d,f])};window.mixpanel=c})(document,[]);
|
||||
|
|
@ -18,7 +18,7 @@ module AnalyticsHelper
|
|||
def include_mixpanel_guid
|
||||
return unless current_user
|
||||
include_analytics "mixpanel" do
|
||||
javascript_tag do
|
||||
nonced_javascript_tag do
|
||||
<<-JS.html_safe
|
||||
mixpanel.name_tag("#{current_user.guid}");
|
||||
JS
|
||||
|
|
@ -28,12 +28,12 @@ module AnalyticsHelper
|
|||
|
||||
def chartbeat_head_block
|
||||
return unless configured?("chartbeat")
|
||||
javascript_tag("var _sf_startpt=(new Date()).getTime()")
|
||||
nonced_javascript_tag("var _sf_startpt=(new Date()).getTime()")
|
||||
end
|
||||
|
||||
def include_chartbeat
|
||||
include_analytics "chartbeat" do
|
||||
javascript_tag do
|
||||
nonced_javascript_tag do
|
||||
<<-JS.html_safe
|
||||
var _sf_async_config = { uid: #{AppConfig.privacy.chartbeat_uid}, domain: "#{AppConfig.pod_uri.host}" };
|
||||
(function() {
|
||||
|
|
|
|||
|
|
@ -53,14 +53,14 @@ module ApplicationHelper
|
|||
buf = []
|
||||
if AppConfig.privacy.jquery_cdn?
|
||||
version = Jquery::Rails::JQUERY_2_VERSION
|
||||
buf << [ javascript_include_tag("//code.jquery.com/jquery-#{version}.min.js") ]
|
||||
buf << [javascript_tag("!window.jQuery && document.write(unescape('#{j javascript_include_tag('jquery2')}'));")]
|
||||
buf << [javascript_include_tag("//code.jquery.com/jquery-#{version}.min.js")]
|
||||
buf << [nonced_javascript_tag("!window.jQuery && document.write(unescape('#{j javascript_include_tag('jquery2')}'));")]
|
||||
else
|
||||
buf << [javascript_include_tag("jquery2")]
|
||||
end
|
||||
buf << [ javascript_include_tag('jquery_ujs') ]
|
||||
buf << [ javascript_tag("jQuery.ajaxSetup({'cache': false});") ]
|
||||
buf << [ javascript_tag("$.fx.off = true;") ] if Rails.env.test?
|
||||
buf << [javascript_include_tag("jquery_ujs")]
|
||||
buf << [nonced_javascript_tag("jQuery.ajaxSetup({'cache': false});")]
|
||||
buf << [nonced_javascript_tag("$.fx.off = true;")] if Rails.env.test?
|
||||
buf.join("\n").html_safe
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ module LayoutHelper
|
|||
end
|
||||
|
||||
def load_javascript_locales(section = 'javascripts')
|
||||
content_tag(:script) do
|
||||
nonced_javascript_tag do
|
||||
<<-JS.html_safe
|
||||
Diaspora.I18n.load(#{get_javascript_strings_for(I18n.locale, section).to_json},
|
||||
"#{I18n.locale}",
|
||||
|
|
@ -51,7 +51,7 @@ module LayoutHelper
|
|||
end
|
||||
|
||||
def old_browser_js_support
|
||||
content_tag(:script) do
|
||||
nonced_javascript_tag do
|
||||
<<-JS.html_safe
|
||||
if(Array.isArray === undefined) {
|
||||
Array.isArray = function (arg) {
|
||||
|
|
|
|||
|
|
@ -2,25 +2,26 @@
|
|||
-# licensed under the Affero General Public License version 3 or later. See
|
||||
-# the COPYRIGHT file.
|
||||
|
||||
:javascript
|
||||
$(document).ready(function () {
|
||||
var data = $.parseJSON( "#{escape_javascript(@contacts_json)}" ),
|
||||
autocompleteInput = $("#contact-autocomplete");
|
||||
%script{nonce: content_security_policy_nonce(:script)}
|
||||
:plain
|
||||
$(document).ready(function () {
|
||||
var data = $.parseJSON( "#{escape_javascript(@contacts_json).html_safe}" ),
|
||||
autocompleteInput = $("#contact-autocomplete");
|
||||
|
||||
autocompleteInput.autoSuggest(data, {
|
||||
selectedItemProp: "name",
|
||||
searchObjProps: "name",
|
||||
asHtmlID: "contact_ids",
|
||||
retrieveLimit: 10,
|
||||
minChars: 1,
|
||||
keyDelay: 0,
|
||||
startText: '',
|
||||
emptyText: "#{t('no_results')}",
|
||||
preFill: [{name : "#{h params[:name]}",
|
||||
value : "#{@contact_ids}"}]
|
||||
});
|
||||
autocompleteInput.focus();
|
||||
});
|
||||
autocompleteInput.autoSuggest(data, {
|
||||
selectedItemProp: "name",
|
||||
searchObjProps: "name",
|
||||
asHtmlID: "contact_ids",
|
||||
retrieveLimit: 10,
|
||||
minChars: 1,
|
||||
keyDelay: 0,
|
||||
startText: '',
|
||||
emptyText: "#{t("no_results")}",
|
||||
preFill: [{name : "#{h params[:name]}",
|
||||
value : "#{@contact_ids}"}]
|
||||
});
|
||||
autocompleteInput.focus();
|
||||
});
|
||||
|
||||
.col-md-6#new_conversation_pane
|
||||
.container-fluid.row
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@
|
|||
= csrf_meta_tag
|
||||
|
||||
|
||||
= include_gon(camel_case: true)
|
||||
= include_gon(camel_case: true, nonce: content_security_policy_nonce(:script))
|
||||
|
||||
%body{ class: "page-#{controller_name} action-#{action_name}" }
|
||||
= yield :before_content
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@
|
|||
|
||||
= yield(:head)
|
||||
|
||||
= include_gon(:camel_case => true)
|
||||
= include_gon(camel_case: true, nonce: content_security_policy_nonce(:script))
|
||||
%body
|
||||
#app
|
||||
= render "layouts/header"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,5 @@ if defined?(Unicorn)
|
|||
end
|
||||
use Rack::Deflater
|
||||
use Rack::InternetExplorerVersion, minimum: 9
|
||||
use Rack::Protection::FrameOptions
|
||||
|
||||
run Diaspora::Application
|
||||
|
|
|
|||
|
|
@ -148,6 +148,9 @@ defaults:
|
|||
default_metas:
|
||||
title: 'diaspora* social network'
|
||||
description: 'diaspora* is the online social world where you are in control.'
|
||||
csp:
|
||||
report_only: true
|
||||
report_uri:
|
||||
services:
|
||||
facebook:
|
||||
enable: false
|
||||
|
|
|
|||
|
|
@ -551,6 +551,26 @@ configuration: ## Section
|
|||
#title: 'diaspora* social network'
|
||||
#description: 'diaspora* is the online social world where you are in control.'
|
||||
|
||||
## CSP (Content Security Policy) header
|
||||
## CSP allows limiting origins from where resources are allowed to be loaded. This
|
||||
## improves security, since it helps to detect and mitigate cross-site scripting
|
||||
## and data injection attacks. The default policy of diaspora* allows all third
|
||||
## party domains from services that are included in diaspora*, like OEmbed
|
||||
## scripts, so you can safely activate it by setting `report_only` to false. If
|
||||
## you customized diaspora* (edited templates or added own JS), additional work
|
||||
## may be required. You can test the policy with the "report_uri". Our default CSP
|
||||
## does not work with Google analytics or Piwik, because they inject JS code that
|
||||
## is blocked by CSP.
|
||||
csp:
|
||||
## Report-Only header (default=true)
|
||||
## By default diaspora* adds only a "Content-Security-Policy-Report-Only" header. If you set
|
||||
## this to false, the "Content-Security-Policy" header is added instead.
|
||||
#report_only: false
|
||||
|
||||
## CSP report URI (default=)
|
||||
## You can set an URI here, where the user agent reports violations as JSON document via a POST request.
|
||||
#report_uri: "/csp_violation_reports"
|
||||
|
||||
## Posting from Diaspora to external services (all are disabled by default).
|
||||
services: ## Section
|
||||
|
||||
|
|
|
|||
59
config/initializers/secure_headers.rb
Normal file
59
config/initializers/secure_headers.rb
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
SecureHeaders::Configuration.default do |config|
|
||||
config.hsts = SecureHeaders::OPT_OUT # added by Rack::SSL
|
||||
|
||||
config.csp = {
|
||||
default_src: %w('none'),
|
||||
child_src: %w('self' www.youtube.com w.soundcloud.com twitter.com platform.twitter.com syndication.twitter.com
|
||||
player.vimeo.com www.mixcloud.com www.dailymotion.com media.ccc.de bandcamp.com
|
||||
www.instagram.com),
|
||||
connect_src: %w('self' embedr.flickr.com geo.query.yahoo.com nominatim.openstreetmap.org api.github.com),
|
||||
font_src: %w('self'),
|
||||
form_action: %w('self' platform.twitter.com syndication.twitter.com),
|
||||
frame_ancestors: %w('self'),
|
||||
img_src: %w('self' data: *),
|
||||
media_src: %w(https:),
|
||||
script_src: %w('self' 'unsafe-eval' platform.twitter.com cdn.syndication.twimg.com widgets.flickr.com
|
||||
embedr.flickr.com platform.instagram.com 'unsafe-inline'),
|
||||
style_src: %w('self' 'unsafe-inline' platform.twitter.com *.twimg.com)
|
||||
}
|
||||
|
||||
if AppConfig.environment.assets.host.present?
|
||||
asset_host = Addressable::URI.parse(AppConfig.environment.assets.host.get).host
|
||||
config.csp[:script_src] << asset_host
|
||||
config.csp[:style_src] << asset_host
|
||||
end
|
||||
|
||||
if AppConfig.chat.enabled?
|
||||
config.csp[:media_src] << "data:"
|
||||
|
||||
unless AppConfig.chat.server.bosh.proxy?
|
||||
config.csp[:connect_src] << "#{AppConfig.pod_uri.host}:#{AppConfig.chat.server.bosh.port}"
|
||||
end
|
||||
end
|
||||
|
||||
if AppConfig.privacy.mixpanel_uid.present?
|
||||
config.csp[:script_src] << "api.mixpanel.com"
|
||||
config.csp[:connect_src] << "api.mixpanel.com"
|
||||
end
|
||||
|
||||
config.csp[:script_src] << "code.jquery.com" if AppConfig.privacy.jquery_cdn?
|
||||
config.csp[:script_src] << "static.chartbeat.com" if AppConfig.privacy.chartbeat_uid.present?
|
||||
config.csp[:form_action] << "www.paypal.com" if AppConfig.settings.paypal_donations.enable?
|
||||
|
||||
config.csp[:report_only] = AppConfig.settings.csp.report_only?
|
||||
config.csp[:report_uri] = [AppConfig.settings.csp.report_uri] if AppConfig.settings.csp.report_uri.present?
|
||||
|
||||
# Add frame-src but don't spam the log with DEPRECATION warnings.
|
||||
# We need frame-src to support older versions of Chrome, because secure_headers handles all Chrome browsers as
|
||||
# "modern" browser, and ignores the version of the browser. We can drop this once we support only Chrome
|
||||
# versions with child-src support.
|
||||
module SecureHeaders
|
||||
class ContentSecurityPolicy
|
||||
private
|
||||
|
||||
def normalize_child_frame_src
|
||||
@config[:frame_src] = @config[:child_src]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -60,11 +60,11 @@ describe ApplicationHelper, :type => :helper do
|
|||
end
|
||||
|
||||
it 'inclues jquery.js from jquery cdn' do
|
||||
expect(jquery_include_tag).to match(/jquery\.com/)
|
||||
expect(helper.jquery_include_tag).to match(/jquery\.com/)
|
||||
end
|
||||
|
||||
it 'falls back to asset pipeline on cdn failure' do
|
||||
expect(jquery_include_tag).to match(/document\.write/)
|
||||
expect(helper.jquery_include_tag).to match(/document\.write/)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -74,17 +74,17 @@ describe ApplicationHelper, :type => :helper do
|
|||
end
|
||||
|
||||
it 'includes jquery.js from asset pipeline' do
|
||||
expect(jquery_include_tag).to match(/jquery2\.js/)
|
||||
expect(jquery_include_tag).not_to match(/jquery\.com/)
|
||||
expect(helper.jquery_include_tag).to match(/jquery2\.js/)
|
||||
expect(helper.jquery_include_tag).not_to match(/jquery\.com/)
|
||||
end
|
||||
end
|
||||
|
||||
it 'inclues jquery_ujs.js' do
|
||||
expect(jquery_include_tag).to match(/jquery_ujs\.js/)
|
||||
expect(helper.jquery_include_tag).to match(/jquery_ujs\.js/)
|
||||
end
|
||||
|
||||
it "disables ajax caching" do
|
||||
expect(jquery_include_tag).to match(/jQuery\.ajaxSetup/)
|
||||
expect(helper.jquery_include_tag).to match(/jQuery\.ajaxSetup/)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue