Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
pleroma
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
1
Issues
1
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Hakaba Hitoyo
pleroma
Commits
46c7c238
Commit
46c7c238
authored
Aug 27, 2018
by
lain
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature/relay' into 'develop'
message relay Closes #144 See merge request
pleroma/pleroma!264
parents
440b459c
0f5bff8c
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
202 additions
and
7 deletions
+202
-7
config/config.exs
config/config.exs
+1
-0
lib/mix/tasks/relay_follow.ex
lib/mix/tasks/relay_follow.ex
+15
-0
lib/mix/tasks/relay_unfollow.ex
lib/mix/tasks/relay_unfollow.ex
+15
-0
lib/pleroma/user.ex
lib/pleroma/user.ex
+27
-3
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/activity_pub/activity_pub.ex
+12
-1
lib/pleroma/web/activity_pub/activity_pub_controller.ex
lib/pleroma/web/activity_pub/activity_pub_controller.ex
+12
-0
lib/pleroma/web/activity_pub/relay.ex
lib/pleroma/web/activity_pub/relay.ex
+44
-0
lib/pleroma/web/activity_pub/utils.ex
lib/pleroma/web/activity_pub/utils.ex
+26
-1
lib/pleroma/web/activity_pub/views/user_view.ex
lib/pleroma/web/activity_pub/views/user_view.ex
+29
-0
lib/pleroma/web/federator/federator.ex
lib/pleroma/web/federator/federator.ex
+6
-0
lib/pleroma/web/router.ex
lib/pleroma/web/router.ex
+12
-0
test/user_test.exs
test/user_test.exs
+1
-1
test/web/twitter_api/twitter_api_controller_test.exs
test/web/twitter_api/twitter_api_controller_test.exs
+2
-1
No files found.
config/config.exs
View file @
46c7c238
...
...
@@ -61,6 +61,7 @@
upload_limit:
16_000_000
,
registrations_open:
true
,
federating:
true
,
allow_relay:
true
,
rewrite_policy:
Pleroma
.
Web
.
ActivityPub
.
MRF
.
NoOpPolicy
,
public:
true
,
quarantined_instances:
[]
...
...
lib/mix/tasks/relay_follow.ex
0 → 100644
View file @
46c7c238
defmodule
Mix
.
Tasks
.
RelayFollow
do
use
Mix
.
Task
require
Logger
alias
Pleroma
.
Web
.
ActivityPub
.
Relay
@shortdoc
"Follows a remote relay"
def
run
([
target
])
do
Mix
.
Task
.
run
(
"app.start"
)
:ok
=
Relay
.
follow
(
target
)
# put this task to sleep to allow the genserver to push out the messages
:timer
.
sleep
(
500
)
end
end
lib/mix/tasks/relay_unfollow.ex
0 → 100644
View file @
46c7c238
defmodule
Mix
.
Tasks
.
RelayUnfollow
do
use
Mix
.
Task
require
Logger
alias
Pleroma
.
Web
.
ActivityPub
.
Relay
@shortdoc
"Follows a remote relay"
def
run
([
target
])
do
Mix
.
Task
.
run
(
"app.start"
)
:ok
=
Relay
.
unfollow
(
target
)
# put this task to sleep to allow the genserver to push out the messages
:timer
.
sleep
(
500
)
end
end
lib/pleroma/user.ex
View file @
46c7c238
...
...
@@ -77,7 +77,7 @@ def remote_user_creation(params) do
changes
=
%
User
{}
|>
cast
(
params
,
[
:bio
,
:name
,
:ap_id
,
:nickname
,
:info
,
:avatar
])
|>
validate_required
([
:name
,
:ap_id
,
:nickname
])
|>
validate_required
([
:name
,
:ap_id
])
|>
unique_constraint
(
:nickname
)
|>
validate_format
(
:nickname
,
@email_regex
)
|>
validate_length
(
:bio
,
max:
5000
)
...
...
@@ -516,7 +516,8 @@ def search(query, resolve) do
u
.
nickname
,
u
.
name
)
}
},
where:
not
is_nil
(
u
.
nickname
)
)
q
=
...
...
@@ -595,7 +596,11 @@ def unblock_domain(user, domain) do
end
def
local_user_query
()
do
from
(
u
in
User
,
where:
u
.
local
==
true
)
from
(
u
in
User
,
where:
u
.
local
==
true
,
where:
not
is_nil
(
u
.
nickname
)
)
end
def
deactivate
(%
User
{}
=
user
)
do
...
...
@@ -654,6 +659,25 @@ def get_or_fetch_by_ap_id(ap_id) do
end
end
def
get_or_create_instance_user
do
relay_uri
=
"
#{
Pleroma
.
Web
.
Endpoint
.
url
()
}
/relay"
if
user
=
get_by_ap_id
(
relay_uri
)
do
user
else
changes
=
%
User
{}
|>
cast
(%{},
[
:ap_id
,
:nickname
,
:local
])
|>
put_change
(
:ap_id
,
relay_uri
)
|>
put_change
(
:nickname
,
nil
)
|>
put_change
(
:local
,
true
)
|>
put_change
(
:follower_address
,
relay_uri
<>
"/followers"
)
{
:ok
,
user
}
=
Repo
.
insert
(
changes
)
user
end
end
# AP style
def
public_key_from_info
(%{
"source_data"
=>
%{
"publicKey"
=>
%{
"publicKeyPem"
=>
public_key_pem
}}
...
...
lib/pleroma/web/activity_pub/activity_pub.ex
View file @
46c7c238
...
...
@@ -572,12 +572,23 @@ def user_data_from_user_object(data) do
"locked"
=>
locked
},
avatar:
avatar
,
nickname:
"
#{
data
[
"preferredUsername"
]
}
@
#{
URI
.
parse
(
data
[
"id"
])
.
host
}
"
,
name:
data
[
"name"
],
follower_address:
data
[
"followers"
],
bio:
data
[
"summary"
]
}
# nickname can be nil because of virtual actors
user_data
=
if
data
[
"preferredUsername"
]
do
Map
.
put
(
user_data
,
:nickname
,
"
#{
data
[
"preferredUsername"
]
}
@
#{
URI
.
parse
(
data
[
"id"
])
.
host
}
"
)
else
Map
.
put
(
user_data
,
:nickname
,
nil
)
end
{
:ok
,
user_data
}
end
...
...
lib/pleroma/web/activity_pub/activity_pub_controller.ex
View file @
46c7c238
...
...
@@ -3,6 +3,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
alias
Pleroma
.
{
User
,
Object
}
alias
Pleroma
.
Web
.
ActivityPub
.
{
ObjectView
,
UserView
}
alias
Pleroma
.
Web
.
ActivityPub
.
ActivityPub
alias
Pleroma
.
Web
.
ActivityPub
.
Relay
alias
Pleroma
.
Web
.
Federator
require
Logger
...
...
@@ -107,6 +108,17 @@ def inbox(conn, params) do
json
(
conn
,
"ok"
)
end
def
relay
(
conn
,
params
)
do
with
%
User
{}
=
user
<-
Relay
.
get_actor
(),
{
:ok
,
user
}
<-
Pleroma
.
Web
.
WebFinger
.
ensure_keys_present
(
user
)
do
conn
|>
put_resp_header
(
"content-type"
,
"application/activity+json"
)
|>
json
(
UserView
.
render
(
"user.json"
,
%{
user:
user
}))
else
nil
->
{
:error
,
:not_found
}
end
end
def
errors
(
conn
,
{
:error
,
:not_found
})
do
conn
|>
put_status
(
404
)
...
...
lib/pleroma/web/activity_pub/relay.ex
0 → 100644
View file @
46c7c238
defmodule
Pleroma
.
Web
.
ActivityPub
.
Relay
do
alias
Pleroma
.
{
User
,
Object
,
Activity
}
alias
Pleroma
.
Web
.
ActivityPub
.
ActivityPub
require
Logger
def
get_actor
do
User
.
get_or_create_instance_user
()
end
def
follow
(
target_instance
)
do
with
%
User
{}
=
local_user
<-
get_actor
(),
%
User
{}
=
target_user
<-
User
.
get_or_fetch_by_ap_id
(
target_instance
),
{
:ok
,
activity
}
<-
ActivityPub
.
follow
(
local_user
,
target_user
)
do
Logger
.
info
(
"relay: followed instance:
#{
target_instance
}
; id=
#{
activity
.
data
[
"id"
]
}
"
)
else
e
->
Logger
.
error
(
"error:
#{
inspect
(
e
)
}
"
)
end
:ok
end
def
unfollow
(
target_instance
)
do
with
%
User
{}
=
local_user
<-
get_actor
(),
%
User
{}
=
target_user
<-
User
.
get_or_fetch_by_ap_id
(
target_instance
),
{
:ok
,
activity
}
<-
ActivityPub
.
unfollow
(
local_user
,
target_user
)
do
Logger
.
info
(
"relay: unfollowed instance:
#{
target_instance
}
: id=
#{
activity
.
data
[
"id"
]
}
"
)
else
e
->
Logger
.
error
(
"error:
#{
inspect
(
e
)
}
"
)
end
:ok
end
def
publish
(%
Activity
{
data:
%{
"type"
=>
"Create"
}}
=
activity
)
do
with
%
User
{}
=
user
<-
get_actor
(),
%
Object
{}
=
object
<-
Object
.
normalize
(
activity
.
data
[
"object"
][
"id"
])
do
ActivityPub
.
announce
(
user
,
object
)
else
e
->
Logger
.
error
(
"error:
#{
inspect
(
e
)
}
"
)
end
end
def
publish
(
_
),
do
:
nil
end
lib/pleroma/web/activity_pub/utils.ex
View file @
46c7c238
...
...
@@ -306,6 +306,24 @@ def get_existing_announce(actor, %{data: %{"id" => id}}) do
@doc
"""
Make announce activity data for the given actor and object
"""
# for relayed messages, we only want to send to subscribers
def
make_announce_data
(
%
User
{
ap_id:
ap_id
,
nickname:
nil
}
=
user
,
%
Object
{
data:
%{
"id"
=>
id
}}
=
object
,
activity_id
)
do
data
=
%{
"type"
=>
"Announce"
,
"actor"
=>
ap_id
,
"object"
=>
id
,
"to"
=>
[
user
.
follower_address
],
"cc"
=>
[],
"context"
=>
object
.
data
[
"context"
]
}
if
activity_id
,
do
:
Map
.
put
(
data
,
"id"
,
activity_id
),
else
:
data
end
def
make_announce_data
(
%
User
{
ap_id:
ap_id
}
=
user
,
%
Object
{
data:
%{
"id"
=>
id
}}
=
object
,
...
...
@@ -360,7 +378,12 @@ def make_unlike_data(
if
activity_id
,
do
:
Map
.
put
(
data
,
"id"
,
activity_id
),
else
:
data
end
def
add_announce_to_object
(%
Activity
{
data:
%{
"actor"
=>
actor
}},
object
)
do
def
add_announce_to_object
(
%
Activity
{
data:
%{
"actor"
=>
actor
,
"cc"
=>
[
"https://www.w3.org/ns/activitystreams#Public"
]}
},
object
)
do
announcements
=
if
is_list
(
object
.
data
[
"announcements"
]),
do
:
object
.
data
[
"announcements"
],
else
:
[]
...
...
@@ -369,6 +392,8 @@ def add_announce_to_object(%Activity{data: %{"actor" => actor}}, object) do
end
end
def
add_announce_to_object
(
_
,
object
),
do
:
{
:ok
,
object
}
def
remove_announce_from_object
(%
Activity
{
data:
%{
"actor"
=>
actor
}},
object
)
do
announcements
=
if
is_list
(
object
.
data
[
"announcements"
]),
do
:
object
.
data
[
"announcements"
],
else
:
[]
...
...
lib/pleroma/web/activity_pub/views/user_view.ex
View file @
46c7c238
...
...
@@ -9,6 +9,35 @@ defmodule Pleroma.Web.ActivityPub.UserView do
alias
Pleroma
.
Web
.
ActivityPub
.
Utils
import
Ecto
.
Query
# the instance itself is not a Person, but instead an Application
def
render
(
"user.json"
,
%{
user:
%{
nickname:
nil
}
=
user
})
do
{
:ok
,
user
}
=
WebFinger
.
ensure_keys_present
(
user
)
{
:ok
,
_
,
public_key
}
=
Salmon
.
keys_from_pem
(
user
.
info
[
"keys"
])
public_key
=
:public_key
.
pem_entry_encode
(
:SubjectPublicKeyInfo
,
public_key
)
public_key
=
:public_key
.
pem_encode
([
public_key
])
%{
"@context"
=>
"https://www.w3.org/ns/activitystreams"
,
"id"
=>
user
.
ap_id
,
"type"
=>
"Application"
,
"following"
=>
"
#{
user
.
ap_id
}
/following"
,
"followers"
=>
"
#{
user
.
ap_id
}
/followers"
,
"inbox"
=>
"
#{
user
.
ap_id
}
/inbox"
,
"name"
=>
"Pleroma"
,
"summary"
=>
"Virtual actor for Pleroma relay"
,
"url"
=>
user
.
ap_id
,
"manuallyApprovesFollowers"
=>
false
,
"publicKey"
=>
%{
"id"
=>
"
#{
user
.
ap_id
}
#main-key"
,
"owner"
=>
user
.
ap_id
,
"publicKeyPem"
=>
public_key
},
"endpoints"
=>
%{
"sharedInbox"
=>
"
#{
Pleroma
.
Web
.
Endpoint
.
url
()
}
/inbox"
}
}
end
def
render
(
"user.json"
,
%{
user:
user
})
do
{
:ok
,
user
}
=
WebFinger
.
ensure_keys_present
(
user
)
{
:ok
,
_
,
public_key
}
=
Salmon
.
keys_from_pem
(
user
.
info
[
"keys"
])
...
...
lib/pleroma/web/federator/federator.ex
View file @
46c7c238
...
...
@@ -4,6 +4,7 @@ defmodule Pleroma.Web.Federator do
alias
Pleroma
.
Activity
alias
Pleroma
.
Web
.
{
WebFinger
,
Websub
}
alias
Pleroma
.
Web
.
ActivityPub
.
ActivityPub
alias
Pleroma
.
Web
.
ActivityPub
.
Relay
alias
Pleroma
.
Web
.
ActivityPub
.
Transmogrifier
alias
Pleroma
.
Web
.
ActivityPub
.
Utils
require
Logger
...
...
@@ -69,6 +70,11 @@ def handle(:publish, activity) do
Logger
.
info
(
fn
->
"Sending
#{
activity
.
data
[
"id"
]
}
out via Salmon"
end
)
Pleroma
.
Web
.
Salmon
.
publish
(
actor
,
activity
)
if
Mix
.
env
()
!=
:test
do
Logger
.
info
(
fn
->
"Relaying
#{
activity
.
data
[
"id"
]
}
out"
end
)
Pleroma
.
Web
.
ActivityPub
.
Relay
.
publish
(
activity
)
end
end
Logger
.
info
(
fn
->
"Sending
#{
activity
.
data
[
"id"
]
}
out via AP"
end
)
...
...
lib/pleroma/web/router.ex
View file @
46c7c238
...
...
@@ -5,6 +5,7 @@ defmodule Pleroma.Web.Router do
@instance
Application
.
get_env
(
:pleroma
,
:instance
)
@federating
Keyword
.
get
(
@instance
,
:federating
)
@allow_relay
Keyword
.
get
(
@instance
,
:allow_relay
)
@public
Keyword
.
get
(
@instance
,
:public
)
@registrations_open
Keyword
.
get
(
@instance
,
:registrations_open
)
...
...
@@ -293,6 +294,10 @@ def user_fetcher(username_or_email) do
get
(
"/externalprofile/show"
,
TwitterAPI
.
Controller
,
:external_profile
)
end
pipeline
:ap_relay
do
plug
(
:accepts
,
[
"activity+json"
])
end
pipeline
:ostatus
do
plug
(
:accepts
,
[
"xml"
,
"atom"
,
"html"
,
"activity+json"
])
end
...
...
@@ -329,6 +334,13 @@ def user_fetcher(username_or_email) do
end
if
@federating
do
if
@allow_relay
do
scope
"/relay"
,
Pleroma
.
Web
.
ActivityPub
do
pipe_through
(
:ap_relay
)
get
(
"/"
,
ActivityPubController
,
:relay
)
end
end
scope
"/"
,
Pleroma
.
Web
.
ActivityPub
do
pipe_through
(
:activitypub
)
post
(
"/users/:nickname/inbox"
,
ActivityPubController
,
:inbox
)
...
...
test/user_test.exs
View file @
46c7c238
...
...
@@ -220,7 +220,7 @@ test "it enforces the fqn format for nicknames" do
end
test
"it has required fields"
do
[
:name
,
:
nickname
,
:
ap_id
]
[
:name
,
:ap_id
]
|>
Enum
.
each
(
fn
field
->
cs
=
User
.
remote_user_creation
(
Map
.
delete
(
@valid_remote
,
field
))
refute
cs
.
valid?
...
...
test/web/twitter_api/twitter_api_controller_test.exs
View file @
46c7c238
...
...
@@ -77,7 +77,8 @@ test "with credentials", %{conn: conn, user: user} do
conn
=
conn_with_creds
|>
post
(
request_path
,
%{
status:
" "
})
assert
json_response
(
conn
,
400
)
==
error_response
conn
=
conn_with_creds
|>
post
(
request_path
,
%{
status:
"Nice meme."
})
# we post with visibility private in order to avoid triggering relay
conn
=
conn_with_creds
|>
post
(
request_path
,
%{
status:
"Nice meme."
,
visibility:
"private"
})
assert
json_response
(
conn
,
200
)
==
ActivityRepresenter
.
to_map
(
Repo
.
one
(
Activity
),
%{
user:
user
})
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment