Skip to content
Snippets Groups Projects
Commit 8c45cd0e authored by Eugen Rochko's avatar Eugen Rochko Committed by GitHub
Browse files

Improve ActivityPub representations (#3844)

* Improve webfinger templates and make tests more flexible

* Clean up AS2 representation of actor

* Refactor outbox

* Create activities representation

* Add representations of followers/following collections, do not redirect /users/:username route if format is empty

* Remove unused translations

* ActivityPub endpoint for single statuses, add ActivityPub::TagManager for better
URL/URI generation

* Add ActivityPub::TagManager#to

* Represent all attachments as Document instead of Image/Video specifically
(Because for remote ones we may not know for sure)

Add mentions and hashtags representation to AP notes

* Add AP-resolvable hashtag URIs

* Use ActiveModelSerializers for ActivityPub

* Clean up unused translations

* Separate route for object and activity

* Adjust cc/to matrices

* Add to/cc to activities, ensure announce activity embeds target status and
not the wrapper status, add "id" to all collections
parent 3fbf1bf3
No related branches found
No related tags found
No related merge requests found
Showing
with 27 additions and 454 deletions
......@@ -30,15 +30,6 @@ fr:
remote_follow: Suivre à distance
reserved_username: Ce nom d’utilisateur⋅ice est réservé
unfollow: Ne plus suivre
activitypub:
activity:
announce:
name: "%{account_name} a partagé une activité."
create:
name: "%{account_name} a créé une note."
outbox:
name: Boîte d’envoi de %{account_name}
summary: Liste d’activités de %{account_name}
admin:
accounts:
are_you_sure: Êtes-vous certain⋅e ?
......
......@@ -29,15 +29,6 @@ he:
posts: הודעות
remote_follow: מעקב מרחוק
unfollow: הפסקת מעקב
activitypub:
activity:
announce:
name: הודעה שותפה על ידי %{account_name}.
create:
name: הודעה חדשה מאת %{account_name}.
outbox:
name: תיבת הדוא"ל היוצא של %{account_name}
summary: אוסף הפעילויות של %{account_name}.
admin:
accounts:
are_you_sure: בטוח?
......
......@@ -29,15 +29,6 @@ id:
posts: Postingan
remote_follow: Mengikuti
unfollow: Berhenti mengikuti
activitypub:
activity:
announce:
name: "%{account_name} membagikan aktivitas."
create:
name: "%{account_name} membuat catatan."
outbox:
name: "%{account_name} Outbox"
summary: Koleksi aktivitas dari pengguna %{account_name}.
admin:
accounts:
are_you_sure: Anda yakin?
......
......@@ -30,15 +30,6 @@ ja:
remote_follow: リモートフォロー
reserved_username: このユーザー名は予約されています。
unfollow: フォロー解除
activitypub:
activity:
announce:
name: "%{account_name} さんがアクティビティをシェアしました"
create:
name: "%{account_name} さんがノートを作成しました"
outbox:
name: "%{account_name} さんの送信トレイ"
summary: "%{account_name} さんからのアクティビティコレクション"
admin:
accounts:
are_you_sure: 本当に実行しますか?
......
......@@ -30,15 +30,6 @@ ko:
remote_follow: 리모트 팔로우
reserved_username: 이 아이디는 예약되어 있습니다.
unfollow: 팔로우 해제
activitypub:
activity:
announce:
name: "%{account_name} 님이 액티비티를 공유했습니다"
create:
name: "%{account_name} 님이 노트를 작성했습니다"
outbox:
name: "%{account_name} 님의 송신함"
summary: "%{account_name} 님의 액티비티 모음"
admin:
accounts:
are_you_sure: 정말로 실행하시겠습니까?
......
......@@ -29,15 +29,6 @@
posts: Poster
remote_follow: Følg fra andre instanser
unfollow: Avfølg
activitypub:
activity:
announce:
name: "%{account_name} delte en aktivitet."
create:
name: "%{account_name} laget en aktivitet."
outbox:
name: "%{account_name} sin utboks"
summary: En samling aktiviteter fra brukeren %{account_name}.
admin:
accounts:
are_you_sure: Er du sikker?
......
......@@ -29,15 +29,6 @@ oc:
posts: Estatuts
remote_follow: Sègre a distància
unfollow: Quitar de sègre
activitypub:
activity:
announce:
name: "%{account_name} a partejat una activitat."
create:
name: "%{account_name} a creat una nòta."
outbox:
name: "%{account_name}'s Outbox"
summary: A collection of activities from user %{account_name}.
admin:
accounts:
are_you_sure: Sètz segur ?
......
......@@ -44,15 +44,6 @@ pl:
remote_follow: Zdalne śledzenie
reserved_username: Ta nazwa użytkownika jest zarezerwowana.
unfollow: Przestań śledzić
activitypub:
activity:
announce:
name: "%{account_name} udostępnił(a) aktywność."
create:
name: "%{account_name} utworzył(a) wpis."
outbox:
name: Skrzynka %{account_name}
summary: Zbiór aktywności użytkownika %{account_name}.
admin:
accounts:
are_you_sure: Jesteś tego pewien?
......
......@@ -29,15 +29,6 @@ pt-BR:
posts: Posts
remote_follow: Acesso remoto
unfollow: Unfollow
activitypub:
activity:
announce:
name: "%{account_name} compartilhou uma atividade."
create:
name: "%{account_name} criou uma nota."
outbox:
name: "%{account_name}'s Outbox"
summary: Uma coleção de atividades do usuário %{account_name}.
admin:
accounts:
are_you_sure: Você tem certeza?
......
......@@ -29,15 +29,6 @@ pt:
posts: Posts
remote_follow: Seguir remotamente
unfollow: Deixar de seguir
activitypub:
activity:
announce:
name: "%{account_name} anunciou uma atividade."
create:
name: "%{account_name} criou uma nota."
outbox:
name: "%{account_name}'s Outbox"
summary: Uma coleção de atividades do usuário %{account_name}.
admin:
accounts:
are_you_sure: Tens a certeza?
......
......@@ -29,15 +29,6 @@ th:
posts: โพสต์
remote_follow: Remote follow
unfollow: เลิกติดตาม
activitypub:
activity:
announce:
name: "%{account_name} แชร์กิจกรรม."
create:
name: "%{account_name} สร้างโน๊ต."
outbox:
name: "%{account_name}'s Outbox"
summary: รวมกิจกรรมของผู้ใช้ %{account_name}.
admin:
accounts:
are_you_sure: แน่ใจนะ?
......
......@@ -29,15 +29,6 @@ tr:
posts: Gönderiler
remote_follow: Uzaktan takip et
unfollow: Takibi bırak
activitypub:
activity:
announce:
name: "%{account_name} bir aktivite paylaştı."
create:
name: "%{account_name} bir not oluşturdu."
outbox:
name: "%{account_name}'in Gönderdikleri"
summary: "%{account_name}'den gelen aktiviteler."
admin:
accounts:
are_you_sure: Emin misiniz?
......
......@@ -29,15 +29,6 @@ zh-CN:
posts: 嘟文
remote_follow: 跨站关注
unfollow: 取消关注
activitypub:
activity:
announce:
name: "%{account_name} 分享了一个活动。"
create:
name: "%{account_name} 创建了一个记事。"
outbox:
name: "%{account_name} 的集合"
summary: "%{account_name} 的活动集合"
admin:
accounts:
are_you_sure: 你确定吗?
......
......@@ -29,15 +29,6 @@ zh-HK:
posts: 文章
remote_follow: 跨站關注
unfollow: 取消關注
activitypub:
activity:
announce:
name: "%{account_name} 分享了一項活動。"
create:
name: "%{account_name} 新增了一篇筆記。"
outbox:
name: "%{account_name} 的活動"
summary: "%{account_name} 分享的活動列表。"
admin:
accounts:
are_you_sure: 你確定嗎?
......
......@@ -26,7 +26,7 @@ Rails.application.routes.draw do
confirmations: 'auth/confirmations',
}
get '/users/:username', to: redirect('/@%{username}'), constraints: { format: :html }
get '/users/:username', to: redirect('/@%{username}'), constraints: lambda { |req| req.format.nil? }
resources :accounts, path: 'users', only: [:show], param: :username do
resources :stream_entries, path: 'updates', only: [:show] do
......@@ -38,10 +38,17 @@ Rails.application.routes.draw do
get :remote_follow, to: 'remote_follow#new'
post :remote_follow, to: 'remote_follow#create'
resources :statuses, only: [:show] do
member do
get :activity
end
end
resources :followers, only: [:index], controller: :follower_accounts
resources :following, only: [:index], controller: :following_accounts
resource :follow, only: [:create], controller: :account_follow
resource :unfollow, only: [:create], controller: :account_unfollow
resource :outbox, only: [:show], module: :activitypub
end
get '/@:username', to: 'accounts#show', as: :short_account
......@@ -119,13 +126,6 @@ Rails.application.routes.draw do
# OEmbed
get '/oembed', to: 'oembed#show', as: :oembed
# ActivityPub
namespace :activitypub do
get '/users/:id/outbox', to: 'outbox#show', as: :outbox
get '/statuses/:id', to: 'activities#show_status', as: :status
resources :notes, only: [:show]
end
# JSON / REST API
namespace :v1 do
resources :statuses, only: [:create, :show, :destroy] do
......
......@@ -38,7 +38,7 @@ RSpec.describe AccountsController, type: :controller do
context 'activitystreams2' do
before do
get :show, params: { username: alice.username }, format: 'activitystreams2'
get :show, params: { username: alice.username }, format: 'json'
end
it 'assigns @account' do
......
require 'rails_helper'
RSpec.describe Api::ActivityPub::ActivitiesController, type: :controller do
render_views
let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
describe 'GET #show' do
describe 'normal status' do
public_status = nil
before do
public_status = Fabricate(:status, account: user.account, text: 'Hello world', visibility: :public)
@request.env['HTTP_ACCEPT'] = 'application/activity+json'
get :show_status, params: { id: public_status.id }
end
it 'returns http success' do
expect(response).to have_http_status(:success)
end
it 'sets Content-Type header to AS2' do
expect(response.header['Content-Type']).to include 'application/activity+json'
end
it 'returns http success' do
json_data = JSON.parse(response.body)
expect(json_data).to include('@context' => 'https://www.w3.org/ns/activitystreams')
expect(json_data).to include('type' => 'Create')
expect(json_data).to include('id' => @request.url)
expect(json_data).to include('type' => 'Create')
expect(json_data).to include('object' => api_activitypub_note_url(public_status))
expect(json_data).to include('url' => TagManager.instance.url_for(public_status))
end
end
describe 'reblog' do
original = nil
reblog = nil
before do
original = Fabricate(:status, account: user.account, text: 'Hello world', visibility: :public)
reblog = Fabricate(:status, account: user.account, reblog_of_id: original.id, visibility: :public)
@request.env['HTTP_ACCEPT'] = 'application/activity+json'
get :show_status, params: { id: reblog.id }
end
it 'returns http success' do
expect(response).to have_http_status(:success)
end
it 'sets Content-Type header to AS2' do
expect(response.header['Content-Type']).to include 'application/activity+json'
end
it 'returns http success' do
json_data = JSON.parse(response.body)
expect(json_data).to include('@context' => 'https://www.w3.org/ns/activitystreams')
expect(json_data).to include('type' => 'Announce')
expect(json_data).to include('id' => @request.url)
expect(json_data).to include('type' => 'Announce')
expect(json_data).to include('object' => api_activitypub_status_url(original))
expect(json_data).to include('url' => TagManager.instance.url_for(reblog))
end
end
end
end
require 'rails_helper'
RSpec.describe Api::ActivityPub::NotesController, type: :controller do
render_views
let(:user_alice) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
let(:user_bob) { Fabricate(:user, account: Fabricate(:account, username: 'bob')) }
describe 'GET #show' do
describe 'normal status' do
public_status = nil
before do
public_status = Fabricate(:status, account: user_alice.account, text: 'Hello world', visibility: :public)
@request.env['HTTP_ACCEPT'] = 'application/activity+json'
get :show, params: { id: public_status.id }
end
it 'returns http success' do
expect(response).to have_http_status(:success)
end
it 'sets Content-Type header to AS2' do
expect(response.header['Content-Type']).to include 'application/activity+json'
end
it 'returns http success' do
json_data = JSON.parse(response.body)
expect(json_data).to include('@context' => 'https://www.w3.org/ns/activitystreams')
expect(json_data).to include('type' => 'Note')
expect(json_data).to include('id' => @request.url)
expect(json_data).to include('name' => 'Hello world')
expect(json_data).to include('content' => 'Hello world')
expect(json_data).to include('published')
expect(json_data).to include('url' => TagManager.instance.url_for(public_status))
end
end
describe 'reply' do
original = nil
reply = nil
before do
original = Fabricate(:status, account: user_alice.account, text: 'Hello world', visibility: :public)
reply = Fabricate(:status, account: user_bob.account, text: 'Hello world', in_reply_to_id: original.id, visibility: :public)
@request.env['HTTP_ACCEPT'] = 'application/activity+json'
get :show, params: { id: reply.id }
end
it 'returns http success' do
expect(response).to have_http_status(:success)
end
it 'sets Content-Type header to AS2' do
expect(response.header['Content-Type']).to include 'application/activity+json'
end
it 'returns http success' do
json_data = JSON.parse(response.body)
expect(json_data).to include('@context' => 'https://www.w3.org/ns/activitystreams')
expect(json_data).to include('type' => 'Note')
expect(json_data).to include('id' => @request.url)
expect(json_data).to include('name' => 'Hello world')
expect(json_data).to include('content' => 'Hello world')
expect(json_data).to include('published')
expect(json_data).to include('url' => TagManager.instance.url_for(reply))
expect(json_data).to include('inReplyTo' => api_activitypub_note_url(original))
end
end
end
end
require 'rails_helper'
RSpec.describe Api::ActivityPub::OutboxController, type: :controller do
render_views
let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
describe 'GET #show' do
before do
@request.headers['ACCEPT'] = 'application/activity+json'
end
describe 'collection with small number of statuses' do
public_status = nil
before do
public_status = Fabricate(:status, account: user.account, text: 'Hello world', visibility: :public)
Fabricate(:status, account: user.account, text: 'Hello world', visibility: :private)
Fabricate(:status, account: user.account, text: 'Hello world', visibility: :unlisted)
Fabricate(:status, account: user.account, text: 'Hello world', visibility: :direct)
get :show, params: { id: user.account.id }
end
it 'returns http success' do
expect(response).to have_http_status(:success)
end
it 'sets Content-Type header to AS2' do
expect(response.header['Content-Type']).to include 'application/activity+json'
end
it 'returns AS2 JSON body' do
json_data = JSON.parse(response.body)
expect(json_data).to include('@context' => 'https://www.w3.org/ns/activitystreams')
expect(json_data).to include('id' => @request.url)
expect(json_data).to include('type' => 'OrderedCollection')
expect(json_data).to include('totalItems' => 1)
expect(json_data).to include('current')
expect(json_data).to include('first')
expect(json_data).to include('last')
end
end
describe 'collection with large number of statuses' do
before do
30.times do
Fabricate(:status, account: user.account, text: 'Hello world', visibility: :public)
end
Fabricate(:status, account: user.account, text: 'Hello world', visibility: :private)
Fabricate(:status, account: user.account, text: 'Hello world', visibility: :unlisted)
Fabricate(:status, account: user.account, text: 'Hello world', visibility: :direct)
get :show, params: { id: user.account.id }
end
it 'returns http success' do
expect(response).to have_http_status(:success)
end
it 'sets Content-Type header to AS2' do
expect(response.header['Content-Type']).to include 'application/activity+json'
end
it 'returns AS2 JSON body' do
json_data = JSON.parse(response.body)
expect(json_data).to include('@context' => 'https://www.w3.org/ns/activitystreams')
expect(json_data).to include('id' => @request.url)
expect(json_data).to include('type' => 'OrderedCollection')
expect(json_data).to include('totalItems' => 30)
expect(json_data).to include('current')
expect(json_data).to include('first')
expect(json_data).to include('last')
end
end
describe 'page with small number of statuses' do
statuses = []
before do
5.times do
statuses << Fabricate(:status, account: user.account, text: 'Hello world', visibility: :public)
end
Fabricate(:status, account: user.account, text: 'Hello world', visibility: :private)
Fabricate(:status, account: user.account, text: 'Hello world', visibility: :unlisted)
Fabricate(:status, account: user.account, text: 'Hello world', visibility: :direct)
get :show, params: { id: user.account.id, max_id: statuses.last.id + 1 }
end
it 'returns http success' do
expect(response).to have_http_status(:success)
end
it 'sets Content-Type header to AS2' do
expect(response.header['Content-Type']).to include 'application/activity+json'
end
it 'returns AS2 JSON body' do
json_data = JSON.parse(response.body)
expect(json_data).to include('@context' => 'https://www.w3.org/ns/activitystreams')
expect(json_data).to include('id' => @request.url)
expect(json_data).to include('type' => 'OrderedCollectionPage')
expect(json_data).to include('partOf')
expect(json_data).to include('items')
expect(json_data['items'].length).to eq(5)
expect(json_data).to include('prev')
expect(json_data).to include('next')
expect(json_data).to include('current')
expect(json_data).to include('first')
expect(json_data).to include('last')
end
end
describe 'page with large number of statuses' do
statuses = []
before do
30.times do
statuses << Fabricate(:status, account: user.account, text: 'Hello world', visibility: :public)
end
Fabricate(:status, account: user.account, text: 'Hello world', visibility: :private)
Fabricate(:status, account: user.account, text: 'Hello world', visibility: :unlisted)
Fabricate(:status, account: user.account, text: 'Hello world', visibility: :direct)
get :show, params: { id: user.account.id, max_id: statuses.last.id + 1 }
end
it 'returns http success' do
expect(response).to have_http_status(:success)
end
it 'sets Content-Type header to AS2' do
expect(response.header['Content-Type']).to include 'application/activity+json'
end
it 'returns AS2 JSON body' do
json_data = JSON.parse(response.body)
expect(json_data).to include('@context' => 'https://www.w3.org/ns/activitystreams')
expect(json_data).to include('id' => @request.url)
expect(json_data).to include('type' => 'OrderedCollectionPage')
expect(json_data).to include('partOf')
expect(json_data).to include('items')
expect(json_data['items'].length).to eq(20)
expect(json_data).to include('prev')
expect(json_data).to include('next')
expect(json_data).to include('current')
expect(json_data).to include('first')
expect(json_data).to include('last')
end
end
end
end
......@@ -9,7 +9,7 @@ describe WellKnown::WebfingerController, type: :controller do
end
before do
alice.private_key = <<PEM
alice.private_key = <<-PEM
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDHgPoPJlrfMZrVcuF39UbVssa8r4ObLP3dYl9Y17Mgp5K4mSYD
R/Y2ag58tSi6ar2zM3Ze3QYsNfTq0NqN1g89eAu0MbSjWqpOsgntRPJiFuj3hai2
......@@ -27,7 +27,7 @@ FTX8IvYBNTbpEttc1VCf/0ccnNpfb0CrFNSPWxRj7t7D
-----END RSA PRIVATE KEY-----
PEM
alice.public_key = <<PEM
alice.public_key = <<-PEM
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHgPoPJlrfMZrVcuF39UbVssa8
r4ObLP3dYl9Y17Mgp5K4mSYDR/Y2ag58tSi6ar2zM3Ze3QYsNfTq0NqN1g89eAu0
......@@ -48,29 +48,23 @@ PEM
it 'returns JSON when account can be found' do
get :show, params: { resource: alice.to_webfinger_s }, format: :json
json = body_as_json
expect(response).to have_http_status(:success)
expect(response.content_type).to eq 'application/jrd+json'
expect(response.body).to eq "{\"subject\":\"acct:alice@cb6e6126.ngrok.io\",\"aliases\":[\"https://cb6e6126.ngrok.io/@alice\",\"https://cb6e6126.ngrok.io/users/alice\"],\"links\":[{\"rel\":\"http://webfinger.net/rel/profile-page\",\"type\":\"text/html\",\"href\":\"https://cb6e6126.ngrok.io/@alice\"},{\"rel\":\"http://schemas.google.com/g/2010#updates-from\",\"type\":\"application/atom+xml\",\"href\":\"https://cb6e6126.ngrok.io/users/alice.atom\"},{\"rel\":\"self\",\"type\":\"application/activity+json\",\"href\":\"https://cb6e6126.ngrok.io/@alice\"},{\"rel\":\"salmon\",\"href\":\"#{api_salmon_url(alice.id)}\"},{\"rel\":\"magic-public-key\",\"href\":\"data:application/magic-public-key,RSA.x4D6DyZa3zGa1XLhd_VG1bLGvK-Dmyz93WJfWNezIKeSuJkmA0f2NmoOfLUoumq9szN2Xt0GLDX06tDajdYPPXgLtDG0o1qqTrIJ7UTyYhbo94Wotl9iJvEwa5IjP1Mn00YJ_KvFrzKCm15PC7up6r-NtHsqoYS8X1KAqcbnptU=.AQAB\"},{\"rel\":\"http://ostatus.org/schema/1.0/subscribe\",\"template\":\"https://cb6e6126.ngrok.io/authorize_follow?acct={uri}\"}]}"
expect(json[:subject]).to eq 'acct:alice@cb6e6126.ngrok.io'
expect(json[:aliases]).to include('https://cb6e6126.ngrok.io/@alice', 'https://cb6e6126.ngrok.io/users/alice')
end
it 'returns JSON when account can be found' do
get :show, params: { resource: alice.to_webfinger_s }, format: :xml
xml = Nokogiri::XML(response.body)
expect(response).to have_http_status(:success)
expect(response.content_type).to eq 'application/xrd+xml'
expect(response.body).to eq <<"XML"
<?xml version="1.0"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
<Subject>acct:alice@cb6e6126.ngrok.io</Subject>
<Alias>https://cb6e6126.ngrok.io/@alice</Alias>
<Alias>https://cb6e6126.ngrok.io/users/alice</Alias>
<Link rel="http://webfinger.net/rel/profile-page" type="text/html" href="https://cb6e6126.ngrok.io/@alice"/>
<Link rel="http://schemas.google.com/g/2010#updates-from" type="application/atom+xml" href="https://cb6e6126.ngrok.io/users/alice.atom"/>
<Link rel="salmon" href="#{api_salmon_url(alice.id)}"/>
<Link rel="magic-public-key" href="data:application/magic-public-key,RSA.x4D6DyZa3zGa1XLhd_VG1bLGvK-Dmyz93WJfWNezIKeSuJkmA0f2NmoOfLUoumq9szN2Xt0GLDX06tDajdYPPXgLtDG0o1qqTrIJ7UTyYhbo94Wotl9iJvEwa5IjP1Mn00YJ_KvFrzKCm15PC7up6r-NtHsqoYS8X1KAqcbnptU=.AQAB"/>
<Link rel="http://ostatus.org/schema/1.0/subscribe" template="https://cb6e6126.ngrok.io/authorize_follow?acct={uri}"/>
</XRD>
XML
expect(xml.at_xpath('//xmlns:Subject').content).to eq 'acct:alice@cb6e6126.ngrok.io'
expect(xml.xpath('//xmlns:Alias').map(&:content)).to include('https://cb6e6126.ngrok.io/@alice', 'https://cb6e6126.ngrok.io/users/alice')
end
it 'returns http not found when account cannot be found' do
......@@ -80,19 +74,22 @@ XML
end
it 'returns JSON when account can be found with alternate domains' do
Rails.configuration.x.alternate_domains = ["foo.org"]
username, domain = alice.to_webfinger_s.split("@")
Rails.configuration.x.alternate_domains = ['foo.org']
username, = alice.to_webfinger_s.split('@')
get :show, params: { resource: "#{username}@foo.org" }, format: :json
json = body_as_json
expect(response).to have_http_status(:success)
expect(response.content_type).to eq 'application/jrd+json'
expect(response.body).to eq "{\"subject\":\"acct:alice@cb6e6126.ngrok.io\",\"aliases\":[\"https://cb6e6126.ngrok.io/@alice\",\"https://cb6e6126.ngrok.io/users/alice\"],\"links\":[{\"rel\":\"http://webfinger.net/rel/profile-page\",\"type\":\"text/html\",\"href\":\"https://cb6e6126.ngrok.io/@alice\"},{\"rel\":\"http://schemas.google.com/g/2010#updates-from\",\"type\":\"application/atom+xml\",\"href\":\"https://cb6e6126.ngrok.io/users/alice.atom\"},{\"rel\":\"self\",\"type\":\"application/activity+json\",\"href\":\"https://cb6e6126.ngrok.io/@alice\"},{\"rel\":\"salmon\",\"href\":\"#{api_salmon_url(alice.id)}\"},{\"rel\":\"magic-public-key\",\"href\":\"data:application/magic-public-key,RSA.x4D6DyZa3zGa1XLhd_VG1bLGvK-Dmyz93WJfWNezIKeSuJkmA0f2NmoOfLUoumq9szN2Xt0GLDX06tDajdYPPXgLtDG0o1qqTrIJ7UTyYhbo94Wotl9iJvEwa5IjP1Mn00YJ_KvFrzKCm15PC7up6r-NtHsqoYS8X1KAqcbnptU=.AQAB\"},{\"rel\":\"http://ostatus.org/schema/1.0/subscribe\",\"template\":\"https://cb6e6126.ngrok.io/authorize_follow?acct={uri}\"}]}"
expect(json[:subject]).to eq 'acct:alice@cb6e6126.ngrok.io'
expect(json[:aliases]).to include('https://cb6e6126.ngrok.io/@alice', 'https://cb6e6126.ngrok.io/users/alice')
end
it 'returns http not found when account can not be found with alternate domains' do
Rails.configuration.x.alternate_domains = ["foo.org"]
username, domain = alice.to_webfinger_s.split("@")
Rails.configuration.x.alternate_domains = ['foo.org']
username, = alice.to_webfinger_s.split('@')
get :show, params: { resource: "#{username}@bar.org" }, format: :json
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment