end
def username_from_resource
- if resource_param =~ /\Ahttps?:\/\//
- path_params = Rails.application.routes.recognize_path(resource_param)
- raise ActiveRecord::RecordNotFound unless path_params[:controller] == 'users' && path_params[:action] == 'show'
- path_params[:username]
- else
- username, domain = resource_param.gsub(/\Aacct:/, '').split('@')
- raise ActiveRecord::RecordNotFound unless TagManager.instance.local_domain?(domain)
- username
- end
+ WebfingerResource.new(resource_param).username
end
def pem_to_magic_key(public_key)
--- /dev/null
+# frozen_string_literal: true
+
+class WebfingerResource
+ attr_reader :resource
+
+ def initialize(resource)
+ @resource = resource
+ end
+
+ def username
+ case resource
+ when /\Ahttps?/i
+ username_from_url
+ when /\@/
+ username_from_acct
+ else
+ raise(ActiveRecord::RecordNotFound)
+ end
+ end
+
+ private
+
+ def username_from_url
+ if account_show_page?
+ path_params[:username]
+ else
+ raise ActiveRecord::RecordNotFound
+ end
+ end
+
+ def account_show_page?
+ path_params[:controller] == 'accounts' && path_params[:action] == 'show'
+ end
+
+ def path_params
+ Rails.application.routes.recognize_path(resource)
+ end
+
+ def username_from_acct
+ if domain_matches_local?
+ local_username
+ else
+ raise ActiveRecord::RecordNotFound
+ end
+ end
+
+ def split_acct
+ resource_without_acct_string.split('@')
+ end
+
+ def resource_without_acct_string
+ resource.gsub(/\Aacct:/, '')
+ end
+
+ def local_username
+ split_acct.first
+ end
+
+ def local_domain
+ split_acct.last
+ end
+
+ def domain_matches_local?
+ TagManager.instance.local_domain?(local_domain)
+ end
+end
--- /dev/null
+require 'rails_helper'
+
+describe WebfingerResource do
+ describe '#username' do
+ describe 'with a URL value' do
+ it 'raises with an unrecognized route' do
+ resource = 'https://example.com/users/alice/other'
+
+ expect {
+ WebfingerResource.new(resource).username
+ }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+
+ it 'raises with a string that doesnt start with URL' do
+ resource = 'website for http://example.com/users/alice/other'
+
+ expect {
+ WebfingerResource.new(resource).username
+ }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+
+ it 'finds the username in a valid https route' do
+ resource = 'https://example.com/users/alice'
+
+ result = WebfingerResource.new(resource).username
+ expect(result).to eq 'alice'
+ end
+
+ it 'finds the username in a mixed case http route' do
+ resource = 'HTTp://exAMPLEe.com/users/alice'
+
+ result = WebfingerResource.new(resource).username
+ expect(result).to eq 'alice'
+ end
+
+ it 'finds the username in a valid http route' do
+ resource = 'http://example.com/users/alice'
+
+ result = WebfingerResource.new(resource).username
+ expect(result).to eq 'alice'
+ end
+ end
+
+ describe 'with a username and hostname value' do
+ it 'raises on a non-local domain' do
+ resource = 'user@remote-host.com'
+
+ expect {
+ WebfingerResource.new(resource).username
+ }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+
+ it 'finds username for a local domain' do
+ Rails.configuration.x.local_domain = 'example.com'
+ resource = 'alice@example.com'
+
+ result = WebfingerResource.new(resource).username
+ expect(result).to eq 'alice'
+ end
+ end
+
+ describe 'with an acct value' do
+ it 'raises on a non-local domain' do
+ resource = 'acct:user@remote-host.com'
+
+ expect {
+ WebfingerResource.new(resource).username
+ }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+
+ it 'raises on a nonsense domain' do
+ resource = 'acct:user@remote-host@remote-hostess.remote.local@remote'
+
+ expect {
+ WebfingerResource.new(resource).username
+ }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+
+ it 'finds the username for a local account' do
+ Rails.configuration.x.local_domain = 'example.com'
+ resource = 'acct:alice@example.com'
+
+ result = WebfingerResource.new(resource).username
+ expect(result).to eq 'alice'
+ end
+ end
+ end
+end