webfingering is now syncrounous
This commit is contained in:
parent
9aa093a0a3
commit
be00a2f1b3
5 changed files with 76 additions and 176 deletions
|
|
@ -30,7 +30,7 @@ class Retraction
|
||||||
if self.type.constantize.find_by_id(post_id)
|
if self.type.constantize.find_by_id(post_id)
|
||||||
unless Post.first(:diaspora_handle => person.diaspora_handle, :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}")
|
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
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
|
|
||||||
|
|
@ -6,23 +6,25 @@ module Diaspora
|
||||||
def receive_salmon salmon_xml
|
def receive_salmon salmon_xml
|
||||||
salmon = Salmon::SalmonSlap.parse salmon_xml, self
|
salmon = Salmon::SalmonSlap.parse salmon_xml, self
|
||||||
webfinger = EMWebfinger.new(salmon.author_email)
|
webfinger = EMWebfinger.new(salmon.author_email)
|
||||||
|
begin
|
||||||
webfinger.on_person { |response|
|
salmon_author = webfinger.fetch
|
||||||
if response.is_a? Person
|
rescue Exception => e
|
||||||
salmon_author = response
|
Rails.logger.info("event=receive status=abort recipient=#{self.diaspora_handle} sender=#{salmon.author_email} reason='#{e.message}'")
|
||||||
if salmon.verified_for_key?(salmon_author.public_key)
|
end
|
||||||
self.receive(salmon.parsed_data, salmon_author)
|
|
||||||
end
|
if salmon_author
|
||||||
|
if salmon.verified_for_key?(salmon_author.public_key)
|
||||||
|
self.receive(salmon.parsed_data, salmon_author)
|
||||||
else
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
def receive xml, salmon_author
|
def receive xml, salmon_author
|
||||||
object = Diaspora::Parser.from_xml(xml)
|
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}")
|
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)
|
if object.is_a?(Request)
|
||||||
salmon_author.save
|
salmon_author.save
|
||||||
object.sender_handle = salmon_author.diaspora_handle
|
object.sender_handle = salmon_author.diaspora_handle
|
||||||
|
|
@ -41,17 +43,23 @@ module Diaspora
|
||||||
|
|
||||||
e = EMWebfinger.new(object.diaspora_handle)
|
e = EMWebfinger.new(object.diaspora_handle)
|
||||||
|
|
||||||
e.on_person do |person|
|
begin
|
||||||
if person.class == Person
|
person = e.fetch
|
||||||
object.person = person if object.respond_to? :person=
|
rescue Exception => e
|
||||||
unless object.is_a?(Request) || self.contact_for(salmon_author)
|
Rails.logger.info("event=receive status=abort reason='#{e.message}' payload_type=#{object.class} recipient=#{self.diaspora_handle} sender=#{salmon_author.diaspora_handle}")
|
||||||
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
|
||||||
return
|
end
|
||||||
else
|
|
||||||
receive_object(object,person)
|
if person
|
||||||
Rails.logger.info("event=receive status=complete recipient=#{self.diaspora_handle} sender=#{salmon_author.diaspora_handle} payload_type#{object.class}")
|
object.person = person if object.respond_to? :person=
|
||||||
return object
|
|
||||||
end
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -102,7 +110,7 @@ module Diaspora
|
||||||
def receive_comment comment
|
def receive_comment comment
|
||||||
|
|
||||||
commenter = comment.person
|
commenter = comment.person
|
||||||
|
|
||||||
unless comment.post.person == self.person || comment.verify_post_creator_signature
|
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}")
|
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
|
return
|
||||||
|
|
@ -136,10 +144,10 @@ module Diaspora
|
||||||
def receive_post post
|
def receive_post post
|
||||||
#exsists locally, but you dont know about it
|
#exsists locally, but you dont know about it
|
||||||
#does not exsist locally, and you dont know about it
|
#does not exsist locally, and you dont know about it
|
||||||
|
|
||||||
#exsists_locally?
|
#exsists_locally?
|
||||||
#you know about it, and it is mutable
|
#you know about it, and it is mutable
|
||||||
#you know about it, and it is not mutable
|
#you know about it, and it is not mutable
|
||||||
#
|
#
|
||||||
on_pod = exsists_on_pod?(post)
|
on_pod = exsists_on_pod?(post)
|
||||||
if on_pod && on_pod.diaspora_handle == post.diaspora_handle
|
if on_pod && on_pod.diaspora_handle == post.diaspora_handle
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ class EMWebfinger
|
||||||
OPTS = {:timeout => TIMEOUT, :redirects => REDIRECTS}
|
OPTS = {:timeout => TIMEOUT, :redirects => REDIRECTS}
|
||||||
def initialize(account)
|
def initialize(account)
|
||||||
@account = account.strip.gsub('acct:','').to_s
|
@account = account.strip.gsub('acct:','').to_s
|
||||||
@callbacks = []
|
|
||||||
@ssl = true
|
@ssl = true
|
||||||
Rails.logger.info("event=EMWebfinger status=initialized target=#{account}")
|
Rails.logger.info("event=EMWebfinger status=initialized target=#{account}")
|
||||||
# Raise an error if identifier has a port number
|
# 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 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]$/)
|
#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
|
end
|
||||||
|
|
||||||
def fetch
|
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)
|
person = Person.by_account_identifier(@account)
|
||||||
if person
|
if person
|
||||||
Rails.logger.info("event=EMWebfinger status=local target=#{@account}")
|
Rails.logger.info("event=EMWebfinger status=local target=#{@account}")
|
||||||
process_callbacks person
|
return person
|
||||||
else
|
else
|
||||||
Rails.logger.info("event=EMWebfinger status=remote target=#{@account}")
|
Rails.logger.info("event=EMWebfinger status=remote target=#{@account}")
|
||||||
|
|
||||||
profile_url = get_xrd
|
profile_url = get_xrd
|
||||||
|
webfinger_profile = get_webfinger_profile(profile_url)
|
||||||
webfinger_profile = get_webfinger_profile(profile_url) if profile_url
|
fingered_person = make_person_from_webfinger(webfinger_profile)
|
||||||
|
fingered_person
|
||||||
fingered_person = make_person_from_webfinger(webfinger_profile) if webfinger_profile
|
|
||||||
|
|
||||||
process_callbacks(fingered_person)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_person(&block)
|
|
||||||
@callbacks << block
|
|
||||||
self.fetch
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def get_xrd
|
def get_xrd
|
||||||
begin
|
begin
|
||||||
http = RestClient.get xrd_url, OPTS
|
http = RestClient.get xrd_url, OPTS
|
||||||
|
|
||||||
profile_url = webfinger_profile_url(http.body)
|
profile_url = webfinger_profile_url(http.body)
|
||||||
if profile_url
|
if profile_url
|
||||||
return profile_url
|
return profile_url
|
||||||
else
|
else
|
||||||
raise "no profile URL"
|
raise "no profile URL"
|
||||||
end
|
end
|
||||||
rescue
|
rescue Exception => e
|
||||||
if @ssl
|
if @ssl
|
||||||
@ssl = false
|
@ssl = false
|
||||||
retry
|
retry
|
||||||
else
|
else
|
||||||
process_callbacks I18n.t('webfinger.xrd_fetch_failed', :account => @account)
|
raise e
|
||||||
return
|
raise I18n.t('webfinger.xrd_fetch_failed', :account => @account)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def get_webfinger_profile(profile_url)
|
def get_webfinger_profile(profile_url)
|
||||||
|
|
||||||
begin
|
begin
|
||||||
http = RestClient.get(profile_url, OPTS)
|
http = RestClient.get(profile_url, OPTS)
|
||||||
return http.body
|
|
||||||
|
|
||||||
rescue Exception => e
|
rescue
|
||||||
puts e.message
|
raise I18n.t('webfinger.fetch_failed', :profile_url => profile_url)
|
||||||
process_callbacks I18n.t('webfinger.fetch_failed', :profile_url => profile_url)
|
end
|
||||||
return
|
return http.body
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_person_from_webfinger(webfinger_profile)
|
def make_person_from_webfinger(webfinger_profile)
|
||||||
|
|
@ -86,9 +71,8 @@ class EMWebfinger
|
||||||
begin
|
begin
|
||||||
hcard = RestClient.get(wf_profile.hcard, OPTS)
|
hcard = RestClient.get(wf_profile.hcard, OPTS)
|
||||||
rescue
|
rescue
|
||||||
process_callbacks I18n.t('webfinger.hcard_fetch_failed', :account => @account)
|
return I18n.t('webfinger.hcard_fetch_failed', :account => @account)
|
||||||
return
|
end
|
||||||
end
|
|
||||||
|
|
||||||
card = HCard.build hcard.body
|
card = HCard.build hcard.body
|
||||||
p = Person.build_from_webfinger(wf_profile, card)
|
p = Person.build_from_webfinger(wf_profile, card)
|
||||||
|
|
@ -96,19 +80,6 @@ class EMWebfinger
|
||||||
end
|
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
|
##helpers
|
||||||
private
|
private
|
||||||
|
|
||||||
|
|
@ -122,7 +93,7 @@ class EMWebfinger
|
||||||
domain = @account.split('@')[1]
|
domain = @account.split('@')[1]
|
||||||
"http#{'s' if @ssl}://#{domain}/.well-known/host-meta"
|
"http#{'s' if @ssl}://#{domain}/.well-known/host-meta"
|
||||||
end
|
end
|
||||||
|
|
||||||
def swizzle(template)
|
def swizzle(template)
|
||||||
template.gsub '{uri}', @account
|
template.gsub '{uri}', @account
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -42,35 +42,6 @@ describe EMWebfinger do
|
||||||
end
|
end
|
||||||
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
|
context 'webfinger query chain processing' do
|
||||||
describe '#webfinger_profile_url' do
|
describe '#webfinger_profile_url' do
|
||||||
it 'should parse out the webfinger template' do
|
it 'should parse out the webfinger template' do
|
||||||
|
|
@ -101,81 +72,31 @@ describe EMWebfinger do
|
||||||
context 'webfingering local people' do
|
context 'webfingering local people' do
|
||||||
it 'should return a person from the database if it matches its handle' do
|
it 'should return a person from the database if it matches its handle' do
|
||||||
person.save
|
person.save
|
||||||
EM.run do
|
finger.fetch.id.should == person.id
|
||||||
finger.on_person { |p|
|
|
||||||
p.should == person
|
|
||||||
EM.stop
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should fetch a diaspora webfinger and make a person for them' do
|
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")
|
#new_person = Factory.build(:person, :diaspora_handle => "tom@tom.joindiaspora.com")
|
||||||
# http://tom.joindiaspora.com/.well-known/host-meta
|
# 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
|
end
|
||||||
|
|
||||||
it 'should retry with http if https fails' do
|
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")
|
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
|
f.should_receive(:xrd_url).twice
|
||||||
|
f.send(:get_xrd)
|
||||||
EM.run {
|
f.instance_variable_get(:@ssl).should == false
|
||||||
f.on_person{ |p|
|
|
||||||
EM.stop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
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
|
end
|
||||||
end
|
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ describe User do
|
||||||
|
|
||||||
describe '#receive_salmon' do
|
describe '#receive_salmon' do
|
||||||
it 'should handle the case where the webfinger fails' 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{
|
proc{
|
||||||
user2.post :status_message, :message => "store this!", :to => aspect2.id
|
user2.post :status_message, :message => "store this!", :to => aspect2.id
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue