about summary refs log tree commit diff
path: root/app/lib
diff options
context:
space:
mode:
authorThibaut Girka <thib@sitedethib.com>2020-10-21 19:10:50 +0200
committerThibaut Girka <thib@sitedethib.com>2020-10-21 19:10:50 +0200
commitec49aa81753ac71fa26b2ee86448fa5b481d49e4 (patch)
tree4b775e2e094af4886f24514ba6026f82af8e814a /app/lib
parent29870d2be6c0e78132416b5561aba20d6ca3c746 (diff)
parentca56527140034952002f8f7334da9f94c4f486a8 (diff)
Merge branch 'master' into glitch-soc/merge-upstream
Conflicts:
- `.github/dependabot.yml`:
  Updated upstream, we deleted it to not be flooded by Depandabot.
  Kept deleted.
- `Gemfile.lock`:
  Puma updated on both sides, went for the most recent version.
- `app/controllers/api/v1/mutes_controller.rb`:
  Upstream updated the serializer to support timed mutes, while
  glitch-soc added a custom API ages ago to get information that
  is already available elsewhere.
  Dropped the glitch-soc-specific API, went with upstream changes.
- `app/javascript/core/admin.js`:
  Conflict due to changing how assets are loaded. Went with upstream.
- `app/javascript/packs/public.js`:
  Conflict due to changing how assets are loaded. Went with upstream.
- `app/models/mute.rb`:
  🤷
- `app/models/user.rb`:
  New user setting added upstream while we have glitch-soc-specific
  user settings. Added upstream's user setting.
- `config/settings.yml`:
  Upstream added a new user setting close to a user setting we had
  changed the defaults for. Added the new upstream setting.
- `package.json`:
  Upstream dependency updated “too close” to a glitch-soc-specific
  dependency. No real conflict. Updated the dependency.
Diffstat (limited to 'app/lib')
-rw-r--r--app/lib/activitypub/activity.rb2
-rw-r--r--app/lib/activitypub/tag_manager.rb4
-rw-r--r--app/lib/fast_ip_map.rb32
-rw-r--r--app/lib/sanitize_config.rb1
-rw-r--r--app/lib/settings/scoped_settings.rb2
-rw-r--r--app/lib/user_settings_decorator.rb5
-rw-r--r--app/lib/webfinger.rb93
7 files changed, 136 insertions, 3 deletions
diff --git a/app/lib/activitypub/activity.rb b/app/lib/activitypub/activity.rb
index 224451f41..2b5d3ffc2 100644
--- a/app/lib/activitypub/activity.rb
+++ b/app/lib/activitypub/activity.rb
@@ -74,7 +74,7 @@ class ActivityPub::Activity
     @object_uri ||= begin
       str = value_or_id(@object)
 
-      if str.start_with?('bear:')
+      if str&.start_with?('bear:')
         Addressable::URI.parse(str).query_values['u']
       else
         str
diff --git a/app/lib/activitypub/tag_manager.rb b/app/lib/activitypub/tag_manager.rb
index 3f98dad2e..3f2ae1106 100644
--- a/app/lib/activitypub/tag_manager.rb
+++ b/app/lib/activitypub/tag_manager.rb
@@ -40,6 +40,10 @@ class ActivityPub::TagManager
     end
   end
 
+  def uri_for_username(username)
+    account_url(username: username)
+  end
+
   def generate_uri_for(_target)
     URI.join(root_url, 'payloads', SecureRandom.uuid)
   end
diff --git a/app/lib/fast_ip_map.rb b/app/lib/fast_ip_map.rb
new file mode 100644
index 000000000..ba30b45f3
--- /dev/null
+++ b/app/lib/fast_ip_map.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+class FastIpMap
+  MAX_IPV4_PREFIX = 32
+  MAX_IPV6_PREFIX = 128
+
+  # @param [Enumerable<IPAddr>] addresses
+  def initialize(addresses)
+    @fast_lookup = {}
+    @ranges      = []
+
+    # Hash look-up is faster but only works for exact matches, so we split
+    # exact addresses from non-exact ones
+    addresses.each do |address|
+      if (address.ipv4? && address.prefix == MAX_IPV4_PREFIX) || (address.ipv6? && address.prefix == MAX_IPV6_PREFIX)
+        @fast_lookup[address.to_s] = true
+      else
+        @ranges << address
+      end
+    end
+
+    # We're more likely to hit wider-reaching ranges when checking for
+    # inclusion, so make sure they're sorted first
+    @ranges.sort_by!(&:prefix)
+  end
+
+  # @param [IPAddr] address
+  # @return [Boolean]
+  def include?(address)
+    @fast_lookup[address.to_s] || @ranges.any? { |cidr| cidr.include?(address) }
+  end
+end
diff --git a/app/lib/sanitize_config.rb b/app/lib/sanitize_config.rb
index ccc3f4642..0fb415bd1 100644
--- a/app/lib/sanitize_config.rb
+++ b/app/lib/sanitize_config.rb
@@ -18,6 +18,7 @@ class Sanitize
       gopher
       xmpp
       magnet
