webfingering is now syncrounous

This commit is contained in:
maxwell 2010-12-01 15:38:55 -08:00 committed by Raphael
parent 9aa093a0a3
commit be00a2f1b3
5 changed files with 76 additions and 176 deletions

View file

@ -30,7 +30,7 @@ class Retraction
if self.type.constantize.find_by_id(post_id)
unless Post.first(:diaspora_handle => person.diaspora_handle, :id => post_id)
Rails.logger.info("event=retraction status=abort reason='no post found authored by retractor' sender=#{person.diaspora_handle} post_id=#{post_id}")
raise "#{person.inspect} is trying to retract a post that either doesn't exist or is not by them"
return
end
begin

View file

@ -6,23 +6,25 @@ module Diaspora
def receive_salmon salmon_xml
salmon = Salmon::SalmonSlap.parse salmon_xml, self
webfinger = EMWebfinger.new(salmon.author_email)
webfinger.on_person { |response|
if response.is_a? Person
salmon_author = response
if salmon.verified_for_key?(salmon_author.public_key)
self.receive(salmon.parsed_data, salmon_author)
end
begin
salmon_author = webfinger.fetch
rescue Exception => e
Rails.logger.info("event=receive status=abort recipient=#{self.diaspora_handle} sender=#{salmon.author_email} reason='#{e.message}'")
end
if salmon_author
if salmon.verified_for_key?(salmon_author.public_key)
self.receive(salmon.parsed_data, salmon_author)
else
Rails.logger.info("event=receive status=abort recipient=#{self.diaspora_handle} sender=#{salmon.author_email} reason='#{response}'")
Rails.logger.info("event=receive status=abort recipient=#{self.diaspora_handle} sender=#{salmon.author_email} reason='not_verified for key'")
end
}
end
end
def receive xml, salmon_author
object = Diaspora::Parser.from_xml(xml)
Rails.logger.info("event=receive status=start recipient=#{self.diaspora_handle} payload_type=#{object.class} sender=#{salmon_author.diaspora_handle}")
if object.is_a?(Request)
salmon_author.save
object.sender_handle = salmon_author.diaspora_handle
@ -41,17 +43,23 @@ module Diaspora
e = EMWebfinger.new(object.diaspora_handle)
e.on_person do |person|
if person.class == Person
object.person = person if object.respond_to? :person=
unless object.is_a?(Request) || self.contact_for(salmon_author)
Rails.logger.info("event=receive status=abort reason='sender not connected to recipient' recipient=#{self.diaspora_handle} sender=#{salmon_author.diaspora_handle} payload_type=#{object.class}")
return
else
receive_object(object,person)
Rails.logger.info("event=receive status=complete recipient=#{self.diaspora_handle} sender=#{salmon_author.diaspora_handle} payload_type#{object.class}")
return object
end
begin
person = e.fetch
rescue Exception => e
Rails.logger.info("event=receive status=abort reason='#{e.message}' payload_type=#{object.class} recipient=#{self.diaspora_handle} sender=#{salmon_author.diaspora_handle}")
return
end
if person
object.person = person if object.respond_to? :person=
unless object.is_a?(Request) || self.contact_for(salmon_author)
Rails.logger.info("event=receive status=abort reason='sender not connected to recipient' recipient=#{self.diaspora_handle} sender=#{salmon_author.diaspora_handle} payload_type=#{object.class}")
return
else
receive_object(object,person)
Rails.logger.info("event=receive status=complete recipient=#{self.diaspora_handle} sender=#{salmon_author.diaspora_handle} payload_type#{object.class}")
return object
end
end
end
@ -102,7 +110,7 @@ module Diaspora
def receive_comment comment
commenter = comment.person
unless comment.post.person == self.person || comment.verify_post_creator_signature
Rails.logger.info("event=receive status=abort reason='comment signature not valid' recipient=#{self.diaspora_handle} sender=#{comment.post.person.diaspora_handle} payload_type=#{comment.class} post_id=#{comment.post_id}")
return
@ -136,10 +144,10 @@ module Diaspora
def receive_post post
#exsists locally, but you dont know about it
#does not exsist locally, and you dont know about it
#exsists_locally?
#you know about it, and it is mutable
#you know about it, and it is not mutable
#you know about it, and it is mutable
#you know about it, and it is not mutable
#
on_pod = exsists_on_pod?(post)
if on_pod && on_pod.diaspora_handle == post.diaspora_handle

