Relayable retractions pretty much done

This commit is contained in:
Raphael Sofaer 2011-03-25 10:46:11 -07:00
parent 31f43696cb
commit b9af450628
5 changed files with 115 additions and 46 deletions

View file

@ -24,8 +24,6 @@ class Post < ActiveRecord::Base
cattr_reader :per_page
@@per_page = 10
after_destroy :propogate_retraction
def user_refs
self.post_visibilities.count
end
@ -93,10 +91,5 @@ class Post < ActiveRecord::Base
Rails.logger.info("event=receive payload_type=#{self.class} update=true status=abort sender=#{self.diaspora_handle} reason='update not from post owner' existing_post=#{self.id}")
end
end
protected
def propogate_retraction
self.author.owner.retract(self) if self.author.owner
end
end

View file

@ -5,6 +5,7 @@
class RelayableRetraction
include ROXML
include Diaspora::Webhooks
include Diaspora::Encryptable
xml_attr :target_guid
xml_attr :target_type
@ -18,6 +19,16 @@ class RelayableRetraction
:target_author_signature,
:sender
def signable_accessors
accessors = self.class.roxml_attrs.collect do |definition|
definition.accessor
end
['target_author_signature', 'parent_author_signature'].each do |acc|
accessors.delete acc
end
accessors
end
def sender_handle= new_sender_handle
@sender = Person.where(:diaspora_handle => new_sender_handle).first
end
@ -27,18 +38,25 @@ class RelayableRetraction
end
def subscribers(user)
@subscribers ||= self.target.subscribers(user)
self.target.subscribers(user)
end
def self.initialize(sender, target)
self.sender = sender
self.target = target
def self.build(sender, target)
retraction = self.new
retraction.sender = sender
retraction.target = target
retraction.target_author_signature = retraction.sign_with_key(sender.encryption_key) if sender.person == target.author
retraction.parent_author_signature = retraction.sign_with_key(sender.encryption_key) if sender.person == target.parent.author
retraction
end
def target
@target ||= self.target_type.constantize.where(:guid => target_guid).first
end
def guid
target_guid
end
def target= new_target
@target = new_target
@target_type = new_target.class.to_s
@ -49,20 +67,18 @@ class RelayableRetraction
self.target.parent
end
def parent_class
self.target.parent_class
end
def perform receiving_user
Rails.logger.debug "Performing retraction for #{target_guid}"
self.target.unsocket_from_user receiving_user if target.respond_to? :unsocket_from_user
self.target.destroy
target.post_visibilities.delete_all
Rails.logger.info("event=retraction status=complete target_type=#{self.target_type} guid=#{self.target_guid}")
Rails.logger.info(:event => :retraction, :status => :complete, :target_type => self.target_type, :guid => self.target_guid)
end
def receive(recipient, sender)
if self.parent.author == recipient.person && self.target_author_signature_valid?
if self.target.nil?
Rails.logger.info("event=retraction status=abort reason='no post found' sender=#{sender.diaspora_handle} target_guid=#{target_guid}")
return
elsif self.parent.author == recipient.person && self.target_author_signature_valid?
#this is a retraction from the downstream object creator, and the recipient is the upstream owner
self.parent_author_signature = self.sign_with_key(recipient.encryption_key)
Postzord::Dispatch.new(recipient, self).post
@ -82,6 +98,6 @@ class RelayableRetraction
end
def target_author_signature_valid?
verify_signature(self.target_author_signature, self.author)
verify_signature(self.target_author_signature, self.target.author)
end
end

View file

@ -218,14 +218,14 @@ class User < ActiveRecord::Base
######### Posts and Such ###############
def retract(post)
aspects = post.aspects
if post.relayable
retraction = RelayableRetraction.new(self, post)
aspects = post.parent.aspects
retraction = RelayableRetraction.build(self, post)
else
aspects = post.aspects
retraction = Retraction.for(post)
end
post.unsocket_from_user(self, :aspect_ids => aspects.map { |a| a.id.to_s }) if post.respond_to? :unsocket_from_user
retraction.perform(self)
mailman = Postzord::Dispatch.new(self, retraction)
mailman.post

View file

@ -2,16 +2,16 @@ module Diaspora
module Encryptable
def verify_signature(signature, person)
if person.nil?
Rails.logger.info("event=verify_signature status=abort reason=no_person guid=#{self.guid} model_id=#{self.id}")
Rails.logger.info("event=verify_signature status=abort reason=no_person guid=#{self.guid}")
return false
elsif person.public_key.nil?
Rails.logger.info("event=verify_signature status=abort reason=no_key guid=#{self.guid} model_id=#{self.id}")
Rails.logger.info("event=verify_signature status=abort reason=no_key guid=#{self.guid}")
return false
elsif signature.nil?
Rails.logger.info("event=verify_signature status=abort reason=no_signature guid=#{self.guid} model_id=#{self.id}")
Rails.logger.info("event=verify_signature status=abort reason=no_signature guid=#{self.guid}")
return false
end
log_string = "event=verify_signature status=complete model_id=#{id}"
log_string = "event=verify_signature status=complete guid=#{self.guid}"
validity = person.public_key.verify "SHA", Base64.decode64(signature), signable_string
log_string += " validity=#{validity}"
Rails.logger.info(log_string)
@ -20,7 +20,9 @@ module Diaspora
def sign_with_key(key)
sig = Base64.encode64(key.sign "SHA", signable_string)
Rails.logger.info("event=sign_with_key status=complete model_id=#{id}")
log_hash = {:event => :sign_with_key, :status => :complete}
log_hash.merge(:model_id => self.id) if self.respond_to?(:persisted?)
Rails.logger.info(log_hash)
sig
end

