diff --git a/lib/diaspora_federation/entities.rb b/lib/diaspora_federation/entities.rb index e2748cc..7ab98e9 100644 --- a/lib/diaspora_federation/entities.rb +++ b/lib/diaspora_federation/entities.rb @@ -14,3 +14,4 @@ require "diaspora_federation/entities/location" require "diaspora_federation/entities/photo" require "diaspora_federation/entities/status_message" require "diaspora_federation/entities/request" +require "diaspora_federation/entities/participation" diff --git a/lib/diaspora_federation/entities/participation.rb b/lib/diaspora_federation/entities/participation.rb new file mode 100644 index 0000000..a7f99ce --- /dev/null +++ b/lib/diaspora_federation/entities/participation.rb @@ -0,0 +1,12 @@ +module DiasporaFederation + module Entities + class Participation < Entity + property :guid + property :target_type + property :parent_guid + property :parent_author_signature + property :author_signature + property :diaspora_id, xml_name: :diaspora_handle + end + end +end diff --git a/lib/diaspora_federation/validators.rb b/lib/diaspora_federation/validators.rb index a84f349..5f4c7f3 100644 --- a/lib/diaspora_federation/validators.rb +++ b/lib/diaspora_federation/validators.rb @@ -3,6 +3,7 @@ require "validation/rule/regular_expression" require "validation/rule/length" require "validation/rule/not_empty" require "validation/rule/uri" +require "validation/rule/numeric" # +valid+ gem namespace module Validation @@ -37,3 +38,7 @@ require "diaspora_federation/validators/person_validator" require "diaspora_federation/validators/profile_validator" require "diaspora_federation/validators/web_finger_validator" require "diaspora_federation/validators/request_validator" +require "diaspora_federation/validators/photo_validator" +require "diaspora_federation/validators/location_validator" +require "diaspora_federation/validators/status_message_validator" +require "diaspora_federation/validators/participation_validator" diff --git a/lib/diaspora_federation/validators/location_validator.rb b/lib/diaspora_federation/validators/location_validator.rb new file mode 100644 index 0000000..4a2e91d --- /dev/null +++ b/lib/diaspora_federation/validators/location_validator.rb @@ -0,0 +1,10 @@ +module DiasporaFederation + module Validators + class LocationValidator < Validation::Validator + include Validation + + rule :lat, :not_empty + rule :lng, :not_empty + end + end +end diff --git a/lib/diaspora_federation/validators/participation_validator.rb b/lib/diaspora_federation/validators/participation_validator.rb new file mode 100644 index 0000000..e51739b --- /dev/null +++ b/lib/diaspora_federation/validators/participation_validator.rb @@ -0,0 +1,19 @@ +module DiasporaFederation + module Validators + class ParticipationValidator < Validation::Validator + include Validation + + rule :guid, :guid + + rule :target_type, :not_empty + + rule :parent_guid, :guid + + rule :parent_author_signature, :not_empty + + rule :author_signature, :not_empty + + rule :diaspora_id, %i(not_empty diaspora_id) + end + end +end diff --git a/lib/diaspora_federation/validators/photo_validator.rb b/lib/diaspora_federation/validators/photo_validator.rb new file mode 100644 index 0000000..ffc0680 --- /dev/null +++ b/lib/diaspora_federation/validators/photo_validator.rb @@ -0,0 +1,23 @@ +module DiasporaFederation + module Validators + class PhotoValidator < Validation::Validator + include Validation + + rule :guid, :guid + + rule :diaspora_id, %i(not_empty diaspora_id) + + rule :public, :boolean + + rule :remote_photo_path, :not_empty + + rule :remote_photo_name, :not_empty + + rule :status_message_guid, :guid + + rule :height, :numeric + + rule :width, :numeric + end + end +end diff --git a/lib/diaspora_federation/validators/request_validator.rb b/lib/diaspora_federation/validators/request_validator.rb index 2bd7ec3..fecb7ea 100644 --- a/lib/diaspora_federation/validators/request_validator.rb +++ b/lib/diaspora_federation/validators/request_validator.rb @@ -3,8 +3,8 @@ module DiasporaFederation class RequestValidator < Validation::Validator include Validation - rule :sender_id, %i(not_nil diaspora_id) - rule :recipient_id, %i(not_nil diaspora_id) + rule :sender_id, %i(not_empty diaspora_id) + rule :recipient_id, %i(not_empty diaspora_id) end end end diff --git a/lib/diaspora_federation/validators/status_message_validator.rb b/lib/diaspora_federation/validators/status_message_validator.rb new file mode 100644 index 0000000..04dbb36 --- /dev/null +++ b/lib/diaspora_federation/validators/status_message_validator.rb @@ -0,0 +1,13 @@ +module DiasporaFederation + module Validators + class StatusMessageValidator < Validation::Validator + include Validation + + rule :guid, :guid + + rule :diaspora_id, %i(not_empty diaspora_id) + + rule :public, :boolean + end + end +end diff --git a/spec/factories.rb b/spec/factories.rb index 25fce9b..d68b25d 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -8,6 +8,11 @@ FactoryGirl.define do sequence(:guid) { UUID.generate :compact } sequence(:diaspora_id) {|n| "person-#{n}-#{r_str}@localhost:3000" } sequence(:public_key) { OpenSSL::PKey::RSA.generate(1024).public_key.export } + sequence(:signature) do |i| + abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + ltr = abc[i % abc.length] + "#{ltr * 6}==" + end factory :person do diaspora_id @@ -83,8 +88,30 @@ FactoryGirl.define do remote_photo_path "https://diaspora.example.tld/uploads/images/" remote_photo_name "f2a41e9d2db4d9a199c8.jpg" text "what you see here..." - status_message_guid { guid } + status_message_guid { generate(:guid) } height 480 width 800 end + + factory :participation_entity, class: DiasporaFederation::Entities::Participation do + guid + target_type "StatusMessage" + parent_guid { generate(:guid) } + diaspora_id + parent_author_signature { generate(:signature) } + author_signature { generate(:signature) } + end + + factory :status_message_entity, class: DiasporaFederation::Entities::StatusMessage do + raw_message "i am a very interesting status update" + guid + diaspora_id + public(true) + created_at { Time.zone.now } + end + + factory :request_entity, class: DiasporaFederation::Entities::Request do + sender_id { generate(:diaspora_id) } + recipient_id { generate(:diaspora_id) } + end end diff --git a/spec/lib/diaspora_federation/entities/participation_spec.rb b/spec/lib/diaspora_federation/entities/participation_spec.rb new file mode 100644 index 0000000..5653c41 --- /dev/null +++ b/spec/lib/diaspora_federation/entities/participation_spec.rb @@ -0,0 +1,29 @@ +module DiasporaFederation + describe Entities::Participation do + let(:data) { + {guid: "0123456789abcdef", + target_type: "Post", + parent_guid: "fedcba9876543210", + parent_author_signature: "BBBBBB==", + author_signature: "AAAAAA==", + diaspora_id: "luke@diaspora.example.tld"} + } + + let(:xml) { + <<-XML + + #{data[:guid]} + #{data[:target_type]} + #{data[:parent_guid]} + #{data[:parent_author_signature]} + #{data[:author_signature]} + #{data[:diaspora_id]} + +XML + } + + it_behaves_like "an Entity subclass" + + it_behaves_like "an XML Entity" + end +end diff --git a/spec/lib/diaspora_federation/validators/h_card_validator_spec.rb b/spec/lib/diaspora_federation/validators/h_card_validator_spec.rb index a23887b..3811808 100644 --- a/spec/lib/diaspora_federation/validators/h_card_validator_spec.rb +++ b/spec/lib/diaspora_federation/validators/h_card_validator_spec.rb @@ -3,15 +3,10 @@ module DiasporaFederation let(:entity) { :h_card } def hcard_stub(data={}) - OpenStruct.new(FactoryGirl.attributes_for(:h_card).merge(data)) + entity_stub(entity, data) end - it "validates a well-formed instance" do - validator = Validators::HCardValidator.new(hcard_stub) - - expect(validator).to be_valid - expect(validator.errors).to be_empty - end + it_behaves_like "a common validator" describe "#full_name" do it_behaves_like "a name validator" do diff --git a/spec/lib/diaspora_federation/validators/location_validator_spec.rb b/spec/lib/diaspora_federation/validators/location_validator_spec.rb new file mode 100644 index 0000000..90e09eb --- /dev/null +++ b/spec/lib/diaspora_federation/validators/location_validator_spec.rb @@ -0,0 +1,16 @@ +module DiasporaFederation + describe Validators::LocationValidator do + let(:entity) { :location_entity } + it_behaves_like "a common validator" + + context "#lat and #lng" do + %i(lat lng).each do |prop| + it "must not be empty" do + validator = Validators::LocationValidator.new(entity_stub(entity, prop => "")) + expect(validator).not_to be_valid + expect(validator.errors).to include(prop) + end + end + end + end +end diff --git a/spec/lib/diaspora_federation/validators/participation_validator_spec.rb b/spec/lib/diaspora_federation/validators/participation_validator_spec.rb new file mode 100644 index 0000000..590688d --- /dev/null +++ b/spec/lib/diaspora_federation/validators/participation_validator_spec.rb @@ -0,0 +1,38 @@ +module DiasporaFederation + describe Validators::ParticipationValidator do + let(:entity) { :participation_entity } + + it_behaves_like "a common validator" + + it_behaves_like "a diaspora id validator" do + let(:property) { :diaspora_id } + let(:mandatory) { true } + end + + context "#target_type" do + it "must not be empty" do + validator = Validators::ParticipationValidator.new(entity_stub(entity, target_type: "")) + expect(validator).not_to be_valid + expect(validator.errors).to include(:target_type) + end + end + + context "#guid, #parent_guid" do + %i(guid parent_guid).each do |prop| + it_behaves_like "a guid validator" do + let(:property) { prop } + end + end + end + + context "#author_signature and #parent_author_signature" do + %i(author_signature parent_author_signature).each do |prop| + it "must not be empty" do + validator = Validators::ParticipationValidator.new(entity_stub(entity, prop => "")) + expect(validator).not_to be_valid + expect(validator.errors).to include(prop) + end + end + end + end +end diff --git a/spec/lib/diaspora_federation/validators/person_validator_spec.rb b/spec/lib/diaspora_federation/validators/person_validator_spec.rb index 753cd9c..b973472 100644 --- a/spec/lib/diaspora_federation/validators/person_validator_spec.rb +++ b/spec/lib/diaspora_federation/validators/person_validator_spec.rb @@ -2,13 +2,7 @@ module DiasporaFederation describe Validators::PersonValidator do let(:entity) { :person_entity } - it "validates a well-formed instance" do - instance = OpenStruct.new(FactoryGirl.attributes_for(:person_entity)) - validator = Validators::PersonValidator.new(instance) - - expect(validator).to be_valid - expect(validator.errors).to be_empty - end + it_behaves_like "a common validator" it_behaves_like "a diaspora id validator" do let(:property) { :diaspora_id } diff --git a/spec/lib/diaspora_federation/validators/photo_validator_spec.rb b/spec/lib/diaspora_federation/validators/photo_validator_spec.rb new file mode 100644 index 0000000..626047b --- /dev/null +++ b/spec/lib/diaspora_federation/validators/photo_validator_spec.rb @@ -0,0 +1,54 @@ +module DiasporaFederation + describe Validators::PhotoValidator do + let(:entity) { :photo_entity } + + it_behaves_like "a common validator" + + it_behaves_like "a diaspora id validator" do + let(:property) { :diaspora_id } + let(:mandatory) { true } + end + + context "#guid, #status_message_guid" do + %i(guid status_message_guid).each do |prop| + it_behaves_like "a guid validator" do + let(:property) { prop } + end + end + end + + it_behaves_like "a boolean validator" do + let(:property) { :public } + end + + context "#remote_photo_path, #remote_photo_name" do + %i(remote_photo_name remote_photo_path).each do |prop| + it "must not be empty" do + validator = Validators::PhotoValidator.new(entity_stub(entity, prop => "")) + expect(validator).not_to be_valid + expect(validator.errors).to include(prop) + end + end + end + + context "#height, #width" do + %i(height width).each do |prop| + it "validates an integer" do + [123, "123"].each do |val| + validator = Validators::PhotoValidator.new(entity_stub(entity, prop => val)) + expect(validator).to be_valid + expect(validator.errors).to be_empty + end + end + + it "fails for non numeric types" do + [true, :num, "asdf"].each do |val| + validator = Validators::PhotoValidator.new(entity_stub(entity, prop => val)) + expect(validator).not_to be_valid + expect(validator.errors).to include(prop) + end + end + end + end + end +end diff --git a/spec/lib/diaspora_federation/validators/profile_validator_spec.rb b/spec/lib/diaspora_federation/validators/profile_validator_spec.rb index 8bff965..321f3ae 100644 --- a/spec/lib/diaspora_federation/validators/profile_validator_spec.rb +++ b/spec/lib/diaspora_federation/validators/profile_validator_spec.rb @@ -3,15 +3,10 @@ module DiasporaFederation let(:entity) { :profile_entity } def profile_stub(data={}) - OpenStruct.new(FactoryGirl.attributes_for(:profile_entity).merge(data)) + entity_stub(entity, data) end - it "validates a well-formed instance" do - validator = Validators::ProfileValidator.new(profile_stub) - - expect(validator).to be_valid - expect(validator.errors).to be_empty - end + it_behaves_like "a common validator" it_behaves_like "a diaspora id validator" do let(:property) { :diaspora_id } diff --git a/spec/lib/diaspora_federation/validators/request_validator_spec.rb b/spec/lib/diaspora_federation/validators/request_validator_spec.rb new file mode 100644 index 0000000..79a34c4 --- /dev/null +++ b/spec/lib/diaspora_federation/validators/request_validator_spec.rb @@ -0,0 +1,16 @@ +module DiasporaFederation + describe Validators::RequestValidator do + let(:entity) { :request_entity } + + it_behaves_like "a common validator" + + context "#sender_id, #recipient_id" do + %i(sender_id recipient_id).each do |prop| + it_behaves_like "a diaspora id validator" do + let(:property) { prop } + let(:mandatory) { true } + end + end + end + end +end diff --git a/spec/lib/diaspora_federation/validators/status_message_validator_spec.rb b/spec/lib/diaspora_federation/validators/status_message_validator_spec.rb new file mode 100644 index 0000000..1d33a1c --- /dev/null +++ b/spec/lib/diaspora_federation/validators/status_message_validator_spec.rb @@ -0,0 +1,20 @@ +module DiasporaFederation + describe Validators::StatusMessageValidator do + let(:entity) { :status_message_entity } + + it_behaves_like "a common validator" + + it_behaves_like "a diaspora id validator" do + let(:property) { :diaspora_id } + let(:mandatory) { true } + end + + it_behaves_like "a guid validator" do + let(:property) { :guid } + end + + it_behaves_like "a boolean validator" do + let(:property) { :public } + end + end +end diff --git a/spec/lib/diaspora_federation/validators/web_finger_validator_spec.rb b/spec/lib/diaspora_federation/validators/web_finger_validator_spec.rb index 00f5e02..e1ec327 100644 --- a/spec/lib/diaspora_federation/validators/web_finger_validator_spec.rb +++ b/spec/lib/diaspora_federation/validators/web_finger_validator_spec.rb @@ -3,15 +3,10 @@ module DiasporaFederation let(:entity) { :webfinger } def webfinger_stub(data={}) - OpenStruct.new(FactoryGirl.attributes_for(:webfinger).merge(data)) + entity_stub(entity, data) end - it "validates a well-formed instance" do - validator = Validators::WebFingerValidator.new(webfinger_stub) - - expect(validator).to be_valid - expect(validator.errors).to be_empty - end + it_behaves_like "a common validator" describe "#acct_uri" do it "fails if it is nil or empty" do diff --git a/spec/support/shared_validator_specs.rb b/spec/support/shared_validator_specs.rb index 9b96d30..13ec3b1 100644 --- a/spec/support/shared_validator_specs.rb +++ b/spec/support/shared_validator_specs.rb @@ -1,7 +1,5 @@ -def entity_stub(entity, property, val) - instance = OpenStruct.new(FactoryGirl.attributes_for(entity)) - instance.public_send("#{property}=", val) - instance +def entity_stub(entity, data={}) + OpenStruct.new(FactoryGirl.attributes_for(entity).merge(data)) end ALPHANUMERIC_RANGE = [*"0".."9", *"A".."Z", *"a".."z"] @@ -10,10 +8,18 @@ def alphanumeric_string(length) Array.new(length) { ALPHANUMERIC_RANGE.sample }.join end +shared_examples "a common validator" do + it "validates a well-formed instance" do + validator = described_class.new(entity_stub(entity)) + expect(validator).to be_valid + expect(validator.errors).to be_empty + end +end + shared_examples "a diaspora id validator" do it "must not be nil or empty if mandatory" do [nil, ""].each do |val| - validator = described_class.new(entity_stub(entity, property, val)) + validator = described_class.new(entity_stub(entity, property => val)) if mandatory expect(validator).not_to be_valid @@ -26,7 +32,7 @@ shared_examples "a diaspora id validator" do end it "must be a valid diaspora id" do - validator = described_class.new(entity_stub(entity, property, "i am a weird diaspora id @@@ ### 12345")) + validator = described_class.new(entity_stub(entity, property => "i am a weird diaspora id @@@ ### 12345")) expect(validator).not_to be_valid expect(validator.errors).to include(property) @@ -35,21 +41,21 @@ end shared_examples "a guid validator" do it "validates a well-formed guid from redmatrix" do - validator = described_class.new(entity_stub(entity, property, "1234567890ABCDefgh_ijkl-mnopQR@example.com:3000")) + validator = described_class.new(entity_stub(entity, property => "1234567890ABCDefgh_ijkl-mnopQR@example.com:3000")) expect(validator).to be_valid expect(validator.errors).to be_empty end it "must be at least 16 chars" do - validator = described_class.new(entity_stub(entity, property, "aaaaaa")) + validator = described_class.new(entity_stub(entity, property => "aaaaaa")) expect(validator).not_to be_valid expect(validator.errors).to include(property) end it "must only contain [0-9a-z-_@.:]" do - validator = described_class.new(entity_stub(entity, property, "zzz+-#*$$")) + validator = described_class.new(entity_stub(entity, property => "zzz+-#*$$")) expect(validator).not_to be_valid expect(validator.errors).to include(property) @@ -57,7 +63,7 @@ shared_examples "a guid validator" do it "must not be nil or empty" do [nil, ""].each do |val| - validator = described_class.new(entity_stub(entity, property, val)) + validator = described_class.new(entity_stub(entity, property => val)) expect(validator).not_to be_valid expect(validator.errors).to include(property) @@ -68,7 +74,7 @@ end shared_examples "a boolean validator" do it "validates a well-formed boolean" do [true, "true", false, "false"].each do |val| - validator = described_class.new(entity_stub(entity, property, val)) + validator = described_class.new(entity_stub(entity, property => val)) expect(validator).to be_valid expect(validator.errors).to be_empty @@ -77,7 +83,7 @@ shared_examples "a boolean validator" do it "must not be an arbitrary string or other object" do ["asdf", Time.zone.today, 1234].each do |val| - validator = described_class.new(entity_stub(entity, property, val)) + validator = described_class.new(entity_stub(entity, property => val)) expect(validator).not_to be_valid expect(validator.errors).to include(property) @@ -87,7 +93,7 @@ end shared_examples "a public key validator" do it "fails for malformed rsa key" do - validator = described_class.new(entity_stub(entity, property, "ASDF")) + validator = described_class.new(entity_stub(entity, property => "ASDF")) expect(validator).not_to be_valid expect(validator.errors).to include(property) @@ -95,7 +101,7 @@ shared_examples "a public key validator" do it "must not be nil or empty" do [nil, ""].each do |val| - validator = described_class.new(entity_stub(entity, property, val)) + validator = described_class.new(entity_stub(entity, property => val)) expect(validator).not_to be_valid expect(validator.errors).to include(property) @@ -106,7 +112,7 @@ end shared_examples "a name validator" do it "is allowed to be nil or empty" do [nil, ""].each do |val| - validator = described_class.new(entity_stub(entity, property, val)) + validator = described_class.new(entity_stub(entity, property => val)) expect(validator).to be_valid expect(validator.errors).to be_empty @@ -114,28 +120,28 @@ shared_examples "a name validator" do end it "is allowed to contain special chars" do - validator = described_class.new(entity_stub(entity, property, "cool name ©")) + validator = described_class.new(entity_stub(entity, property => "cool name ©")) expect(validator).to be_valid expect(validator.errors).to be_empty end it "validates the maximum number of chars" do - validator = described_class.new(entity_stub(entity, property, alphanumeric_string(length))) + validator = described_class.new(entity_stub(entity, property => alphanumeric_string(length))) expect(validator).to be_valid expect(validator.errors).to be_empty end it "must not exceed the maximum number of chars" do - validator = described_class.new(entity_stub(entity, property, alphanumeric_string(length + 1))) + validator = described_class.new(entity_stub(entity, property => alphanumeric_string(length + 1))) expect(validator).not_to be_valid expect(validator.errors).to include(property) end it "must not contain semicolons" do - validator = described_class.new(entity_stub(entity, property, "asdf;qwer;yxcv")) + validator = described_class.new(entity_stub(entity, property => "asdf;qwer;yxcv")) expect(validator).not_to be_valid expect(validator.errors).to include(property) @@ -145,7 +151,7 @@ end shared_examples "a length validator" do it "is allowed to be nil or empty" do [nil, ""].each do |val| - validator = described_class.new(entity_stub(entity, property, val)) + validator = described_class.new(entity_stub(entity, property => val)) expect(validator).to be_valid expect(validator.errors).to be_empty @@ -153,21 +159,21 @@ shared_examples "a length validator" do end it "is allowed to contain special chars" do - validator = described_class.new(entity_stub(entity, property, "cool name ©;:#%")) + validator = described_class.new(entity_stub(entity, property => "cool name ©;:#%")) expect(validator).to be_valid expect(validator.errors).to be_empty end it "validates the maximum number of chars" do - validator = described_class.new(entity_stub(entity, property, alphanumeric_string(length))) + validator = described_class.new(entity_stub(entity, property => alphanumeric_string(length))) expect(validator).to be_valid expect(validator.errors).to be_empty end it "must not exceed the maximum number of chars" do - validator = described_class.new(entity_stub(entity, property, alphanumeric_string(length + 1))) + validator = described_class.new(entity_stub(entity, property => alphanumeric_string(length + 1))) expect(validator).not_to be_valid expect(validator.errors).to include(property) @@ -177,7 +183,7 @@ end shared_examples "a url validator without path" do it "must not be nil or empty" do [nil, ""].each do |val| - validator = described_class.new(entity_stub(entity, property, val)) + validator = described_class.new(entity_stub(entity, property => val)) expect(validator).not_to be_valid expect(validator.errors).to include(property) @@ -185,14 +191,14 @@ shared_examples "a url validator without path" do end it "fails for url with special chars" do - validator = described_class.new(entity_stub(entity, property, "https://asdf$%.com")) + validator = described_class.new(entity_stub(entity, property => "https://asdf$%.com")) expect(validator).not_to be_valid expect(validator.errors).to include(property) end it "fails for url without scheme" do - validator = described_class.new(entity_stub(entity, property, "example.com")) + validator = described_class.new(entity_stub(entity, property => "example.com")) expect(validator).not_to be_valid expect(validator.errors).to include(property) @@ -201,14 +207,14 @@ end shared_examples "a url path validator" do it "fails for url with special chars" do - validator = described_class.new(entity_stub(entity, property, "https://asdf$%.com/some/path")) + validator = described_class.new(entity_stub(entity, property => "https://asdf$%.com/some/path")) expect(validator).not_to be_valid expect(validator.errors).to include(property) end it "fails for url without path" do - validator = described_class.new(entity_stub(entity, property, "https://example.com")) + validator = described_class.new(entity_stub(entity, property => "https://example.com")) expect(validator).not_to be_valid expect(validator.errors).to include(property)