View file

@ -7,7 +7,6 @@ class EMWebfinger
OPTS = {:timeout => TIMEOUT, :redirects => REDIRECTS}
def initialize(account)
@account = account.strip.gsub('acct:','').to_s
@callbacks = []
@ssl = true
Rails.logger.info("event=EMWebfinger status=initialized target=#{account}")
# Raise an error if identifier has a port number
@ -15,67 +14,53 @@ class EMWebfinger
# Raise an error if identifier is not a valid email (generous regexp)
#raise "Identifier is invalid" if !(@account=~ /^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/)
end
def fetch
if @callbacks.empty?
Rails.logger.info("event=EMWebfinger status=abort target=#{@account} callbacks=empty")
raise 'you need to set a callback before calling fetch'
end
person = Person.by_account_identifier(@account)
if person
Rails.logger.info("event=EMWebfinger status=local target=#{@account}")
process_callbacks person
return person
else
Rails.logger.info("event=EMWebfinger status=remote target=#{@account}")
profile_url = get_xrd
webfinger_profile = get_webfinger_profile(profile_url) if profile_url
fingered_person = make_person_from_webfinger(webfinger_profile) if webfinger_profile
process_callbacks(fingered_person)
webfinger_profile = get_webfinger_profile(profile_url)
fingered_person = make_person_from_webfinger(webfinger_profile)
fingered_person
end
end
def on_person(&block)
@callbacks << block
self.fetch
end
private
def get_xrd
begin
http = RestClient.get xrd_url, OPTS
begin
http = RestClient.get xrd_url, OPTS
profile_url = webfinger_profile_url(http.body)
if profile_url
return profile_url
else
raise "no profile URL"
end
rescue
if @ssl
@ssl = false
retry
else
process_callbacks I18n.t('webfinger.xrd_fetch_failed', :account => @account)
return
end
end
profile_url = webfinger_profile_url(http.body)
if profile_url
return profile_url
else
raise "no profile URL"
end
rescue Exception => e
if @ssl
@ssl = false
retry
else
raise e
raise I18n.t('webfinger.xrd_fetch_failed', :account => @account)
end
end
end
def get_webfinger_profile(profile_url)
begin
http = RestClient.get(profile_url, OPTS)
return http.body
rescue Exception => e
puts e.message
process_callbacks I18n.t('webfinger.fetch_failed', :profile_url => profile_url)
return
end
rescue
raise I18n.t('webfinger.fetch_failed', :profile_url => profile_url)
end
return http.body
end
def make_person_from_webfinger(webfinger_profile)
@ -86,9 +71,8 @@ class EMWebfinger
begin
hcard = RestClient.get(wf_profile.hcard, OPTS)
rescue
process_callbacks I18n.t('webfinger.hcard_fetch_failed', :account => @account)
return
end
return I18n.t('webfinger.hcard_fetch_failed', :account => @account)
end
card = HCard.build hcard.body
p = Person.build_from_webfinger(wf_profile, card)
@ -96,19 +80,6 @@ class EMWebfinger
end
def process_callbacks(person)
Rails.logger.info("event=EMWebfinger status=callbacks_started target=#{@account} response='#{person.is_a?(String) ? person : person.id}'")
@callbacks.each { |c|
begin
c.call(person)
rescue Exception => e
Rails.logger.info("event=EMWebfinger status=error_on_callback error='#{e.inspect}'")
end
}
Rails.logger.info("event=EMWebfinger status=complete target=#{@account}")
end
##helpers
private
@ -122,7 +93,7 @@ class EMWebfinger
domain = @account.split('@')[1]
"http#{'s' if @ssl}://#{domain}/.well-known/host-meta"
end
def swizzle(template)
template.gsub '{uri}', @account
end

View file

