From 709c6685a90bb819696566cc9e42e587546d72dc Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 22 Feb 2016 16:00:20 +0100 Subject: Made some progress --- app/services/fetch_feed_service.rb | 12 +++++- app/services/follow_remote_account_service.rb | 57 +++++++++++++++++++++++++ app/services/follow_remote_user_service.rb | 60 --------------------------- app/services/follow_service.rb | 12 ++++++ app/services/process_feed_service.rb | 20 +++++++++ app/services/process_feed_update_service.rb | 20 --------- app/services/process_interaction_service.rb | 38 +++++++++++++++++ app/services/setup_local_account_service.rb | 14 +++++++ 8 files changed, 152 insertions(+), 81 deletions(-) create mode 100644 app/services/follow_remote_account_service.rb delete mode 100644 app/services/follow_remote_user_service.rb create mode 100644 app/services/follow_service.rb create mode 100644 app/services/process_feed_service.rb delete mode 100644 app/services/process_feed_update_service.rb create mode 100644 app/services/process_interaction_service.rb create mode 100644 app/services/setup_local_account_service.rb (limited to 'app/services') diff --git a/app/services/fetch_feed_service.rb b/app/services/fetch_feed_service.rb index 3b8efbe3b..059d65925 100644 --- a/app/services/fetch_feed_service.rb +++ b/app/services/fetch_feed_service.rb @@ -1,5 +1,15 @@ class FetchFeedService def call(account) - # todo + process_service.(http_client.get(account.remote_url), account) + end + + private + + def process_service + ProcessFeedService.new + end + + def http_client + HTTP end end diff --git a/app/services/follow_remote_account_service.rb b/app/services/follow_remote_account_service.rb new file mode 100644 index 000000000..41f8fa4a0 --- /dev/null +++ b/app/services/follow_remote_account_service.rb @@ -0,0 +1,57 @@ +class FollowRemoteAccountService + include ApplicationHelper + + def call(uri) + username, domain = uri.split('@') + account = Account.where(username: username, domain: domain).first + + return account unless account.nil? + + account = Account.new(username: username, domain: domain) + data = Goldfinger.finger("acct:#{uri}") + + account.remote_url = data.link('http://schemas.google.com/g/2010#updates-from').href + account.salmon_url = data.link('salmon').href + account.public_key = magic_key_to_pem(data.link('magic-public-key').href) + account.private_key = nil + + account.secret = SecureRandom.hex + account.verify_token = SecureRandom.hex + + feed = get_feed(account.remote_url) + hubs = feed.xpath('//xmlns:link[@rel="hub"]') + + return false if hubs.empty? || hubs.first.attribute('href').nil? || feed.at_xpath('/xmlns:author/xmlns:uri').nil? + + account.uri = feed.at_xpath('/xmlns:author/xmlns:uri').content + account.hub_url = hubs.first.attribute('href').value + account.save! + + subscription = account.subscription(subscription_url(account)) + subscription.subscribe + rescue Goldfinger::Error, HTTP::Error => e + false + end + + private + + def get_feed(url) + response = http_client.get(Addressable::URI.parse(url)) + Nokogiri::XML(response) + end + + def magic_key_to_pem(magic_key) + _, modulus, exponent = magic_key.split('.') + modulus, exponent = [modulus, exponent].map { |n| Base64.urlsafe_decode64(n).bytes.inject(0) { |num, byte| (num << 8) | byte } } + + key = OpenSSL::PKey::RSA.new + key.n = modulus + key.e = exponent + + key.to_pem + end + + def http_client + HTTP + end +end diff --git a/app/services/follow_remote_user_service.rb b/app/services/follow_remote_user_service.rb deleted file mode 100644 index f3c0e68df..000000000 --- a/app/services/follow_remote_user_service.rb +++ /dev/null @@ -1,60 +0,0 @@ -class FollowRemoteUserService - include GrapeRouteHelpers::NamedRouteMatcher - - def call(user) - username, domain = user.split('@') - account = Account.where(username: username, domain: domain).first - - return account unless account.nil? - - account = Account.new(username: username, domain: domain) - data = Goldfinger.finger("acct:#{user}") - - account.remote_url = data.link('http://schemas.google.com/g/2010#updates-from').href - account.salmon_url = data.link('salmon').href - account.public_key = magic_key_to_pem(data.link('magic-public-key').href) - account.private_key = nil - - account.secret = SecureRandom.hex - account.verify_token = SecureRandom.hex - - feed = get_feed(account.remote_url) - hubs = feed.xpath('//xmlns:link[@rel="hub"]') - - return false if hubs.empty? || hubs.first.attribute('href').nil? - - account.hub_url = hubs.first.attribute('href').value - account.save! - - subscription = account.subscription(subscription_url(account)) - subscription.subscribe - rescue Goldfinger::Error, HTTP::Error => e - false - end - - private - - def get_feed(url) - response = http_client.get(Addressable::URI.parse(url)) - Nokogiri::XML(response) - end - - def magic_key_to_pem(magic_key) - _, modulus, exponent = magic_key.split('.') - modulus, exponent = [modulus, exponent].map { |n| Base64.urlsafe_decode64(n).bytes.inject(0) { |num, byte| (num << 8) | byte } } - - key = OpenSSL::PKey::RSA.new - key.n = modulus - key.d = exponent - - key.to_pem - end - - def http_client - HTTP - end - - def subscription_url(account) - "https://649841dc.ngrok.io/api#{subscriptions_path(id: account.id)}" - end -end diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb new file mode 100644 index 000000000..fc606730b --- /dev/null +++ b/app/services/follow_service.rb @@ -0,0 +1,12 @@ +class FollowService + def call(source_account, uri) + target_account = follow_remote_account_service.(uri) + source_account.follow!(target_account) + end + + private + + def follow_remote_account_service + FollowRemoteAccountService.new + end +end diff --git a/app/services/process_feed_service.rb b/app/services/process_feed_service.rb new file mode 100644 index 000000000..f2523a313 --- /dev/null +++ b/app/services/process_feed_service.rb @@ -0,0 +1,20 @@ +class ProcessFeedService + def call(body, account) + xml = Nokogiri::XML(body) + + xml.xpath('/xmlns:feed/xmlns:entry').each do |entry| + uri = entry.at_xpath('./xmlns:id').content + status = Status.find_by(uri: uri) + + next unless status.nil? + + status = Status.new + status.account = account + status.uri = uri + status.text = entry.at_xpath('./xmlns:content').content + status.created_at = entry.at_xpath('./xmlns:published').content + status.updated_at = entry.at_xpath('./xmlns:updated').content + status.save! + end + end +end diff --git a/app/services/process_feed_update_service.rb b/app/services/process_feed_update_service.rb deleted file mode 100644 index 0585fad7a..000000000 --- a/app/services/process_feed_update_service.rb +++ /dev/null @@ -1,20 +0,0 @@ -class ProcessFeedUpdateService - def call(body, account) - xml = Nokogiri::XML(body) - - xml.xpath('/xmlns:feed/xmlns:entry').each do |entry| - uri = entry.at_xpath('./xmlns:id').content - status = Status.find_by(uri: uri) - - next unless status.nil? - - status = Status.new - status.account = account - status.uri = uri - status.text = entry.at_xpath('./xmlns:content').content - status.created_at = entry.at_xpath('./xmlns:published').content - status.updated_at = entry.at_xpath('./xmlns:updated').content - status.save! - end - end -end diff --git a/app/services/process_interaction_service.rb b/app/services/process_interaction_service.rb new file mode 100644 index 000000000..8262ead8f --- /dev/null +++ b/app/services/process_interaction_service.rb @@ -0,0 +1,38 @@ +class ProcessInteractionService + def call(envelope, target_account) + body = salmon.unpack(envelope) + xml = Nokogiri::XML(body) + + return if xml.at_xpath('//author/name').nil? || xml.at_xpath('//author/uri').nil? + + username = xml.at_xpath('//author/name').content + url = xml.at_xpath('//author/uri').content + domain = Addressable::URI.parse(url).host + account = Account.find_by(username: username, domain: domain) + + if account.nil? + account = follow_remote_account_service.("acct:#{username}@#{domain}") + end + + if salmon.verify(envelope, account.keypair) + verb = xml.at_path('//activity:verb').content + + case verb + when 'http://activitystrea.ms/schema/1.0/follow', 'follow' + account.follow!(target_account) + when 'http://activitystrea.ms/schema/1.0/unfollow', 'unfollow' + account.unfollow!(target_account) + end + end + end + + private + + def salmon + OStatus2::Salmon.new + end + + def follow_remote_account_service + FollowRemoteAccountService.new + end +end diff --git a/app/services/setup_local_account_service.rb b/app/services/setup_local_account_service.rb new file mode 100644 index 000000000..c40e51855 --- /dev/null +++ b/app/services/setup_local_account_service.rb @@ -0,0 +1,14 @@ +class SetupLocalAccountService + def call(user, username) + user.build_account + + user.account.username = username + user.account.domain = nil + + keypair = OpenSSL::PKey::RSA.new(2048) + user.account.private_key = keypair.to_pem + user.account.public_key = keypair.public_key.to_pem + + user.save! + end +end -- cgit