Commit 36b1c331 authored by ng's avatar ng

Merge branch '360-setting-fingerprint-without-fingerprint' into 'master'

Resolve "x-set-fingerprint sets empty fingerprint-value in subscription if there is an accidental line-break between E-Mail and Fingerprint"

Closes #360

See merge request schleuder/schleuder!209
parents 3119f5a5 21ca3b3a
......@@ -11,6 +11,12 @@ This project adheres to [Semantic Versioning](http://semver.org/).
* Send replies to keyword-usage and notices to admins regardless of the delivery-flag of their subscription. (#354)
* X-UNSUBSCRIBE will refuse to unsubscribe the last admin of a list. (#357)
* Handle "protected subjects" in a way that Thunderbird/Enigmail recognize. (#74)
* X-SET-FINGERPRINT will not anymore allow setting an empty fingerprint. (#360)
### Added
* To remove a fingerprint from a subscription one can use the new keyword X-UNSET-FINGERPRINT (#360).
### Changed
......
......@@ -5,7 +5,8 @@ module Schleuder
include Singleton
EMAIL_REGEXP = /\A.+@[[:alnum:]_.-]+\z/i
FINGERPRINT_REGEXP = /\A(0x)?[a-f0-9]{32,}\z/i
# TODO: drop v3 keys and only accept length of 40
FINGERPRINT_REGEXP = /\A(0x)?[a-f0-9]{32}([a-f0-9]{8})?\z/i
DEFAULTS = {
'lists_dir' => '/var/lib/schleuder/lists',
......
......@@ -208,5 +208,9 @@ module GPGME
pinentry = File.join(ENV['SCHLEUDER_ROOT'], 'bin', 'pinentry-clearpassphrase')
GPGME::Ctx.spawn_daemon('gpg-agent', "--use-standard-socket --pinentry-program #{pinentry}")
end
def self.valid_fingerprint?(fp)
fp =~ Schleuder::Conf::FINGERPRINT_REGEXP
end
end
end
......@@ -137,8 +137,15 @@ module Schleuder
)
end
sub.fingerprint = arguments.join
fingerprint = arguments.join
unless GPGME::Key.valid_fingerprint?(fingerprint)
return I18n.t(
"plugins.subscription_management.set_fingerprint_requires_valid_fingerprint",
fingerprint: fingerprint
)
end
sub.fingerprint = fingerprint
if sub.save
I18n.t(
"plugins.subscription_management.fingerprint_set",
......@@ -149,7 +156,48 @@ module Schleuder
I18n.t(
"plugins.subscription_management.setting_fingerprint_failed",
email: email,
fingerprint: arguments.last,
fingerprint: sub.fingerprint,
errors: sub.errors.to_a.join("\n")
)
end
end
def self.unset_fingerprint(arguments, list, mail)
if arguments.blank?
return I18n.t(
"plugins.subscription_management.unset_fingerprint_requires_arguments"
)
end
email = arguments.first
unless email == mail.signer.email || list.from_admin?(mail)
return I18n.t(
"plugins.subscription_management.unset_fingerprint_only_self"
)
end
if email == mail.signer.email && list.from_admin?(mail) && arguments.last != 'force'
return I18n.t(
"plugins.subscription_management.unset_fingerprint_requires_arguments"
)
end
sub = list.subscriptions.where(email: email).first
if sub.blank?
return I18n.t(
"plugins.subscription_management.is_not_subscribed", email: email
)
end
sub.fingerprint = ''
if sub.save
I18n.t(
"plugins.subscription_management.fingerprint_unset",
email: email
)
else
I18n.t(
"plugins.subscription_management.unsetting_fingerprint_failed",
email: email,
errors: sub.errors.to_a.join("\n")
)
end
......
class FingerprintValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value =~ /\A[A-F0-9]{32,}\z/
unless GPGME::Key.valid_fingerprint?(value)
record.errors[attribute] << (options[:message] || I18n.t("errors.invalid_fingerprint"))
end
end
......
......@@ -150,6 +150,20 @@ de:
setting_fingerprint_failed: |
Fingerabdruck für %{email} konnte nicht auf %{fingerprint} gesetzt werden:
%{errors}.
set_fingerprint_requires_valid_fingerprint: |
Du hast zu dem Schlüsselwort 'SET-FINGERPRINT' keinen gültigen Wert angegeben.
Es wurde der folgende Wert erkannt: %{fingerprint}
Benötigt werden ein oder zwei Werte, bspw.:
X-SET-FINGERPRINT: 0xB3D190D5235C74E1907EACFE898F2C91E2E6E1F3
oder (als admin):
X-SET-FINGERPRINT: subscription2@hostname 0xB3D190D5235C74E1907EACFE898F2C91E2E6E1F3
Wobei der Fingerprint in der gesamten Länge (40 Zeichen) angegeben werden muss. Optional mit 0x als Präfix.
Um einen Fingerprint zu entfernen kannst du das Schlüsselwort 'UNSET-FINGERPRINT' verwenden.
set_fingerprint_requires_arguments: |
Du hast zu dem Schlüsselwort 'SET-FINGERPRINT' keinen Wert angegeben.
......@@ -158,6 +172,21 @@ de:
oder (als admin):
X-SET-FINGERPRINT: subscription2@hostname 0xB3D190D5235C74E1907EACFE898F2C91E2E6E1F3
Um einen Fingerprint zu entfernen kannst du das Schlüsselwort 'UNSET-FINGERPRINT' verwenden.
unset_fingerprint_only_self: Nur admins dürfen den Fingerabdruck für andere Abos festlegen.
fingerprint_unset: Fingerabdruck für %{email} wurde entfernt.
unsetting_fingerprint_failed: |
Fingerabdruck für %{email} konnte nicht entfernt werden:
%{errors}.
unset_fingerprint_requires_arguments: |
Du hast zu dem Schlüsselwort 'UNSET-FINGERPRINT' keinen Wert angegeben.
Benötigt werden ein Wert, bspw.:
X-UNSET-FINGERPRINT: subscription2@hostname
Als admin musst du um deinen eigenen Fingerabdruck zu entfernen, noch zusätzlich das Argument force mitgeben. bspw.:
X-UNSET-FINGERPRINT: adminsubscription2@hostname force
subscribe_requires_arguments: |
Fehler: Du hast zu dem Schlüsselwort 'SUBSCRIBE' keinen Wert angegeben.
......
......@@ -154,6 +154,20 @@ en:
setting_fingerprint_failed: |
Setting fingerprint for %{email} to %{fingerprint} failed:
%{errors}.
set_fingerprint_requires_valid_fingerprint: |
You did not send a valid fingerprint for the keyword 'SET-FINGERPRINT'
The following value was detected: %{fingerprint}
One or two are required, e.g.:
X-SET-FINGERPRINT: 0xB3D190D5235C74E1907EACFE898F2C91E2E6E1F3
or (as an admin):
X-SET-FINGERPRINT: subscription2@hostname 0xB3D190D5235C74E1907EACFE898F2C91E2E6E1F3
While the fingerprint must be passed in the full length (40 characters). Optionally prefixed with 0x.
To remove a fingerprint you can use the keyword 'UNSET-FINGERPRINT'
set_fingerprint_requires_arguments: |
Error: You did not send any arguments for the keyword 'SET-FINGERPRINT'.
......@@ -162,6 +176,21 @@ en:
or (as an admin):
X-SET-FINGERPRINT: subscription2@hostname 0xB3D190D5235C74E1907EACFE898F2C91E2E6E1F3
To remove a fingerprint you can use the keyword 'UNSET-FINGERPRINT'
unset_fingerprint_only_self: Only admins may remove fingerprints of subscriptions other than their own.
unset_fingerprint_requires_arguments: |
Error: You did not send any arguments for the keyword 'UNSET-FINGERPRINT'
One value is required, e.g.:
X-UNSET-FINGERPRINT: subscription2@hostname
As an admin to unset your own fingerprint you must additionally pass the argument force. E.g.:
X-UNSET-FINGERPRINT: adminsubscription2@hostname force
fingerprint_unset: Fingerprint for %{email} removed.
unsetting_fingerprint_failed: |
Removing fingerprint for %{email} failed:
%{errors}.
subscribe_requires_arguments: |
Error: You did not send any arguments for the keyword 'SUBSCRIBE'.
......
This diff is collapsed.
......@@ -9,7 +9,7 @@ describe GPGME::Key do
expect(key.oneline).to match(/0x59C71FB38AEE22E091C78259D06350440F759BD3 schleuder@example.org \d{4}-\d{2}-\d{2}/)
end
it "displays the expected attributes for an expiring key" do
list = create(:list)
list.import_key(File.read("spec/fixtures/expiring_key.txt"))
......@@ -24,7 +24,7 @@ describe GPGME::Key do
list.import_key(File.read("spec/fixtures/expired_key.txt"))
key = list.key("98769E8A1091F36BD88403ECF71A3F8412D83889")
expect(key.oneline).to match(/0x98769E8A1091F36BD88403ECF71A3F8412D83889 bla@foo \d{4}-\d{2}-\d{2} \[expired: \d{4}-\d{2}-\d{2}\]/)
end
......@@ -33,7 +33,7 @@ describe GPGME::Key do
list.import_key(File.read("spec/fixtures/revoked_key.txt"))
key = list.key("7E783CDE6D1EFE6D2409739C098AC83A4C0028E9")
expect(key.oneline).to match(/0x7E783CDE6D1EFE6D2409739C098AC83A4C0028E9 paz@nadir.org \d{4}-\d{2}-\d{2} \[revoked\]/)
end
......@@ -43,8 +43,35 @@ describe GPGME::Key do
list.import_key(File.read("spec/fixtures/signonly_key.txt"))
key = list.key("B1CD8BB15C2673C6BFD8FA4B70B2CF29E01AD53E")
expect(key.oneline).to match(/0xB1CD8BB15C2673C6BFD8FA4B70B2CF29E01AD53E signonly@example.org \d{4}-\d{2}-\d{2} \[not capable of encryption\]/)
end
end
describe '.valid_fingerprint?' do
context 'valid fingerprints' do
['59C71FB38AEE22E091C78259D06350440F759BD3',
'0x59C71FB38AEE22E091C78259D06350440F759BD3',
'59C71FB38AEE22E091C78259D0635044',
'0x59C71FB38AEE22E091C78259D0635044',
].each do |fp|
it "accepts #{fp} as a valid fingerprint" do
expect(described_class.valid_fingerprint?(fp)).to be_truthy
end
end
end
context 'invalid fingerprints' do
['Z9C71FB38AEE22E091C78259D06350440F759BD3',
'59C71FB38AEE22E091C78259D06350440F759BD3A',
'59C71FB38AEE22E091C78259D06350440F759BD',
'0x59C71FB38AEE22E091C78259D06350440F759B',
'Z9C71FB38AEE22E091C78259D0635044',
'Z9C71FB38AEE22E091C78259D0635044',
].each do |fp|
it "rejects #{fp} as an invalid fingerprint" do
expect(described_class.valid_fingerprint?(fp)).to be_falsey
end
end
end
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment