aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock4
-rw-r--r--app/models/censor_rule.rb5
-rw-r--r--app/models/info_request.rb5
-rw-r--r--app/models/outgoing_message.rb47
-rw-r--r--config/initializers/alaveteli.rb2
-rw-r--r--config/packages.debian-wheezy1
-rw-r--r--lib/attachment_to_html/adapters/pdf.rb4
-rw-r--r--lib/configuration.rb4
-rwxr-xr-xscript/mailin2
-rw-r--r--spec/factories/info_requests.rb2
-rw-r--r--spec/integration/download_request_spec.rb3
-rw-r--r--spec/models/censor_rule_spec.rb36
-rw-r--r--spec/models/outgoing_message_spec.rb109
-rw-r--r--spec/models/post_redirect_spec.rb1
15 files changed, 176 insertions, 51 deletions
diff --git a/Gemfile b/Gemfile
index f1ea6e307..a836653d0 100644
--- a/Gemfile
+++ b/Gemfile
@@ -28,7 +28,7 @@ gem 'rails-i18n', '~> 0.7.3'
gem 'recaptcha', '~> 0.3.1', :require => 'recaptcha/rails'
gem 'rmagick', '~> 2.14.0'
gem 'ruby-msg', '~> 1.5.0', :git => 'https://github.com/mysociety/ruby-msg.git'
-gem 'secure_headers', '~> 1.3.4'
+gem 'secure_headers', '~> 2.0.2'
gem 'statistics2', '~> 0.54'
gem 'syslog_protocol', '~> 0.9.2'
gem 'thin', '~> 1.5.1'
diff --git a/Gemfile.lock b/Gemfile.lock
index b9e0f3380..9353b9145 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -244,7 +244,7 @@ GEM
railties (~> 3.2.0)
sass (>= 3.1.10)
tilt (~> 1.3)
- secure_headers (1.3.4)
+ secure_headers (2.0.2)
simplecov (0.7.1)
multi_json (~> 1.0)
simplecov-html (~> 0.7.1)
@@ -353,7 +353,7 @@ DEPENDENCIES
ruby-debug (~> 0.10.4)
ruby-msg (~> 1.5.0)!
sass-rails (~> 3.2.3)
- secure_headers (~> 1.3.4)
+ secure_headers (~> 2.0.2)
spork-rails (~> 3.2.1)
statistics2 (~> 0.54)
syslog_protocol (~> 0.9.2)
diff --git a/app/models/censor_rule.rb b/app/models/censor_rule.rb
index 3b5c2d805..58170f237 100644
--- a/app/models/censor_rule.rb
+++ b/app/models/censor_rule.rb
@@ -42,6 +42,11 @@ class CensorRule < ActiveRecord::Base
:user_id => nil,
:public_body_id => nil } }
+ def apply_to_text(text_to_censor)
+ return nil if text_to_censor.nil?
+ text_to_censor.gsub(to_replace, replacement)
+ end
+
def apply_to_text!(text_to_censor)
return nil if text_to_censor.nil?
text_to_censor.gsub!(to_replace, replacement)
diff --git a/app/models/info_request.rb b/app/models/info_request.rb
index 3ce89be3b..3a81860ad 100644
--- a/app/models/info_request.rb
+++ b/app/models/info_request.rb
@@ -811,8 +811,9 @@ public
# Text from the the initial request, for use in summary display
def initial_request_text
- return '' if outgoing_messages.empty? # mainly for use with incomplete fixtures
- outgoing_messages.first.get_text_for_indexing
+ return '' if outgoing_messages.empty?
+ body_opts = { :censor_rules => applicable_censor_rules }
+ outgoing_messages.first.try(:get_text_for_indexing, true, body_opts) or ''
end
# Returns index of last event which is described or nil if none described.
diff --git a/app/models/outgoing_message.rb b/app/models/outgoing_message.rb
index c2c8ef4f2..4f6318b3d 100644
--- a/app/models/outgoing_message.rb
+++ b/app/models/outgoing_message.rb
@@ -140,22 +140,28 @@ class OutgoingMessage < ActiveRecord::Base
end
end
- def body
- ret = read_attribute(:body)
- if ret.nil?
- return ret
+ # Public: The body text of the OutgoingMessage. The text is cleaned and
+ # CensorRules are applied.
+ #
+ # options - Hash of options
+ # :censor_rules - Array of CensorRules to apply. Defaults to the
+ # applicable_censor_rules of the associated
+ # InfoRequest. (optional)
+ #
+ # Returns a String
+ def body(options = {})
+ text = raw_body.dup
+ return text if text.nil?
+
+ text = clean_text(text)
+
+ # Use the given censor_rules; otherwise fetch them from the associated
+ # info_request
+ censor_rules = options.fetch(:censor_rules) do
+ info_request.try(:applicable_censor_rules) or []
end
- ret = ret.dup
- ret.strip!
- ret.gsub!(/(?:\n\s*){2,}/, "\n\n") # remove excess linebreaks that unnecessarily space it out
-
- # Remove things from censor rules
- unless info_request.nil?
- self.info_request.apply_censor_rules_to_text!(ret)
- end
-
- ret
+ censor_rules.reduce(text) { |text, rule| rule.apply_to_text(text) }
end
def raw_body
@@ -227,8 +233,12 @@ class OutgoingMessage < ActiveRecord::Base
end
# Returns text for indexing / text display
- def get_text_for_indexing(strip_salutation = true)
- text = body.strip
+ def get_text_for_indexing(strip_salutation = true, opts = {})
+ if opts.empty?
+ text = body.strip
+ else
+ text = body(opts).strip
+ end
# Remove salutation
text.sub!(/Dear .+,/, "") if strip_salutation
@@ -332,6 +342,11 @@ class OutgoingMessage < ActiveRecord::Base
errors.add(:what_doing_dummy, _('Please choose what sort of reply you are making.'))
end
end
+
+ # remove excess linebreaks that unnecessarily space it out
+ def clean_text(text)
+ text.strip.gsub(/(?:\n\s*){2,}/, "\n\n")
+ end
end
diff --git a/config/initializers/alaveteli.rb b/config/initializers/alaveteli.rb
index 035d744b8..53a9456d2 100644
--- a/config/initializers/alaveteli.rb
+++ b/config/initializers/alaveteli.rb
@@ -10,7 +10,7 @@ load "debug_helpers.rb"
load "util.rb"
# Application version
-ALAVETELI_VERSION = '0.21.0.26'
+ALAVETELI_VERSION = '0.21.0.27'
# Add new inflection rules using the following format
# (all these examples are active by default):
diff --git a/config/packages.debian-wheezy b/config/packages.debian-wheezy
index 4129aa930..ff1a55d84 100644
--- a/config/packages.debian-wheezy
+++ b/config/packages.debian-wheezy
@@ -35,3 +35,4 @@ wkhtmltopdf-static
wv
xapian-tools
xlhtml
+ttf-bitstream-vera
diff --git a/lib/attachment_to_html/adapters/pdf.rb b/lib/attachment_to_html/adapters/pdf.rb
index 3c18e9d4a..a010b0342 100644
--- a/lib/attachment_to_html/adapters/pdf.rb
+++ b/lib/attachment_to_html/adapters/pdf.rb
@@ -71,10 +71,10 @@ module AttachmentToHTML
@converted ||= Dir.chdir(tmpdir) do
tempfile = create_tempfile(text)
-
html = AlaveteliExternalCommand.run("pdftohtml",
"-nodrm", "-zoom", "1.0", "-stdout", "-enc", "UTF-8",
- "-noframes", tempfile.path, :timeout => 30, :binary_output => false
+ "-noframes", "./#{File.basename(tempfile.path)}",
+ :timeout => 30, :binary_output => false
)
cleanup_tempfile(tempfile)
diff --git a/lib/configuration.rb b/lib/configuration.rb
index 89f148602..b60cc102b 100644
--- a/lib/configuration.rb
+++ b/lib/configuration.rb
@@ -33,8 +33,8 @@ module AlaveteliConfiguration
:DOMAIN => 'localhost:3000',
:DONATION_URL => '',
:ENABLE_WIDGETS => false,
- :EXCEPTION_NOTIFICATIONS_FROM => '',
- :EXCEPTION_NOTIFICATIONS_TO => '',
+ :EXCEPTION_NOTIFICATIONS_FROM => 'errors@localhost',
+ :EXCEPTION_NOTIFICATIONS_TO => 'user-support@localhost',
:FORCE_REGISTRATION_ON_NEW_REQUEST => false,
:FORCE_SSL => true,
:FORWARD_NONBOUNCE_RESPONSES_TO => 'user-support@localhost',
diff --git a/script/mailin b/script/mailin
index 65f9d06f2..5f2a9c243 100755
--- a/script/mailin
+++ b/script/mailin
@@ -23,7 +23,7 @@ then
SUBJ="Mail import error for $OPTION_DOMAIN"
BODY="There was an error code $ERROR_CODE returned by the RequestMailer.receive command in script/mailin. See attached for details. This might be quite serious, such as the database was down, or might be an email with corrupt headers that Rails is choking on. We returned the email with an exit code 75, which for Exim at least instructs the MTA to try again later. A well configured installation of this code will separately have had Exim make a backup copy of the email in a separate mailbox, just in case."
FROM="$OPTION_BLACKHOLE_PREFIX@$OPTION_INCOMING_EMAIL_DOMAIN"
- /usr/bin/mutt -e "set use_envelope_from" -e "set envelope_from_address=$FROM" -s "$SUBJ" -a "$OUTPUT" "$INPUT" -- "$OPTION_FORWARD_NONBOUNCE_RESPONSES_TO" <<<"$BODY"
+ /usr/bin/mutt -e "set use_envelope_from" -e "set envelope_from_address=$FROM" -s "$SUBJ" -a "$OUTPUT" "$INPUT" -- "$OPTION_EXCEPTION_NOTIFICATIONS_TO" <<<"$BODY"
# tell exim error was temporary, so try again later (no point bouncing message to authority)
rm -f "$INPUT" "$OUTPUT"
diff --git a/spec/factories/info_requests.rb b/spec/factories/info_requests.rb
index 8052625cd..ee96bfa89 100644
--- a/spec/factories/info_requests.rb
+++ b/spec/factories/info_requests.rb
@@ -1,7 +1,7 @@
FactoryGirl.define do
factory :info_request do
- title "Example Title"
+ sequence(:title) { |n| "Example Title #{n}" }
public_body
user
diff --git a/spec/integration/download_request_spec.rb b/spec/integration/download_request_spec.rb
index 48b42b11d..c73b85866 100644
--- a/spec/integration/download_request_spec.rb
+++ b/spec/integration/download_request_spec.rb
@@ -143,7 +143,8 @@ describe 'when making a zipfile available' do
it "should update the contents of the zipfile when the request changes" do
- info_request = FactoryGirl.create(:info_request_with_incoming)
+ info_request = FactoryGirl.create(:info_request_with_incoming,
+ :title => 'Example Title')
request_owner = login(info_request.user)
inspect_zip_download(request_owner, info_request) do |zip|
zip.count.should == 1 # just the message
diff --git a/spec/models/censor_rule_spec.rb b/spec/models/censor_rule_spec.rb
index 4ecd2d3e1..77b8cd07a 100644
--- a/spec/models/censor_rule_spec.rb
+++ b/spec/models/censor_rule_spec.rb
@@ -17,6 +17,42 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+describe CensorRule do
+
+ describe :apply_to_text do
+
+ it 'applies the rule to the text' do
+ rule = FactoryGirl.build(:censor_rule, :text => 'secret')
+ text = 'Some secret text'
+ expect(rule.apply_to_text(text)).to eq('Some [REDACTED] text')
+ end
+
+ it 'does not mutate the input' do
+ rule = FactoryGirl.build(:censor_rule, :text => 'secret')
+ text = 'Some secret text'
+ rule.apply_to_text(text)
+ expect(text).to eq('Some secret text')
+ end
+
+ it 'returns the text if the rule is unmatched' do
+ rule = FactoryGirl.build(:censor_rule, :text => 'secret')
+ text = 'Some text'
+ expect(rule.apply_to_text(text)).to eq('Some text')
+ end
+ end
+
+ describe :apply_to_text! do
+
+ it 'mutates the input' do
+ rule = FactoryGirl.build(:censor_rule, :text => 'secret')
+ text = 'Some secret text'
+ rule.apply_to_text!(text)
+ expect(text).to eq('Some [REDACTED] text')
+ end
+
+ end
+end
+
describe CensorRule, "substituting things" do
describe 'when using a text rule' do
diff --git a/spec/models/outgoing_message_spec.rb b/spec/models/outgoing_message_spec.rb
index a3e2d1c68..051f263d2 100644
--- a/spec/models/outgoing_message_spec.rb
+++ b/spec/models/outgoing_message_spec.rb
@@ -18,6 +18,93 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+describe OutgoingMessage do
+
+ describe :initialize do
+
+ it 'does not censor the #body' do
+ attrs = { :status => 'ready',
+ :message_type => 'initial_request',
+ :body => 'abc',
+ :what_doing => 'normal_sort' }
+
+ message = FactoryGirl.create(:outgoing_message, attrs)
+
+ OutgoingMessage.any_instance.should_not_receive(:body).and_call_original
+ OutgoingMessage.find(message.id)
+ end
+
+ end
+
+ describe :body do
+
+ it 'returns the body attribute' do
+ attrs = { :status => 'ready',
+ :message_type => 'initial_request',
+ :body => 'abc',
+ :what_doing => 'normal_sort' }
+
+ message = FactoryGirl.build(:outgoing_message, attrs)
+ expect(message.body).to eq('abc')
+ end
+
+ it 'strips the body of leading and trailing whitespace' do
+ attrs = { :status => 'ready',
+ :message_type => 'initial_request',
+ :body => ' abc ',
+ :what_doing => 'normal_sort' }
+
+ message = FactoryGirl.build(:outgoing_message, attrs)
+ expect(message.body).to eq('abc')
+ end
+
+ it 'removes excess linebreaks that unnecessarily space it out' do
+ attrs = { :status => 'ready',
+ :message_type => 'initial_request',
+ :body => "ab\n\nc\n\n",
+ :what_doing => 'normal_sort' }
+
+ message = FactoryGirl.build(:outgoing_message, attrs)
+ expect(message.body).to eq("ab\n\nc")
+ end
+
+ it "applies the associated request's censor rules to the text" do
+ attrs = { :status => 'ready',
+ :message_type => 'initial_request',
+ :body => 'This sensitive text contains secret info!',
+ :what_doing => 'normal_sort' }
+ message = FactoryGirl.build(:outgoing_message, attrs)
+
+ rules = [FactoryGirl.build(:censor_rule, :text => 'secret'),
+ FactoryGirl.build(:censor_rule, :text => 'sensitive')]
+ InfoRequest.any_instance.stub(:censor_rules).and_return(rules)
+
+ expected = 'This [REDACTED] text contains [REDACTED] info!'
+ expect(message.body).to eq(expected)
+ end
+
+ it "applies the given censor rules to the text" do
+ attrs = { :status => 'ready',
+ :message_type => 'initial_request',
+ :body => 'This sensitive text contains secret info!',
+ :what_doing => 'normal_sort' }
+ message = FactoryGirl.build(:outgoing_message, attrs)
+
+ request_rules = [FactoryGirl.build(:censor_rule, :text => 'secret'),
+ FactoryGirl.build(:censor_rule, :text => 'sensitive')]
+ InfoRequest.any_instance.stub(:censor_rules).and_return(request_rules)
+
+ censor_rules = [FactoryGirl.build(:censor_rule, :text => 'text'),
+ FactoryGirl.build(:censor_rule, :text => 'contains')]
+
+ expected = 'This sensitive [REDACTED] [REDACTED] secret info!'
+ expect(message.body(:censor_rules => censor_rules)).to eq(expected)
+ end
+
+ end
+
+end
+
describe OutgoingMessage, " when making an outgoing message" do
before do
@@ -57,6 +144,7 @@ describe OutgoingMessage, " when making an outgoing message" do
info_request = mock_model(InfoRequest, :public_body => public_body,
:url_title => 'a_test_title',
:title => 'A test title',
+ :applicable_censor_rules => [],
:apply_censor_rules_to_text! => nil,
:is_batch_request_template? => false)
outgoing_message = OutgoingMessage.new({
@@ -155,27 +243,6 @@ describe OutgoingMessage, " when making an outgoing message" do
end
end
-
-describe OutgoingMessage, " when censoring data" do
-
- before do
- @om = outgoing_messages(:useless_outgoing_message)
-
- @censor_rule = CensorRule.new()
- @censor_rule.text = "dog"
- @censor_rule.replacement = "cat"
- @censor_rule.last_edit_editor = "unknown"
- @censor_rule.last_edit_comment = "none"
-
- @om.info_request.censor_rules << @censor_rule
- end
-
- it "should apply censor rules to outgoing messages" do
- @om.read_attribute(:body).should match(/fancy dog/)
- @om.body.should match(/fancy cat/)
- end
-end
-
describe OutgoingMessage, "when validating the format of the message body" do
it 'should handle a salutation with a bracket in it' do
diff --git a/spec/models/post_redirect_spec.rb b/spec/models/post_redirect_spec.rb
index 70b221f10..750e47cc3 100644
--- a/spec/models/post_redirect_spec.rb
+++ b/spec/models/post_redirect_spec.rb
@@ -76,7 +76,6 @@ describe PostRedirect, " when accessing values" do
pr = PostRedirect.new
utf8_params = "--- \n:foo: !binary |\n 0KLQvtCz0LDRiCDR\n"
pr.reason_params_yaml = utf8_params
- puts pr.reason_params
pr.reason_params[:foo].encoding.to_s.should == 'UTF-8' if pr.reason_params[:foo].respond_to?(:encoding)
end
end