about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2018-01-08 05:00:23 +0100
committerGitHub <noreply@github.com>2018-01-08 05:00:23 +0100
commite4a241abefaa68492938c3fbb7e5e5401d12138e (patch)
treef6f97d531d969aa6d32f6463045e1c2930e06dc2 /app
parent93555182c3cfd810fc481d9451e990955a696ea4 (diff)
Fix bad URL schemes being accepted (#6219)
* Fix actors accepting invalid URI schemes or different host between URI and URL

* Fix statuses accepting invalid URI scheme or different host to actor

* Adjust tests to new requirements

* Improve readability of mismatching_origin?/invalid_origin? methods
Diffstat (limited to 'app')
-rw-r--r--app/helpers/jsonld_helper.rb4
-rw-r--r--app/lib/activitypub/activity/create.rb20
-rw-r--r--app/services/activitypub/process_account_service.rb18
3 files changed, 38 insertions, 4 deletions
diff --git a/app/helpers/jsonld_helper.rb b/app/helpers/jsonld_helper.rb
index 6c7c38070..9530ad9f3 100644
--- a/app/helpers/jsonld_helper.rb
+++ b/app/helpers/jsonld_helper.rb
@@ -39,6 +39,10 @@ module JsonLdHelper
     !json.nil? && equals_or_includes?(json['@context'], ActivityPub::TagManager::CONTEXT)
   end
 
+  def unsupported_uri_scheme?(uri)
+    !uri.start_with?('http://', 'https://')
+  end
+
   def canonicalize(json)
     graph = RDF::Graph.new << JSON::LD::API.toRdf(json)
     graph.dump(:normalize)
diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb
index d96446b56..64c429420 100644
--- a/app/lib/activitypub/activity/create.rb
+++ b/app/lib/activitypub/activity/create.rb
@@ -5,7 +5,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
   CONVERTED_TYPES = %w(Image Video Article).freeze
 
   def perform
-    return if delete_arrived_first?(object_uri) || unsupported_object_type?
+    return if delete_arrived_first?(object_uri) || unsupported_object_type? || invalid_origin?(@object['id'])
 
     RedisLock.acquire(lock_options) do |lock|
       if lock.acquired?
@@ -213,7 +213,14 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
 
   def object_url
     return if @object['url'].blank?
-    url_to_href(@object['url'], 'text/html')
+
+    url_candidate = url_to_href(@object['url'], 'text/html')
+
+    if invalid_origin?(url_candidate)
+      nil
+    else
+      url_candidate
+    end
   end
 
   def content_language_map?
@@ -245,6 +252,15 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
     @skip_download ||= DomainBlock.find_by(domain: @account.domain)&.reject_media?
   end
 
+  def invalid_origin?(url)
+    return true if unsupported_uri_scheme?(url)
+
+    needle   = Addressable::URI.parse(url).host
+    haystack = Addressable::URI.parse(@account.uri).host
+
+    !haystack.casecmp(needle).zero?
+  end
+
   def reply_to_local?
     !replied_to_status.nil? && replied_to_status.account.local?
   end
diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb
index 0fbf18c00..f43edafe7 100644
--- a/app/services/activitypub/process_account_service.rb
+++ b/app/services/activitypub/process_account_service.rb
@@ -6,7 +6,7 @@ class ActivityPub::ProcessAccountService < BaseService
   # Should be called with confirmed valid JSON
   # and WebFinger-resolved username and domain
   def call(username, domain, json)
-    return if json['inbox'].blank?
+    return if json['inbox'].blank? || unsupported_uri_scheme?(json['id'])
 
     @json        = json
     @uri         = @json['id']
@@ -107,7 +107,21 @@ class ActivityPub::ProcessAccountService < BaseService
 
   def url
     return if @json['url'].blank?
-    url_to_href(@json['url'], 'text/html')
+
+    url_candidate = url_to_href(@json['url'], 'text/html')
+
+    if unsupported_uri_scheme?(url_candidate) || mismatching_origin?(url_candidate)
+      nil
+    else
+      url_candidate
+    end
+  end
+
+  def mismatching_origin?(url)
+    needle   = Addressable::URI.parse(url).host
+    haystack = Addressable::URI.parse(@uri).host
+
+    !haystack.casecmp(needle).zero?
   end
 
   def outbox_total_items