+      gemini
     ).freeze
 
     CLASS_WHITELIST_TRANSFORMER = lambda do |env|
diff --git a/app/lib/settings/scoped_settings.rb b/app/lib/settings/scoped_settings.rb
index 8aa826561..9889940f3 100644
--- a/app/lib/settings/scoped_settings.rb
+++ b/app/lib/settings/scoped_settings.rb
@@ -12,7 +12,6 @@ module Settings
       @object = object
     end
 
-    # rubocop:disable Style/MethodMissingSuper
     def method_missing(method, *args)
       method_name = method.to_s
       # set a value for a variable
@@ -25,7 +24,6 @@ module Settings
         self[method_name]
       end
     end
-    # rubocop:enable Style/MethodMissingSuper
 
     def respond_to_missing?(*)
       true
diff --git a/app/lib/user_settings_decorator.rb b/app/lib/user_settings_decorator.rb
index 2f9cfe3ad..581101782 100644
--- a/app/lib/user_settings_decorator.rb
+++ b/app/lib/user_settings_decorator.rb
@@ -28,6 +28,7 @@ class UserSettingsDecorator
     user.settings['display_media']       = display_media_preference if change?('setting_display_media')
     user.settings['expand_spoilers']     = expand_spoilers_preference if change?('setting_expand_spoilers')
     user.settings['reduce_motion']       = reduce_motion_preference if change?('setting_reduce_motion')
+    user.settings['disable_swiping']     = disable_swiping_preference if change?('setting_disable_swiping')
     user.settings['system_font_ui']      = system_font_ui_preference if change?('setting_system_font_ui')
     user.settings['system_emoji_font']   = system_emoji_font_preference if change?('setting_system_emoji_font')
     user.settings['noindex']             = noindex_preference if change?('setting_noindex')
@@ -101,6 +102,10 @@ class UserSettingsDecorator
     boolean_cast_setting 'setting_reduce_motion'
   end
 
+  def disable_swiping_preference
+    boolean_cast_setting 'setting_disable_swiping'
+  end
+
   def noindex_preference
     boolean_cast_setting 'setting_noindex'
   end
diff --git a/app/lib/webfinger.rb b/app/lib/webfinger.rb
new file mode 100644
index 000000000..b2374c494
--- /dev/null
+++ b/app/lib/webfinger.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+class Webfinger
+  class Error < StandardError; end
+
+  class Response
+    def initialize(body)
+      @json = Oj.load(body, mode: :strict)
+    end
+
+    def subject
+      @json['subject']
+    end
+
+    def link(rel, attribute)
+      links.dig(rel, attribute)
+    end
+
+    private
+
+    def links
+      @links ||= @json['links'].map { |link| [link['rel'], link] }.to_h
+    end
+  end
+
+  def initialize(uri)
+    _, @domain = uri.split('@')
+
+    raise ArgumentError, 'Webfinger requested for local account' if @domain.nil?
+
+    @uri = uri
+  end
+
+  def perform
+    Response.new(body_from_webfinger)
+  rescue Oj::ParseError
+    raise Webfinger::Error, "Invalid JSON in response for #{@uri}"
+  rescue Addressable::URI::InvalidURIError
+    raise Webfinger::Error, "Invalid URI for #{@uri}"
+  end
+
+  private
+
+  def body_from_webfinger(url = standard_url, use_fallback = true)
+    webfinger_request(url).perform do |res|
+      if res.code == 200
+        res.body_with_limit
+      elsif res.code == 404 && use_fallback
+        body_from_host_meta
+      else
+        raise Webfinger::Error, "Request for #{@uri} returned HTTP #{res.code}"
+      end
+    end
+  end
+
+  def body_from_host_meta
+    host_meta_request.perform do |res|
+      if res.code == 200
+        body_from_webfinger(url_from_template(res.body_with_limit), false)
+      else
+        raise Webfinger::Error, "Request for #{@uri} returned HTTP #{res.code}"
+      end
+    end
+  end
+
+  def url_from_template(str)
+    link = Nokogiri::XML(str).at_xpath('//xmlns:Link[@rel="lrdd"]')
+
+    if link.present?
+      link['template'].gsub('{uri}', @uri)
+    else
+      raise Webfinger::Error, "Request for #{@uri} returned host-meta without link to Webfinger"
+    end
+  rescue Nokogiri::XML::XPath::SyntaxError
+    raise Webfinger::Error, "Invalid XML encountered in host-meta for #{@uri}"
+  end
+
+  def host_meta_request
+    Request.new(:get, host_meta_url).add_headers('Accept' => 'application/xrd+xml, application/xml, text/xml')
+  end
+
+  def webfinger_request(url)
+    Request.new(:get, url).add_headers('Accept' => 'application/jrd+json, application/json')
+  end
+
+  def standard_url
+    "https://#{@domain}/.well-known/webfinger?resource=#{@uri}"
+  end
+
+  def host_meta_url
+    "https://#{@domain}/.well-known/host-meta"
+  end
+end