Skip to content

Commit 6114b79

Browse files
committed
Ensure signed tokens exist during rollout
Until all existing pengin signatures have been verified it's possible that signed_token may be nil so generate it dynamically if it's not been set. This ensures that anyone following the verify link sees the signed page and any existing sharing of a signed link with a token in the url gets redirected to the petition page.
1 parent 5547d48 commit 6114b79

2 files changed

Lines changed: 64 additions & 0 deletions

File tree

app/models/signature.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,10 @@ def validate!(now = Time.current)
374374
attributes[:constituency_id] = new_constituency_id
375375
end
376376

377+
unless signed_token?
378+
attributes[:signed_token] = Authlogic::Random.friendly_token
379+
end
380+
377381
update_columns(attributes)
378382
end
379383
end
@@ -447,6 +451,10 @@ def constituency
447451
end
448452
end
449453

454+
def signed_token
455+
super || generate_and_save_signed_token
456+
end
457+
450458
def get_email_sent_at_for(timestamp)
451459
self[column_name_for(timestamp)]
452460
end
@@ -488,6 +496,20 @@ def generate_uuid
488496
Digest::UUID.uuid_v5(Digest::UUID::URL_NAMESPACE, "mailto:#{email}")
489497
end
490498

499+
def generate_and_save_signed_token
500+
token = Authlogic::Random.friendly_token
501+
502+
retry_lock do
503+
if signed_token?
504+
token = read_attribute(:signed_token)
505+
else
506+
update_column(:signed_token, token)
507+
end
508+
end
509+
510+
token
511+
end
512+
491513
def column_name_for(timestamp)
492514
self.class.column_name_for(timestamp)
493515
end

spec/models/signature_spec.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,16 @@
12741274
expect{ signature.validate! }.to change{ petition.reload.signature_count }.by(0)
12751275
end
12761276

1277+
it "generates a signed_token if it's missing" do
1278+
signature.update_column(:signed_token, nil)
1279+
1280+
expect {
1281+
signature.validate!
1282+
}.to change {
1283+
signature.reload[:signed_token]
1284+
}.from(nil).to(be_present)
1285+
end
1286+
12771287
it 'tells the relevant constituency petition journal to record a new signature' do
12781288
expect(ConstituencyPetitionJournal).to receive(:record_new_signature_for).with(signature)
12791289
signature.validate!
@@ -1697,6 +1707,38 @@
16971707
end
16981708
end
16991709

1710+
describe "#signed_token" do
1711+
let(:signature) { FactoryBot.create(:validated_signature) }
1712+
1713+
context "when the underlying column is nil" do
1714+
before do
1715+
signature.update_column(:signed_token, nil)
1716+
end
1717+
1718+
it "generates and saves a new token" do
1719+
expect {
1720+
signature.signed_token
1721+
}.to change {
1722+
signature.reload[:signed_token]
1723+
}.from(nil).to(be_present)
1724+
end
1725+
end
1726+
1727+
context "when another process has updated the column" do
1728+
let(:token) { Authlogic::Random.friendly_token }
1729+
1730+
before do
1731+
signature.update_column(:signed_token, nil)
1732+
end
1733+
1734+
it "returns the token from the database" do
1735+
expect(signature).to receive(:signed_token?).and_return(true)
1736+
expect(signature).to receive(:read_attribute).with(:signed_token).and_return(token)
1737+
expect(signature.signed_token).to eq(token)
1738+
end
1739+
end
1740+
end
1741+
17001742
describe 'email sent timestamps' do
17011743
describe '#get_email_sent_at_for' do
17021744
let(:signature) { FactoryBot.create(:validated_signature) }

0 commit comments

Comments
 (0)