@@ -37,8 +37,8 @@ defmodule Pleroma.Web.OStatus do | |||
def handle_note(doc) do | |||
content_html = string_from_xpath("/entry/content[1]", doc) | |||
[author] = :xmerl_xpath.string('/entry/author[1]', doc) | |||
{:ok, actor} = find_or_make_user(author) | |||
uri = string_from_xpath("/entry/author/uri[1]", doc) | |||
{:ok, actor} = find_or_make_user(uri) | |||
context = string_from_xpath("/entry/ostatus:conversation[1]", doc) |> String.trim | |||
context = if String.length(context) > 0 do | |||
@@ -78,42 +78,30 @@ defmodule Pleroma.Web.OStatus do | |||
ActivityPub.create(to, actor, context, object, %{}, date) | |||
end | |||
def find_or_make_user(author_doc) do | |||
{:xmlObj, :string, uri } = :xmerl_xpath.string('string(/author[1]/uri)', author_doc) | |||
def find_or_make_user(uri) do | |||
query = from user in User, | |||
where: user.local == false and fragment("? @> ?", user.info, ^%{ostatus_uri: to_string(uri)}) | |||
where: user.local == false and fragment("? @> ?", user.info, ^%{uri: uri}) | |||
user = Repo.one(query) | |||
if is_nil(user) do | |||
make_user(author_doc) | |||
make_user(uri) | |||
else | |||
{:ok, user} | |||
end | |||
end | |||
def make_user(author_doc) do | |||
author = string_from_xpath("/author[1]/uri", author_doc) | |||
name = string_from_xpath("/author[1]/name", author_doc) | |||
preferredUsername = string_from_xpath("/author[1]/poco:preferredUsername", author_doc) | |||
displayName = string_from_xpath("/author[1]/poco:displayName", author_doc) | |||
avatar = make_avatar_object(author_doc) | |||
data = %{ | |||
local: false, | |||
name: preferredUsername || name, | |||
nickname: displayName || name, | |||
ap_id: author, | |||
info: %{ | |||
"ostatus_uri" => author, | |||
"host" => URI.parse(author).host, | |||
"system" => "ostatus" | |||
}, | |||
avatar: avatar | |||
} | |||
Repo.insert(Ecto.Changeset.change(%User{}, data)) | |||
def make_user(uri) do | |||
with {:ok, info} <- gather_user_info(uri) do | |||
data = %{ | |||
local: false, | |||
name: info.name, | |||
nickname: info.nickname, | |||
ap_id: info.uri, | |||
info: info | |||
} | |||
Repo.insert(Ecto.Changeset.change(%User{}, data)) | |||
end | |||
end | |||
# TODO: Just takes the first one for now. | |||
@@ -42,7 +42,7 @@ defmodule Pleroma.Web.WebFinger do | |||
# FIXME: Make this call the host-meta to find the actual address. | |||
defp webfinger_address(domain) do | |||
"https://#{domain}/.well-known/webfinger" | |||
"//#{domain}/.well-known/webfinger" | |||
end | |||
defp webfinger_from_xml(doc) do | |||
@@ -61,9 +61,21 @@ defmodule Pleroma.Web.WebFinger do | |||
end | |||
def finger(account, getter \\ &HTTPoison.get/3) do | |||
[name, domain] = String.split(account, "@") | |||
domain = with [_name, domain] <- String.split(account, "@") do | |||
domain | |||
else _e -> | |||
URI.parse(account).host | |||
end | |||
address = webfinger_address(domain) | |||
with {:ok, %{status_code: status_code, body: body}} when status_code in 200..299 <- getter.(address, ["Accept": "application/xrd+xml"], [params: [resource: account]]), | |||
# try https first | |||
response = with {:ok, result} <- getter.("https:" <> address, ["Accept": "application/xrd+xml"], [params: [resource: account]]) do | |||
{:ok, result} | |||
else _ -> | |||
getter.("http:" <> address, ["Accept": "application/xrd+xml"], [params: [resource: account]]) | |||
end | |||
with {:ok, %{status_code: status_code, body: body}} when status_code in 200..299 <- response, | |||
doc <- XML.parse_document(body), | |||
{:ok, data} <- webfinger_from_xml(doc) do | |||
{:ok, data} | |||
@@ -102,19 +102,21 @@ defmodule Pleroma.Web.Websub do | |||
end | |||
end | |||
def subscribe(user, topic, requester \\ &request_subscription/1) do | |||
def subscribe(subscriber, subscribed, requester \\ &request_subscription/1) do | |||
topic = subscribed.info["topic"] | |||
# FIXME: Race condition, use transactions | |||
{:ok, subscription} = with subscription when not is_nil(subscription) <- Repo.get_by(WebsubClientSubscription, topic: topic) do | |||
subscribers = [user.ap_id, subscription.subcribers] |> Enum.uniq | |||
subscribers = [subscriber.ap_id, subscription.subscribers] |> Enum.uniq | |||
change = Ecto.Changeset.change(subscription, %{subscribers: subscribers}) | |||
Repo.update(change) | |||
else _e -> | |||
subscription = %WebsubClientSubscription{ | |||
topic: topic, | |||
subscribers: [user.ap_id], | |||
hub: subscribed.info["hub"], | |||
subscribers: [subscriber.ap_id], | |||
state: "requested", | |||
secret: :crypto.strong_rand_bytes(8) |> Base.url_encode64, | |||
user: user | |||
user: subscribed | |||
} | |||
Repo.insert(subscription) | |||
end | |||
@@ -25,40 +25,20 @@ defmodule Pleroma.Web.OStatusTest do | |||
end | |||
describe "new remote user creation" do | |||
test "make new user or find them based on an 'author' xml doc" do | |||
incoming = File.read!("test/fixtures/user_name_only.xml") | |||
doc = XML.parse_document(incoming) | |||
{:ok, user} = OStatus.find_or_make_user(doc) | |||
assert user.name == "lambda" | |||
assert user.nickname == "lambda" | |||
assert user.local == false | |||
assert user.info["ostatus_uri"] == "http://gs.example.org:4040/index.php/user/1" | |||
assert user.info["system"] == "ostatus" | |||
assert user.ap_id == "http://gs.example.org:4040/index.php/user/1" | |||
{:ok, user_again} = OStatus.find_or_make_user(doc) | |||
assert user == user_again | |||
end | |||
test "tries to use the information in poco fields" do | |||
incoming = File.read!("test/fixtures/user_full.xml") | |||
doc = XML.parse_document(incoming) | |||
# TODO make test local | |||
uri = "https://social.heldscal.la/user/23211" | |||
{:ok, user} = OStatus.find_or_make_user(doc) | |||
{:ok, user} = OStatus.find_or_make_user(uri) | |||
user = Repo.get(Pleroma.User, user.id) | |||
assert user.name == "Constance Variable" | |||
assert user.nickname == "lambadalambda" | |||
assert user.local == false | |||
assert user.info["ostatus_uri"] == "http://gs.example.org:4040/index.php/user/1" | |||
assert user.info["system"] == "ostatus" | |||
assert user.ap_id == "http://gs.example.org:4040/index.php/user/1" | |||
assert List.first(user.avatar["url"])["href"] == "http://gs.example.org:4040/theme/neo-gnu/default-avatar-profile.png" | |||
assert user.info["uri"] == uri | |||
assert user.ap_id == uri | |||
{:ok, user_again} = OStatus.find_or_make_user(doc) | |||
{:ok, user_again} = OStatus.find_or_make_user(uri) | |||
assert user == user_again | |||
end | |||
@@ -84,5 +64,25 @@ defmodule Pleroma.Web.OStatusTest do | |||
} | |||
assert data == expected | |||
end | |||
test "it works with the uri" do | |||
user = "https://social.heldscal.la/user/29191" | |||
# TODO: make test local | |||
{:ok, data} = OStatus.gather_user_info(user) | |||
expected = %{ | |||
hub: "https://social.heldscal.la/main/push/hub", | |||
magic_key: "RSA.wQ3i9UA0qmAxZ0WTIp4a-waZn_17Ez1pEEmqmqoooRsG1_BvpmOvLN0G2tEcWWxl2KOtdQMCiPptmQObeZeuj48mdsDZ4ArQinexY2hCCTcbV8Xpswpkb8K05RcKipdg07pnI7tAgQ0VWSZDImncL6YUGlG5YN8b5TjGOwk2VG8=.AQAB", | |||
name: "shp", | |||
nickname: "shp", | |||
salmon: "https://social.heldscal.la/main/salmon/user/29191", | |||
subject: "https://social.heldscal.la/user/29191", | |||
topic: "https://social.heldscal.la/api/statuses/user_timeline/29191.atom", | |||
uri: "https://social.heldscal.la/user/29191", | |||
fqn: user | |||
} | |||
assert data == expected | |||
end | |||
end | |||
end |
@@ -93,12 +93,13 @@ defmodule Pleroma.Web.WebsubTest do | |||
end | |||
test "initiate a subscription for a given user and topic" do | |||
user = insert(:user) | |||
topic = "http://example.org/some-topic.atom" | |||
subscriber = insert(:user) | |||
user = insert(:user, %{info: %{ "topic" => "some_topic", "hub" => "some_hub"}}) | |||
{:ok, websub} = Websub.subscribe(user, topic, &accepting_verifier/1) | |||
assert websub.subscribers == [user.ap_id] | |||
assert websub.topic == topic | |||
{:ok, websub} = Websub.subscribe(subscriber, user, &accepting_verifier/1) | |||
assert websub.subscribers == [subscriber.ap_id] | |||
assert websub.topic == "some_topic" | |||
assert websub.hub == "some_hub" | |||
assert is_binary(websub.secret) | |||
assert websub.user == user | |||
assert websub.state == "accepted" | |||