@ -42,35 +42,6 @@ describe EMWebfinger do
end
end
describe '#on_person' do
it 'should set a callback' do
n = EMWebfinger.new("mbs@gmail.com")
n.stub(:fetch).and_return(true)
n.on_person{|person| 1+1}
n.instance_variable_get(:@callbacks).count.should be 1
end
it 'should not blow up if the returned xrd is nil' do
http = FakeHttpRequest.new(:success)
fake_account = 'foo@example.com'
http.callbacks = ['']
EventMachine::HttpRequest.should_receive(:new).and_return(http)
n = EMWebfinger.new("foo@example.com")
n.on_person{|person|
person.should == "webfinger does not seem to be enabled for #{fake_account}'s host"
}
end
end
describe '#fetch' do
it 'should require a callback' do
proc{finger.fetch }.should raise_error "you need to set a callback before calling fetch"
end
end
context 'webfinger query chain processing' do
describe '#webfinger_profile_url' do
it 'should parse out the webfinger template' do
@ -101,81 +72,31 @@ describe EMWebfinger do
context 'webfingering local people' do
it 'should return a person from the database if it matches its handle' do
person.save
EM.run do
finger.on_person { |p|
p.should == person
EM.stop
}
finger.fetch.id.should == person.id
end
end
it 'should fetch a diaspora webfinger and make a person for them' do
good_request.callbacks = [diaspora_xrd, diaspora_finger, hcard_xml]
diaspora_xrd.stub!(:body).and_return(diaspora_xrd)
hcard_xml.stub!(:body).and_return(hcard_xml)
diaspora_finger.stub!(:body).and_return(diaspora_finger)
RestClient.stub!(:get).and_return(diaspora_xrd, diaspora_finger, hcard_xml)
#new_person = Factory.build(:person, :diaspora_handle => "tom@tom.joindiaspora.com")
# http://tom.joindiaspora.com/.well-known/host-meta
f = EMWebfinger.new("tom@tom.joindiaspora.com")
f = EMWebfinger.new("tom@tom.joindiaspora.com").fetch
f.should be_valid
EventMachine::HttpRequest.should_receive(:new).exactly(3).times.and_return(good_request)
EM.run {
f.on_person{ |p|
p.valid?.should be true
EM.stop
}
}
end
it 'should retry with http if https fails' do
good_request.callbacks = [nil, diaspora_xrd, diaspora_finger, hcard_xml]
#new_person = Factory.build(:person, :diaspora_handle => "tom@tom.joindiaspora.com")
# http://tom.joindiaspora.com/.well-known/host-meta
f = EMWebfinger.new("tom@tom.joindiaspora.com")
EventMachine::HttpRequest.should_receive(:new).exactly(4).times.and_return(good_request)
diaspora_xrd.stub!(:body).and_return(diaspora_xrd)
RestClient.should_receive(:get).twice.and_return(nil, diaspora_xrd)
f.should_receive(:xrd_url).twice
EM.run {
f.on_person{ |p|
EM.stop
}
}
f.send(:get_xrd)
f.instance_variable_get(:@ssl).should == false
end
it 'must try https first' do
single_request = FakeHttpRequest.new(:success)
single_request.callbacks = [diaspora_xrd]
good_request.callbacks = [diaspora_finger, hcard_xml]
EventMachine::HttpRequest.should_receive(:new).with("https://tom.joindiaspora.com/.well-known/host-meta").and_return(single_request)
EventMachine::HttpRequest.should_receive(:new).exactly(2).and_return(good_request)
f = EMWebfinger.new("tom@tom.joindiaspora.com")
EM.run {
f.on_person{ |p|
EM.stop
}
}
end
it 'should retry with http if https fails with an http error code' do
bad_request = FakeHttpRequest.new(:failure)
good_request.callbacks = [diaspora_xrd, diaspora_finger, hcard_xml]
EventMachine::HttpRequest.should_receive(:new).with("https://tom.joindiaspora.com/.well-known/host-meta").and_return(bad_request)
EventMachine::HttpRequest.should_receive(:new).exactly(3).and_return(good_request)
f = EMWebfinger.new("tom@tom.joindiaspora.com")
EM.run {
f.on_person{ |p|
EM.stop
}
}
end
end
end
end

View file

@ -61,7 +61,7 @@ describe User do
describe '#receive_salmon' do
it 'should handle the case where the webfinger fails' do
Person.should_receive(:by_account_identifier).and_return("not a person")
EMWebfinger.stub!(:fetch).and_return(nil)
proc{
user2.post :status_message, :message => "store this!", :to => aspect2.id