View file

@ -10,52 +10,110 @@ describe RelayableRetraction do
@local_luke, @local_leia, @remote_raphael = set_up_friends
@remote_parent = Factory.create(:status_message, :author => @remote_raphael)
@local_parent = @local_luke.post :status_message, :text => "hi", :to => @local_luke.aspects.first
@comment_by_parent_author = @local_luke.comment("yo", :on => @local_parent)
@retraction_by_parent_author = @local_luke.retract(@comment_by_parent_author)
@comment_by_recipient = @local_leia.build_comment("yo", :on => @local_parent)
@retraction_by_recipient = @local_leia.retract(@comment_by_recipient)
@comment_on_remote_parent = @local_luke.comment("Yeah, it was great", :on => @remote_parent)
@retraction_from_remote_author = RelayableRetraction.new(@remote_raphael, @comment_on_remote_parent)
end
describe '#subscribers' do
before do
@comment= @local_luke.comment("yo", :on => @local_parent)
@retraction= @local_luke.retract(@comment)
end
it 'delegates it to target' do
arg = mock()
@retraction_by_parent_author.target.should_receive(:subscribers).with(arg)
@retraction_by_parent_author.subscribers(arg)
@retraction.target.should_receive(:subscribers).with(arg)
@retraction.subscribers(arg)
end
end
describe '#receive' do
context 'from the downstream author' do
it 'signs' do
it 'discards a retraction with a nil target' do
@comment= @local_luke.comment("yo", :on => @local_parent)
@retraction= @local_luke.retract(@comment)
@retraction.instance_variable_set(:@target, nil)
@retraction.target_guid = 135245
@retraction.should_not_receive(:perform)
@retraction.receive(@local_luke, @remote_raphael)
end
context 'from the downstream author' do
before do
@comment = @local_leia.comment("yo", :on => @local_parent)
@retraction = @local_leia.retract(@comment)
@recipient = @local_luke
end
it 'signs' do
@retraction.should_receive(:sign_with_key) do |key|
key.to_s.should == @recipient.encryption_key.to_s
end
@retraction.receive(@recipient, @comment.author)
end
it 'dispatches' do
zord = mock()
zord.should_receive(:post)
Postzord::Dispatch.should_receive(:new).with(@local_luke, @retraction).and_return zord
@retraction.receive(@recipient, @comment.author)
end
it 'performs' do
@retraction.should_receive(:perform).with(@local_luke)
@retraction.receive(@recipient, @comment.author)
end
end
context 'from the upstream owner' do
before do
@comment = @local_luke.comment("Yeah, it was great", :on => @remote_parent)
@retraction = RelayableRetraction.allocate
@retraction.sender = @remote_raphael
@retraction.target = @comment
@retraction.stub!(:parent_author_signature_valid?).and_return(true)
@recipient = @local_luke
end
it 'performs' do
@retraction.should_receive(:perform).with(@recipient)
@retraction.receive(@recipient, @remote_raphael)
end
it 'does not dispatch' do
Postzord::Dispatch.should_not_receive(:new)
@retraction.receive(@recipient, @remote_raphael)
end
end
end
describe 'xml' do
before do
@comment = @local_leia.comment("yo", :on => @local_parent)
@retraction = RelayableRetraction.build(@local_leia, @comment)
@retraction.parent_author_signature = 'PARENTSIGNATURE'
@retraction.target_author_signature = 'TARGETSIGNATURE'
@xml = @retraction.to_xml.to_s
end
describe '#to_xml' do
it 'serializes target_guid' do
@xml.should include(@comment.guid)
end
it 'serializes target_type' do
@xml.should include(@comment.class.to_s)
end
it 'serializes sender_handle' do
@xml.should include(@local_leia.diaspora_handle)
end
it 'serializes signatures' do
@xml.should include('TARGETSIGNATURE')
@xml.should include('PARENTSIGNATURE')
end
end
describe '.from_xml' do
before do
@marshalled = RelayableRetraction.from_xml(@xml)
end
it 'marshals the target' do
@marshalled.target.should == @comment
end
it 'marshals the sender' do
@marshalled.sender.should == @local_leia.person
end
it 'marshals the signature' do
@marshalled.target_author_signature.should == 'TARGETSIGNATURE'
@marshalled.parent_author_signature.should == 'PARENTSIGNATURE'
end
end
end
end