From 43d7a4b2cfe686c15b68f6599ce16446fa1dfab0 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 24 Apr 2017 08:48:52 +0200 Subject: Add basic fields to support remote users. --- lib/pleroma/user.ex | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 3ce07d510..160acbdb9 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -15,6 +15,8 @@ defmodule Pleroma.User do field :following, { :array, :string }, default: [] field :ap_id, :string field :avatar, :map + field :local, :boolean, default: true + field :info, :map timestamps() end -- cgit v1.2.3 From ab0114fbaabd28d1e1a6961f6bfbd683f3e7fbbc Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 24 Apr 2017 18:46:34 +0200 Subject: Return salmon path for users, basic incoming salmon handling. --- lib/pleroma/web/activity_pub/activity_pub.ex | 42 ++++++++ lib/pleroma/web/ostatus/feed_representer.ex | 1 + lib/pleroma/web/ostatus/ostatus.ex | 134 +++++++++++++++++++++++++- lib/pleroma/web/ostatus/ostatus_controller.ex | 11 ++- lib/pleroma/web/router.ex | 1 + lib/pleroma/web/twitter_api/twitter_api.ex | 65 ++++++------- lib/pleroma/web/web_finger/web_finger.ex | 3 +- 7 files changed, 218 insertions(+), 39 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index e9f0dcd32..7264123d8 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -19,6 +19,48 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do Repo.insert(%Activity{data: map}) end + def create(to, actor, context, object, additional \\ %{}, published \\ nil) do + published = published || make_date() + + activity = %{ + "type" => "Create", + "to" => to, + "actor" => actor.ap_id, + "object" => object, + "published" => published, + "context" => context + } + |> Map.merge(additional) + + with {:ok, activity} <- insert(activity) do + {:ok, activity} = add_conversation_id(activity) + + if actor.local do + Pleroma.Web.Websub.publish(Pleroma.Web.OStatus.feed_path(actor), actor, activity) + end + + {:ok, activity} + end + end + + defp add_conversation_id(activity) do + if is_integer(activity.data["statusnetConversationId"]) do + {:ok, activity} + else + data = activity.data + |> put_in(["object", "statusnetConversationId"], activity.id) + |> put_in(["statusnetConversationId"], activity.id) + + object = Object.get_by_ap_id(activity.data["object"]["id"]) + + changeset = Ecto.Changeset.change(object, data: data["object"]) + Repo.update(changeset) + + changeset = Ecto.Changeset.change(activity, data: data) + Repo.update(changeset) + end + end + def like(%User{ap_id: ap_id} = user, %Object{data: %{ "id" => id}} = object) do cond do # There's already a like here, so return the original activity. diff --git a/lib/pleroma/web/ostatus/feed_representer.ex b/lib/pleroma/web/ostatus/feed_representer.ex index 14ac3ebf4..2cc0da9ba 100644 --- a/lib/pleroma/web/ostatus/feed_representer.ex +++ b/lib/pleroma/web/ostatus/feed_representer.ex @@ -23,6 +23,7 @@ defmodule Pleroma.Web.OStatus.FeedRepresenter do {:title, ['#{user.nickname}\'s timeline']}, {:updated, h.(most_recent_update)}, {:link, [rel: 'hub', href: h.(OStatus.pubsub_path(user))], []}, + {:link, [rel: 'salmon', href: h.(OStatus.salmon_path(user))], []}, {:link, [rel: 'self', href: h.(OStatus.feed_path(user))], []}, {:author, UserRepresenter.to_simple_form(user)}, ] ++ entries diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index d21b9078f..4fd649c92 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -1,5 +1,9 @@ defmodule Pleroma.Web.OStatus do - alias Pleroma.Web + import Ecto.Query + require Logger + + alias Pleroma.{Repo, User, Web} + alias Pleroma.Web.ActivityPub.ActivityPub def feed_path(user) do "#{user.ap_id}/feed.atom" @@ -9,6 +13,132 @@ defmodule Pleroma.Web.OStatus do "#{Web.base_url}/push/hub/#{user.nickname}" end - def user_path(user) do + def salmon_path(user) do + "#{user.ap_id}/salmon" + end + + def handle_incoming(xml_string) do + {doc, _rest} = :xmerl_scan.string(to_charlist(xml_string)) + + {:xmlObj, :string, object_type } = :xmerl_xpath.string('string(/entry/activity:object-type[1])', doc) + + case object_type do + 'http://activitystrea.ms/schema/1.0/note' -> + handle_note(doc) + _ -> + Logger.error("Couldn't parse incoming document") + end + end + + # TODO + # Parse mention + # wire up replies + # Set correct context + # Set correct statusnet ids. + 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) + + context = ActivityPub.generate_context_id + + to = [ + "https://www.w3.org/ns/activitystreams#Public" + ] + + date = string_from_xpath("/entry/published", doc) + + object = %{ + "type" => "Note", + "to" => to, + "content" => content_html, + "published" => date, + "context" => context, + "actor" => actor.ap_id + } + + ActivityPub.create(to, actor, context, object, %{}, date) + end + + def find_or_make(author, doc) do + query = from user in User, + where: user.local == false and fragment("? @> ?", user.info, ^%{ostatus_uri: author}) + + user = Repo.one(query) + + if is_nil(user) do + make_user(doc) + else + {:ok, user} + end + end + + def find_or_make_user(author_doc) do + {:xmlObj, :string, uri } = :xmerl_xpath.string('string(/author[1]/uri)', author_doc) + + query = from user in User, + where: user.local == false and fragment("? @> ?", user.info, ^%{ostatus_uri: to_string(uri)}) + + user = Repo.one(query) + + if is_nil(user) do + make_user(author_doc) + else + {:ok, user} + end + end + + defp string_from_xpath(xpath, doc) do + {:xmlObj, :string, res} = :xmerl_xpath.string('string(#{xpath})', doc) + + res = res + |> to_string + |> String.trim + + if res == "", do: nil, else: res + 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)) + end + + # TODO: Just takes the first one for now. + defp make_avatar_object(author_doc) do + href = string_from_xpath("/author[1]/link[@rel=\"avatar\"]/@href", author_doc) + type = string_from_xpath("/author[1]/link[@rel=\"avatar\"]/@type", author_doc) + + if href do + %{ + "type" => "Image", + "url" => + [%{ + "type" => "Link", + "mediaType" => type, + "href" => href + }] + } + else + nil + end end end diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 3c8d8c0f1..4174db786 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -25,7 +25,14 @@ defmodule Pleroma.Web.OStatus.OStatusController do |> send_resp(200, response) end - def temp(conn, params) do - IO.inspect(params) + def salmon_incoming(conn, params) do + {:ok, body, _conn} = read_body(conn) + magic_key = Pleroma.Web.Salmon.fetch_magic_key(body) + {:ok, doc} = Pleroma.Web.Salmon.decode_and_validate(magic_key, body) + + Pleroma.Web.OStatus.handle_incoming(doc) + + conn + |> send_resp(200, "") end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index a4f13c879..c98eac688 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -74,6 +74,7 @@ defmodule Pleroma.Web.Router do pipe_through :ostatus get "/users/:nickname/feed", OStatus.OStatusController, :feed + post "/users/:nickname/salmon", OStatus.OStatusController, :salmon_incoming post "/push/hub/:nickname", Websub.WebsubController, :websub_subscription_request end diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 0f84cffbd..9049b4efc 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -28,11 +28,33 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do date = make_date() - activity = %{ - "type" => "Create", - "to" => to, - "actor" => user.ap_id, - "object" => %{ + # Wire up reply info. + [to, context, object, additional] = + with inReplyToId when not is_nil(inReplyToId) <- data["in_reply_to_status_id"], + inReplyTo <- Repo.get(Activity, inReplyToId), + context <- inReplyTo.data["context"] + do + to = to ++ [inReplyTo.data["actor"]] + + object = %{ + "type" => "Note", + "to" => to, + "content" => content_html, + "published" => date, + "context" => context, + "attachment" => attachments, + "actor" => user.ap_id, + "inReplyTo" => inReplyTo.data["object"]["id"], + "inReplyToStatusId" => inReplyToId, + "statusnetConversationId" => inReplyTo.data["statusnetConversationId"] + } + additional = %{ + "statusnetConversationId" => inReplyTo.data["statusnetConversationId"] + } + + [to, context, object, additional] + else _e -> + object = %{ "type" => "Note", "to" => to, "content" => content_html, @@ -40,36 +62,11 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do "context" => context, "attachment" => attachments, "actor" => user.ap_id - }, - "published" => date, - "context" => context - } - - # Wire up reply info. - activity = with inReplyToId when not is_nil(inReplyToId) <- data["in_reply_to_status_id"], - inReplyTo <- Repo.get(Activity, inReplyToId), - context <- inReplyTo.data["context"] - do - - to = activity["to"] ++ [inReplyTo.data["actor"]] - - activity - |> put_in(["to"], to) - |> put_in(["context"], context) - |> put_in(["object", "context"], context) - |> put_in(["object", "inReplyTo"], inReplyTo.data["object"]["id"]) - |> put_in(["object", "inReplyToStatusId"], inReplyToId) - |> put_in(["statusnetConversationId"], inReplyTo.data["statusnetConversationId"]) - |> put_in(["object", "statusnetConversationId"], inReplyTo.data["statusnetConversationId"]) - else _e -> - activity - end - - with {:ok, activity} <- ActivityPub.insert(activity) do - {:ok, activity} = add_conversation_id(activity) - Pleroma.Web.Websub.publish(Pleroma.Web.OStatus.feed_path(user), user, activity) - {:ok, activity} + } + [to, context, object, %{}] end + + ActivityPub.create(to, user, context, object, additional, data) end def fetch_friend_statuses(user, opts \\ %{}) do diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index eb540e92a..18459e8f0 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -31,7 +31,8 @@ defmodule Pleroma.Web.WebFinger do [ {:Subject, "acct:#{user.nickname}@#{Pleroma.Web.host}"}, {:Alias, user.ap_id}, - {:Link, %{rel: "http://schemas.google.com/g/2010#updates-from", type: "application/atom+xml", href: OStatus.feed_path(user)}} + {:Link, %{rel: "http://schemas.google.com/g/2010#updates-from", type: "application/atom+xml", href: OStatus.feed_path(user)}}, + {:Link, %{rel: "salmon", href: OStatus.salmon_path(user)}} ] } |> XmlBuilder.to_doc -- cgit v1.2.3 From ef4190b3abbc581e9405f2a32fe7579345a3d155 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 25 Apr 2017 17:26:05 +0200 Subject: Clean up status create method. --- lib/pleroma/web/twitter_api/twitter_api.ex | 33 ++++++++++++++++++------------ 1 file changed, 20 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 9049b4efc..ad73e82ce 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -5,26 +5,33 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do import Ecto.Query - def create_status(user = %User{}, data = %{}) do - attachments = Enum.map(data["media_ids"] || [], fn (media_id) -> - Repo.get(Object, media_id).data - end) - - context = ActivityPub.generate_context_id - - content = HtmlSanitizeEx.strip_tags(data["status"]) - |> String.replace("\n", "
") - - mentions = parse_mentions(content) - + def to_for_user_and_mentions(user, mentions) do default_to = [ User.ap_followers(user), "https://www.w3.org/ns/activitystreams#Public" ] to = default_to ++ Enum.map(mentions, fn ({_, %{ap_id: ap_id}}) -> ap_id end) + end - content_html = add_user_links(content, mentions) + def format_input(text, mentions) do + content = HtmlSanitizeEx.strip_tags(text) + |> String.replace("\n", "
") + |> add_user_links(mentions) + end + + def attachments_from_ids(ids) do + Enum.map(ids || [], fn (media_id) -> + Repo.get(Object, media_id).data + end) + end + + def create_status(user = %User{}, data = %{"status" => status}) do + attachments = attachments_from_ids(data["media_ids"]) + context = ActivityPub.generate_context_id + mentions = parse_mentions(status) + content_html = format_input(status, mentions) + to = to_for_user_and_mentions(user, mentions) date = make_date() -- cgit v1.2.3 From 4771962a5d0749746b7bb921074b97e13348dedf Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 25 Apr 2017 17:32:36 +0200 Subject: More refactoring. --- lib/pleroma/web/twitter_api/twitter_api.ex | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index ad73e82ce..ad4bf7153 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -26,21 +26,26 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do end) end + def get_replied_to_activity(id) when not is_nil(id) do + Repo.get(Activity, id) + end + + def get_replied_to_activity(_), do: nil + def create_status(user = %User{}, data = %{"status" => status}) do attachments = attachments_from_ids(data["media_ids"]) context = ActivityPub.generate_context_id mentions = parse_mentions(status) content_html = format_input(status, mentions) to = to_for_user_and_mentions(user, mentions) - date = make_date() + inReplyTo = get_replied_to_activity(data["in_reply_to_status_id"]) + # Wire up reply info. [to, context, object, additional] = - with inReplyToId when not is_nil(inReplyToId) <- data["in_reply_to_status_id"], - inReplyTo <- Repo.get(Activity, inReplyToId), - context <- inReplyTo.data["context"] - do + if inReplyTo do + context = inReplyTo.data["context"] to = to ++ [inReplyTo.data["actor"]] object = %{ @@ -52,7 +57,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do "attachment" => attachments, "actor" => user.ap_id, "inReplyTo" => inReplyTo.data["object"]["id"], - "inReplyToStatusId" => inReplyToId, + "inReplyToStatusId" => inReplyTo.id, "statusnetConversationId" => inReplyTo.data["statusnetConversationId"] } additional = %{ @@ -60,7 +65,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do } [to, context, object, additional] - else _e -> + else object = %{ "type" => "Note", "to" => to, -- cgit v1.2.3 From 6c5f5e18ec1103a9d10d88081a27c2ae9dba4f41 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 25 Apr 2017 17:35:21 +0200 Subject: Even more refactoring. --- lib/pleroma/web/twitter_api/twitter_api.ex | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index ad4bf7153..cb48c7f5f 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -11,11 +11,11 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do "https://www.w3.org/ns/activitystreams#Public" ] - to = default_to ++ Enum.map(mentions, fn ({_, %{ap_id: ap_id}}) -> ap_id end) + default_to ++ Enum.map(mentions, fn ({_, %{ap_id: ap_id}}) -> ap_id end) end def format_input(text, mentions) do - content = HtmlSanitizeEx.strip_tags(text) + HtmlSanitizeEx.strip_tags(text) |> String.replace("\n", "
") |> add_user_links(mentions) end @@ -235,24 +235,6 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do Enum.reduce(mentions, text, fn ({match, %User{ap_id: ap_id}}, text) -> String.replace(text, match, "#{match}") end) end - defp add_conversation_id(activity) do - if is_integer(activity.data["statusnetConversationId"]) do - {:ok, activity} - else - data = activity.data - |> put_in(["object", "statusnetConversationId"], activity.id) - |> put_in(["statusnetConversationId"], activity.id) - - object = Object.get_by_ap_id(activity.data["object"]["id"]) - - changeset = Ecto.Changeset.change(object, data: data["object"]) - Repo.update(changeset) - - changeset = Ecto.Changeset.change(activity, data: data) - Repo.update(changeset) - end - end - def register_user(params) do params = %{ nickname: params["nickname"], -- cgit v1.2.3 From b438ea24ee936ae10efdcd3c9079e3b45ae521f4 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 25 Apr 2017 17:45:34 +0200 Subject: Add ostatus conversation as context. --- lib/pleroma/web/ostatus/ostatus.ex | 7 ++++++- lib/pleroma/web/twitter_api/twitter_api.ex | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 4fd649c92..8c31ce5aa 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -41,7 +41,12 @@ defmodule Pleroma.Web.OStatus do [author] = :xmerl_xpath.string('/entry/author[1]', doc) {:ok, actor} = find_or_make_user(author) - context = ActivityPub.generate_context_id + context = string_from_xpath("/entry/ostatus:conversation[1]", doc) |> String.trim + context = if String.length(context) > 0 do + context + else + ActivityPub.generate_context_id + end to = [ "https://www.w3.org/ns/activitystreams#Public" diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index cb48c7f5f..e4e26df15 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -253,7 +253,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do {:error, changeset} -> errors = Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end) |> Poison.encode! - {:error, %{error: errors}} + {:error, %{error: errors}} end end -- cgit v1.2.3 From f980f6778b1447b808299fa9274854bb25f9823b Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 25 Apr 2017 18:03:14 +0200 Subject: Wire up mentions. --- lib/pleroma/web/ostatus/ostatus.ex | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 8c31ce5aa..65141f826 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -31,10 +31,7 @@ defmodule Pleroma.Web.OStatus do end # TODO - # Parse mention # wire up replies - # Set correct context - # Set correct statusnet ids. def handle_note(doc) do content_html = string_from_xpath("/entry/content[1]", doc) @@ -52,6 +49,11 @@ defmodule Pleroma.Web.OStatus do "https://www.w3.org/ns/activitystreams#Public" ] + mentions = :xmerl_xpath.string('/entry/link[@rel="mentioned" and @ostatus:object-type="http://activitystrea.ms/schema/1.0/person"]', doc) + |> Enum.map(fn(person) -> string_from_xpath("@href", person) end) + + to = to ++ mentions + date = string_from_xpath("/entry/published", doc) object = %{ @@ -66,19 +68,6 @@ defmodule Pleroma.Web.OStatus do ActivityPub.create(to, actor, context, object, %{}, date) end - def find_or_make(author, doc) do - query = from user in User, - where: user.local == false and fragment("? @> ?", user.info, ^%{ostatus_uri: author}) - - user = Repo.one(query) - - if is_nil(user) do - make_user(doc) - else - {:ok, user} - end - end - def find_or_make_user(author_doc) do {:xmlObj, :string, uri } = :xmerl_xpath.string('string(/author[1]/uri)', author_doc) -- cgit v1.2.3 From b91ccef2371fb0bbc23638b174e815dd7189482e Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Wed, 26 Apr 2017 08:47:22 +0200 Subject: Output conversation id. --- lib/pleroma/web/ostatus/activity_representer.ex | 4 +++- lib/pleroma/web/ostatus/feed_representer.ex | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex index 590abc8bb..367212fe1 100644 --- a/lib/pleroma/web/ostatus/activity_representer.ex +++ b/lib/pleroma/web/ostatus/activity_representer.ex @@ -19,7 +19,9 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do {:title, ['New note by #{user.nickname}']}, {:content, [type: 'html'], h.(activity.data["object"]["content"])}, {:published, h.(inserted_at)}, - {:updated, h.(updated_at)} + {:updated, h.(updated_at)}, + {:"ostatus:conversation", [], h.(activity.data["context"])}, + {:link, [href: h.(activity.data["context"]), rel: 'ostatus:conversation'], []} ] ++ attachments end diff --git a/lib/pleroma/web/ostatus/feed_representer.ex b/lib/pleroma/web/ostatus/feed_representer.ex index 2cc0da9ba..10a1ffb25 100644 --- a/lib/pleroma/web/ostatus/feed_representer.ex +++ b/lib/pleroma/web/ostatus/feed_representer.ex @@ -17,7 +17,8 @@ defmodule Pleroma.Web.OStatus.FeedRepresenter do :feed, [ xmlns: 'http://www.w3.org/2005/Atom', "xmlns:activity": 'http://activitystrea.ms/spec/1.0/', - "xmlns:poco": 'http://portablecontacts.net/spec/1.0' + "xmlns:poco": 'http://portablecontacts.net/spec/1.0', + "xmlns:ostatus": 'http://ostatus.org/schema/1.0' ], [ {:id, h.(OStatus.feed_path(user))}, {:title, ['#{user.nickname}\'s timeline']}, -- cgit v1.2.3 From d9ebd785ab7d9b371ba5accdc6ca5d72af7b509d Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Wed, 26 Apr 2017 10:08:13 +0200 Subject: Ostatus doesn't distinguish between activities / objects on create. --- lib/pleroma/web/ostatus/activity_representer.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex index 367212fe1..30e695bcc 100644 --- a/lib/pleroma/web/ostatus/activity_representer.ex +++ b/lib/pleroma/web/ostatus/activity_representer.ex @@ -15,7 +15,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do [ {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/note']}, {:"activity:verb", ['http://activitystrea.ms/schema/1.0/post']}, - {:id, h.(activity.data["object"]["id"])}, + {:id, h.(activity.data["id"])}, {:title, ['New note by #{user.nickname}']}, {:content, [type: 'html'], h.(activity.data["object"]["content"])}, {:published, h.(inserted_at)}, -- cgit v1.2.3 From f1ebf812eede5b77931d2315757a7ad8e0ea5a7e Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Wed, 26 Apr 2017 10:22:51 +0200 Subject: Add inReplyTo to incoming messages. --- lib/pleroma/web/ostatus/ostatus.ex | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 65141f826..5b68f057e 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -65,6 +65,14 @@ defmodule Pleroma.Web.OStatus do "actor" => actor.ap_id } + inReplyTo = string_from_xpath("/entry/thr:in-reply-to[1]/@href", doc) + + object = if inReplyTo do + Map.put(object, "inReplyTo", inReplyTo) + else + object + end + ActivityPub.create(to, actor, context, object, %{}, date) end -- cgit v1.2.3 From 57bd59e4071adf847f94229479e5ffa0951721fd Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Wed, 26 Apr 2017 14:25:44 +0200 Subject: Salmon creation. --- lib/pleroma/web/salmon/salmon.ex | 56 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex index 3881f2758..24b5eb0d9 100644 --- a/lib/pleroma/web/salmon/salmon.ex +++ b/lib/pleroma/web/salmon/salmon.ex @@ -57,7 +57,7 @@ defmodule Pleroma.Web.Salmon do end end - defp decode_key("RSA." <> magickey) do + def decode_key("RSA." <> magickey) do make_integer = fn(bin) -> list = :erlang.binary_to_list(bin) Enum.reduce(list, 0, fn (el, acc) -> (acc <<< 8) ||| el end) @@ -70,4 +70,58 @@ defmodule Pleroma.Web.Salmon do {:RSAPublicKey, modulus, exponent} end + + def encode_key({:RSAPublicKey, modulus, exponent}) do + modulus_enc = :binary.encode_unsigned(modulus) |> Base.url_encode64 + exponent_enc = :binary.encode_unsigned(exponent) |> Base.url_encode64 + + "RSA.#{modulus_enc}.#{exponent_enc}" + end + + def generate_rsa_pem do + port = Port.open({:spawn, "openssl genrsa"}, [:binary]) + {:ok, pem} = receive do + {^port, {:data, pem}} -> {:ok, pem} + end + Port.close(port) + if Regex.match?(~r/RSA PRIVATE KEY/, pem) do + {:ok, pem} + else + :error + end + end + + def keys_from_pem(pem) do + [private_key_code] = :public_key.pem_decode(pem) + private_key = :public_key.pem_entry_decode(private_key_code) + {:RSAPrivateKey, _, modulus, exponent, _, _, _, _, _, _, _} = private_key + public_key = {:RSAPublicKey, modulus, exponent} + {:ok, private_key, public_key} + end + + def encode(private_key, doc) do + type = "application/atom+xml" + encoding = "base64url" + alg = "RSA-SHA256" + + signed_text = [doc, type, encoding, alg] + |> Enum.map(&Base.url_encode64/1) + |> Enum.join(".") + + signature = :public_key.sign(signed_text, :sha256, private_key) |> to_string |> Base.url_encode64 + doc_base64= doc |> Base.url_encode64 + + # Don't need proper xml building, these strings are safe to leave unescaped + salmon = """ + + + #{doc_base64} + #{encoding} + #{alg} + #{signature} + + """ + + {:ok, salmon} + end end -- cgit v1.2.3 From c5fa682c317717c64168bf2d77b28d805ffff450 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Wed, 26 Apr 2017 18:33:10 +0200 Subject: Refactor, add beginnings of websub client subscriptions. --- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- lib/pleroma/web/federator/federator.ex | 32 ++++++++++++++++++++++ lib/pleroma/web/websub/websub.ex | 26 ++++++++++++++---- .../web/websub/websub_client_subscription.ex | 13 +++++++++ 4 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 lib/pleroma/web/federator/federator.ex create mode 100644 lib/pleroma/web/websub/websub_client_subscription.ex (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 7264123d8..82f9fcc1c 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -36,7 +36,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do {:ok, activity} = add_conversation_id(activity) if actor.local do - Pleroma.Web.Websub.publish(Pleroma.Web.OStatus.feed_path(actor), actor, activity) + Pleroma.Web.Federator.enqueue(:publish, activity) end {:ok, activity} diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex new file mode 100644 index 000000000..f489ed837 --- /dev/null +++ b/lib/pleroma/web/federator/federator.ex @@ -0,0 +1,32 @@ +defmodule Pleroma.Web.Federator do + alias Pleroma.User + require Logger + + @websub_verifier Application.get_env(:pleroma, :websub_verifier) + + def handle(:publish, activity) do + Logger.debug("Running publish for #{activity.data["id"]}") + with actor when not is_nil(actor) <- User.get_cached_by_ap_id(activity.data["actor"]) do + Pleroma.Web.Websub.publish(Pleroma.Web.OStatus.feed_path(actor), actor, activity) + end + end + + def handle(:verify_websub, websub) do + Logger.debug("Running websub verification for #{websub.id} (#{websub.topic}, #{websub.callback})") + @websub_verifier.verify(websub) + end + + def handle(type, payload) do + Logger.debug("Unknown task: #{type}") + {:error, "Don't know what do do with this"} + end + + def enqueue(type, payload) do + # for now, just run immediately in a new process. + if Mix.env == :test do + handle(type, payload) + else + spawn(fn -> handle(type, payload) end) + end + end +end diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index cc66b52dd..03b0aec8f 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -1,13 +1,11 @@ defmodule Pleroma.Web.Websub do alias Pleroma.Repo - alias Pleroma.Web.Websub.WebsubServerSubscription + alias Pleroma.Web.Websub.{WebsubServerSubscription, WebsubClientSubscription} alias Pleroma.Web.OStatus.FeedRepresenter alias Pleroma.Web.OStatus import Ecto.Query - @websub_verifier Application.get_env(:pleroma, :websub_verifier) - def verify(subscription, getter \\ &HTTPoison.get/3 ) do challenge = Base.encode16(:crypto.strong_rand_bytes(8)) lease_seconds = NaiveDateTime.diff(subscription.valid_until, subscription.updated_at) |> to_string @@ -71,8 +69,7 @@ defmodule Pleroma.Web.Websub do change = Ecto.Changeset.change(websub, %{valid_until: NaiveDateTime.add(websub.updated_at, lease_time)}) websub = Repo.update!(change) - # Just spawn that for now, maybe pool later. - spawn(fn -> @websub_verifier.verify(websub) end) + Pleroma.Web.Federator.enqueue(:verify_websub, websub) {:ok, websub} else {:error, reason} -> @@ -99,4 +96,23 @@ defmodule Pleroma.Web.Websub do {:error, "Wrong topic requested, expected #{OStatus.feed_path(user)}, got #{topic}"} end end + + def subscribe(user, topic) do + # 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 + change = Ecto.Changeset.change(subscription, %{subscribers: subscribers}) + Repo.update(change) + else _e -> + subscription = %WebsubClientSubscription{ + topic: topic, + subscribers: [user.ap_id], + state: "requested", + secret: :crypto.strong_rand_bytes(8) |> Base.url_encode64 + } + Repo.insert(subscription) + end + + {:ok, subscription} + end end diff --git a/lib/pleroma/web/websub/websub_client_subscription.ex b/lib/pleroma/web/websub/websub_client_subscription.ex new file mode 100644 index 000000000..341e27c51 --- /dev/null +++ b/lib/pleroma/web/websub/websub_client_subscription.ex @@ -0,0 +1,13 @@ +defmodule Pleroma.Web.Websub.WebsubClientSubscription do + use Ecto.Schema + + schema "websub_client_subscriptions" do + field :topic, :string + field :secret, :string + field :valid_until, :naive_datetime + field :state, :string + field :subscribers, {:array, :string}, default: [] + + timestamps() + end +end -- cgit v1.2.3 From d1dce56a85e041f78e1d50900a0c9591610de2b9 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Thu, 27 Apr 2017 09:43:58 +0200 Subject: Refactor XML parsing. --- lib/pleroma/web/ostatus/ostatus.ex | 13 ++----------- lib/pleroma/web/salmon/salmon.ex | 8 +++++--- lib/pleroma/web/websub/websub.ex | 1 + lib/pleroma/web/xml/xml.ex | 19 +++++++++++++++++++ 4 files changed, 27 insertions(+), 14 deletions(-) create mode 100644 lib/pleroma/web/xml/xml.ex (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 5b68f057e..89b482592 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -1,5 +1,6 @@ defmodule Pleroma.Web.OStatus do import Ecto.Query + import Pleroma.Web.XML require Logger alias Pleroma.{Repo, User, Web} @@ -18,7 +19,7 @@ defmodule Pleroma.Web.OStatus do end def handle_incoming(xml_string) do - {doc, _rest} = :xmerl_scan.string(to_charlist(xml_string)) + doc = parse_document(xml_string) {:xmlObj, :string, object_type } = :xmerl_xpath.string('string(/entry/activity:object-type[1])', doc) @@ -91,16 +92,6 @@ defmodule Pleroma.Web.OStatus do end end - defp string_from_xpath(xpath, doc) do - {:xmlObj, :string, res} = :xmerl_xpath.string('string(#{xpath})', doc) - - res = res - |> to_string - |> String.trim - - if res == "", do: nil, else: res - 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) diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex index 24b5eb0d9..99cca1f55 100644 --- a/lib/pleroma/web/salmon/salmon.ex +++ b/lib/pleroma/web/salmon/salmon.ex @@ -1,8 +1,9 @@ defmodule Pleroma.Web.Salmon do use Bitwise + alias Pleroma.Web.XML def decode(salmon) do - {doc, _rest} = :xmerl_scan.string(to_charlist(salmon)) + doc = XML.parse_document(salmon) {:xmlObj, :string, data} = :xmerl_xpath.string('string(//me:data[1])', doc) {:xmlObj, :string, sig} = :xmerl_xpath.string('string(//me:sig[1])', doc) @@ -22,16 +23,17 @@ defmodule Pleroma.Web.Salmon do def fetch_magic_key(salmon) do [data, _, _, _, _] = decode(salmon) - {doc, _rest} = :xmerl_scan.string(to_charlist(data)) + doc = XML.parse_document(data) {:xmlObj, :string, uri} = :xmerl_xpath.string('string(//author[1]/uri)', doc) uri = to_string(uri) base = URI.parse(uri).host # TODO: Find out if this endpoint is mandated by the standard. + # At least diaspora does it differently {:ok, response} = HTTPoison.get(base <> "/.well-known/webfinger", ["Accept": "application/xrd+xml"], [params: [resource: uri]]) - {doc, _rest} = :xmerl_scan.string(to_charlist(response.body)) + doc = XML.parse_document(response.body) {:xmlObj, :string, magickey} = :xmerl_xpath.string('string(//Link[@rel="magic-public-key"]/@href)', doc) "data:application/magic-public-key," <> magickey = to_string(magickey) diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index 03b0aec8f..5372416e6 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -3,6 +3,7 @@ defmodule Pleroma.Web.Websub do alias Pleroma.Web.Websub.{WebsubServerSubscription, WebsubClientSubscription} alias Pleroma.Web.OStatus.FeedRepresenter alias Pleroma.Web.OStatus + alias Pleroma.Web.XML import Ecto.Query diff --git a/lib/pleroma/web/xml/xml.ex b/lib/pleroma/web/xml/xml.ex new file mode 100644 index 000000000..22faf72df --- /dev/null +++ b/lib/pleroma/web/xml/xml.ex @@ -0,0 +1,19 @@ +defmodule Pleroma.Web.XML do + def string_from_xpath(xpath, doc) do + {:xmlObj, :string, res} = :xmerl_xpath.string('string(#{xpath})', doc) + + res = res + |> to_string + |> String.trim + + if res == "", do: nil, else: res + end + + def parse_document(text) do + {doc, _rest} = text + |> :binary.bin_to_list + |> :xmerl_scan.string + + doc + end +end -- cgit v1.2.3 From e8a311ecffe1fb19a3d194b1c5628853263909a7 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Thu, 27 Apr 2017 09:44:20 +0200 Subject: Add user and hub to websub client subscriptions. --- lib/pleroma/web/websub/websub_client_subscription.ex | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/websub/websub_client_subscription.ex b/lib/pleroma/web/websub/websub_client_subscription.ex index 341e27c51..c7a25ea22 100644 --- a/lib/pleroma/web/websub/websub_client_subscription.ex +++ b/lib/pleroma/web/websub/websub_client_subscription.ex @@ -1,5 +1,6 @@ defmodule Pleroma.Web.Websub.WebsubClientSubscription do use Ecto.Schema + alias Pleroma.User schema "websub_client_subscriptions" do field :topic, :string @@ -7,6 +8,8 @@ defmodule Pleroma.Web.Websub.WebsubClientSubscription do field :valid_until, :naive_datetime field :state, :string field :subscribers, {:array, :string}, default: [] + field :hub, :string + belongs_to :user, User timestamps() end -- cgit v1.2.3 From 90da25505f9cfbd16a9088e20714b24c2c6fa215 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Thu, 27 Apr 2017 09:46:45 +0200 Subject: Add discovery and subscription requests to websub. --- lib/pleroma/web/websub/websub.ex | 58 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index 5372416e6..4a35ca8fc 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.Websub do alias Pleroma.Web.OStatus.FeedRepresenter alias Pleroma.Web.OStatus alias Pleroma.Web.XML + require Logger import Ecto.Query @@ -98,8 +99,8 @@ defmodule Pleroma.Web.Websub do end end - def subscribe(user, topic) do - # Race condition, use transactions + def subscribe(user, topic, requester \\ &request_subscription/1) do + # 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 change = Ecto.Changeset.change(subscription, %{subscribers: subscribers}) @@ -109,11 +110,60 @@ defmodule Pleroma.Web.Websub do topic: topic, subscribers: [user.ap_id], state: "requested", - secret: :crypto.strong_rand_bytes(8) |> Base.url_encode64 + secret: :crypto.strong_rand_bytes(8) |> Base.url_encode64, + user: user } Repo.insert(subscription) end + requester.(subscription) + end + + def discover(topic, getter \\ &HTTPoison.get/1) do + with {:ok, response} <- getter.(topic), + status_code when status_code in 200..299 <- response.status_code, + body <- response.body, + doc <- XML.parse_document(body), + url when not is_nil(url) <- XML.string_from_xpath(~S{/feed/link[@rel="self"]/@href}, doc), + hub when not is_nil(hub) <- XML.string_from_xpath(~S{/feed/link[@rel="hub"]/@href}, doc) do + {:ok, %{url: url, hub: hub}} + else e -> + {:error, e} + end + end + + def request_subscription(websub, poster \\ &HTTPoison.post/3, timeout \\ 10_000) do + data = [ + "hub.mode": "subscribe", + "hub.topic": websub.topic, + "hub.secret": websub.secret, + "hub.callback": "https://social.heldscal.la/callback" + ] + + # This checks once a second if we are confirmed yet + websub_checker = fn -> + helper = fn (helper) -> + :timer.sleep(1000) + websub = Repo.get_by(WebsubClientSubscription, id: websub.id, state: "accepted") + if websub, do: websub, else: helper.(helper) + end + helper.(helper) + end - {:ok, subscription} + task = Task.async(websub_checker) + + with {:ok, %{status_code: 202}} <- poster.(websub.hub, {:form, data}, ["Content-type": "application/x-www-form-urlencoded"]), + {:ok, websub} <- Task.yield(task, timeout) do + {:ok, websub} + else e -> + Task.shutdown(task) + + change = Ecto.Changeset.change(websub, %{state: "rejected"}) + {:ok, websub} = Repo.update(change) + + Logger.debug("Couldn't confirm subscription: #{inspect(websub)}") + Logger.debug("error: #{inspect(e)}") + + {:error, websub} + end end end -- cgit v1.2.3 From 451d18af63fcf97f0d9621e5bfe296e1f18a0312 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Fri, 28 Apr 2017 09:51:47 +0200 Subject: Add proper callback route for websub confirmation. --- lib/pleroma/web/router.ex | 1 + lib/pleroma/web/websub/websub.ex | 6 +++--- lib/pleroma/web/websub/websub_controller.ex | 5 +++++ 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index c98eac688..bff981f9f 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -75,6 +75,7 @@ defmodule Pleroma.Web.Router do get "/users/:nickname/feed", OStatus.OStatusController, :feed post "/users/:nickname/salmon", OStatus.OStatusController, :salmon_incoming + post "/push/subscriptions/:id", Websub.WebsubController, :websub_subscription_confirmation post "/push/hub/:nickname", Websub.WebsubController, :websub_subscription_request end diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index 4a35ca8fc..ad352ee26 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -2,8 +2,8 @@ defmodule Pleroma.Web.Websub do alias Pleroma.Repo alias Pleroma.Web.Websub.{WebsubServerSubscription, WebsubClientSubscription} alias Pleroma.Web.OStatus.FeedRepresenter - alias Pleroma.Web.OStatus - alias Pleroma.Web.XML + alias Pleroma.Web.{XML, Endpoint, OStatus} + alias Pleroma.Web.Router.Helpers require Logger import Ecto.Query @@ -136,7 +136,7 @@ defmodule Pleroma.Web.Websub do "hub.mode": "subscribe", "hub.topic": websub.topic, "hub.secret": websub.secret, - "hub.callback": "https://social.heldscal.la/callback" + "hub.callback": Helpers.websub_url(Endpoint, :websub_subscription_confirmation, websub.id) ] # This checks once a second if we are confirmed yet diff --git a/lib/pleroma/web/websub/websub_controller.ex b/lib/pleroma/web/websub/websub_controller.ex index 5d54c6ef5..c6b15c0c2 100644 --- a/lib/pleroma/web/websub/websub_controller.ex +++ b/lib/pleroma/web/websub/websub_controller.ex @@ -15,4 +15,9 @@ defmodule Pleroma.Web.Websub.WebsubController do |> send_resp(500, reason) end end + + def websub_subscription_confirmation(conn, params) do + IO.inspect(params) + conn + end end -- cgit v1.2.3 From 1422e7aa84a897c6026e9dcd26b7d5955050687a Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Fri, 28 Apr 2017 15:45:10 +0200 Subject: Handle incoming websub subscriptions. --- lib/pleroma/web/federator/federator.ex | 4 ++-- lib/pleroma/web/router.ex | 3 ++- lib/pleroma/web/websub/websub.ex | 7 ++++-- lib/pleroma/web/websub/websub_controller.ex | 34 +++++++++++++++++++++++++---- 4 files changed, 39 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index f489ed837..38df13540 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -2,7 +2,7 @@ defmodule Pleroma.Web.Federator do alias Pleroma.User require Logger - @websub_verifier Application.get_env(:pleroma, :websub_verifier) + @websub Application.get_env(:pleroma, :websub) def handle(:publish, activity) do Logger.debug("Running publish for #{activity.data["id"]}") @@ -13,7 +13,7 @@ defmodule Pleroma.Web.Federator do def handle(:verify_websub, websub) do Logger.debug("Running websub verification for #{websub.id} (#{websub.topic}, #{websub.callback})") - @websub_verifier.verify(websub) + @websub.verify(websub) end def handle(type, payload) do diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index bff981f9f..2ff75ec5d 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -75,8 +75,9 @@ defmodule Pleroma.Web.Router do get "/users/:nickname/feed", OStatus.OStatusController, :feed post "/users/:nickname/salmon", OStatus.OStatusController, :salmon_incoming - post "/push/subscriptions/:id", Websub.WebsubController, :websub_subscription_confirmation post "/push/hub/:nickname", Websub.WebsubController, :websub_subscription_request + get "/push/subscriptions/:id", Websub.WebsubController, :websub_subscription_confirmation + post "/push/subscriptions/:id", Websub.WebsubController, :websub_incoming end scope "/.well-known", Pleroma.Web do diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index ad352ee26..ad9e47b46 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -42,8 +42,7 @@ defmodule Pleroma.Web.Websub do response = FeedRepresenter.to_simple_form(user, [activity], [user]) |> :xmerl.export_simple(:xmerl_xml) - signature = :crypto.hmac(:sha, sub.secret, response) |> Base.encode16 - + signature = sign(sub.secret, response) HTTPoison.post(sub.callback, response, [ {"Content-Type", "application/atom+xml"}, {"X-Hub-Signature", "sha1=#{signature}"} @@ -51,6 +50,10 @@ defmodule Pleroma.Web.Websub do end) end + def sign(secret, doc) do + :crypto.hmac(:sha, secret, doc) |> Base.encode16 + end + def incoming_subscription_request(user, %{"hub.mode" => "subscribe"} = params) do with {:ok, topic} <- valid_topic(params, user), {:ok, lease_time} <- lease_time(params), diff --git a/lib/pleroma/web/websub/websub_controller.ex b/lib/pleroma/web/websub/websub_controller.ex index c6b15c0c2..cd59a70a3 100644 --- a/lib/pleroma/web/websub/websub_controller.ex +++ b/lib/pleroma/web/websub/websub_controller.ex @@ -1,7 +1,11 @@ defmodule Pleroma.Web.Websub.WebsubController do use Pleroma.Web, :controller - alias Pleroma.User + alias Pleroma.{Repo, User} alias Pleroma.Web.Websub + alias Pleroma.Web.Websub.WebsubClientSubscription + require Logger + + @ostatus Application.get_env(:pleroma, :ostatus) def websub_subscription_request(conn, %{"nickname" => nickname} = params) do user = User.get_cached_by_nickname(nickname) @@ -16,8 +20,30 @@ defmodule Pleroma.Web.Websub.WebsubController do end end - def websub_subscription_confirmation(conn, params) do - IO.inspect(params) - conn + def websub_subscription_confirmation(conn, %{"id" => id, "hub.mode" => "subscribe", "hub.challenge" => challenge, "hub.topic" => topic}) do + with %WebsubClientSubscription{} = websub <- Repo.get_by(WebsubClientSubscription, id: id, topic: topic) do + change = Ecto.Changeset.change(websub, %{state: "accepted"}) + {:ok, _websub} = Repo.update(change) + conn + |> send_resp(200, challenge) + else _e -> + conn + |> send_resp(500, "Error") + end + end + + def websub_incoming(conn, %{"id" => id}) do + with "sha1=" <> signature <- hd(get_req_header(conn, "x-hub-signature")), + %WebsubClientSubscription{} = websub <- Repo.get(WebsubClientSubscription, id), + {:ok, body, _conn} = read_body(conn), + ^signature <- Websub.sign(websub.secret, body) do + @ostatus.handle_incoming(body) + conn + |> send_resp(200, "OK") + else _e -> + Logger.debug("Can't handle incoming subscription post") + conn + |> send_resp(500, "Error") + end end end -- cgit v1.2.3 From 59d4cc60364fd1abf5cbc881e88757b378456b64 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Fri, 28 Apr 2017 15:53:45 +0200 Subject: normalize hex number. --- lib/pleroma/web/websub/websub_controller.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/web/websub/websub_controller.ex b/lib/pleroma/web/websub/websub_controller.ex index cd59a70a3..e5ecf6523 100644 --- a/lib/pleroma/web/websub/websub_controller.ex +++ b/lib/pleroma/web/websub/websub_controller.ex @@ -34,6 +34,7 @@ defmodule Pleroma.Web.Websub.WebsubController do def websub_incoming(conn, %{"id" => id}) do with "sha1=" <> signature <- hd(get_req_header(conn, "x-hub-signature")), + signature <- String.upcase(signature), %WebsubClientSubscription{} = websub <- Repo.get(WebsubClientSubscription, id), {:ok, body, _conn} = read_body(conn), ^signature <- Websub.sign(websub.secret, body) do -- cgit v1.2.3 From ca40dda04c114c32ca9ecfe5f998a083448a189c Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Fri, 28 Apr 2017 17:41:12 +0200 Subject: Add some basic webfingering. --- lib/pleroma/web/web_finger/web_finger.ex | 37 ++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index 18459e8f0..08ff6d278 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -2,6 +2,8 @@ defmodule Pleroma.Web.WebFinger do alias Pleroma.XmlBuilder alias Pleroma.User alias Pleroma.Web.OStatus + alias Pleroma.Web.XML + require Logger def host_meta() do base_url = Pleroma.Web.base_url @@ -37,4 +39,39 @@ defmodule Pleroma.Web.WebFinger do } |> XmlBuilder.to_doc end + + # FIXME: Make this call the host-meta to find the actual address. + defp webfinger_address(domain) do + "https://#{domain}/.well-known/webfinger" + end + + defp webfinger_from_xml(doc) do + magic_key = XML.string_from_xpath(~s{//Link[@rel="magic-public-key"]/@href}, doc) + "data:application/magic-public-key," <> magic_key = magic_key + topic = XML.string_from_xpath(~s{//Link[@rel="http://schemas.google.com/g/2010#updates-from"]/@href}, doc) + subject = XML.string_from_xpath("//Subject", doc) + salmon = XML.string_from_xpath(~s{//Link[@rel="salmon"]/@href}, doc) + data = %{ + magic_key: magic_key, + topic: topic, + subject: subject, + salmon: salmon + } + {:ok, data} + end + + def finger(account, getter \\ &HTTPoison.get/3) do + [name, domain] = String.split(account, "@") + 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]]), + doc <- XML.parse_document(body), + {:ok, data} <- webfinger_from_xml(doc) do + {:ok, data} + else + e -> + Logger.debug("Couldn't finger #{account}.") + Logger.debug(e) + {:error, e} + end + end end -- cgit v1.2.3 From 69922bc724736fb07bf36beaef42d944158d9269 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sat, 29 Apr 2017 17:51:59 +0200 Subject: Add user info gathering. --- lib/pleroma/web/ostatus/ostatus.ex | 11 +++++++++++ lib/pleroma/web/web_finger/web_finger.ex | 4 ++-- lib/pleroma/web/websub/websub.ex | 16 +++++++++++++--- 3 files changed, 26 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 89b482592..90be86755 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.OStatus do alias Pleroma.{Repo, User, Web} alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.{WebFinger, Websub} def feed_path(user) do "#{user.ap_id}/feed.atom" @@ -134,4 +135,14 @@ defmodule Pleroma.Web.OStatus do nil end end + + def gather_user_info(username) do + with {:ok, webfinger_data} <- WebFinger.finger(username), + {:ok, feed_data} <- Websub.gather_feed_data(webfinger_data.topic) do + {:ok, Map.merge(webfinger_data, feed_data) |> Map.put(:fqn, username)} + else e -> + Logger.debug("Couldn't gather info for #{username}") + {:error, e} + end + end end diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index 08ff6d278..1d8c4d0c8 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -18,7 +18,7 @@ defmodule Pleroma.Web.WebFinger do def webfinger(resource) do host = Pleroma.Web.host - regex = ~r/acct:(?\w+)@#{host}/ + regex = ~r/(acct:)?(?\w+)@#{host}/ case Regex.named_captures(regex, resource) do %{"username" => username} -> user = User.get_cached_by_nickname(username) @@ -70,7 +70,7 @@ defmodule Pleroma.Web.WebFinger do else e -> Logger.debug("Couldn't finger #{account}.") - Logger.debug(e) + Logger.debug(inspect(e)) {:error, e} end end diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index ad9e47b46..c1d48ad7a 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -121,14 +121,24 @@ defmodule Pleroma.Web.Websub do requester.(subscription) end - def discover(topic, getter \\ &HTTPoison.get/1) do + def gather_feed_data(topic, getter \\ &HTTPoison.get/1) do with {:ok, response} <- getter.(topic), status_code when status_code in 200..299 <- response.status_code, body <- response.body, doc <- XML.parse_document(body), - url when not is_nil(url) <- XML.string_from_xpath(~S{/feed/link[@rel="self"]/@href}, doc), + uri when not is_nil(uri) <- XML.string_from_xpath("/feed/author[1]/uri", doc), hub when not is_nil(hub) <- XML.string_from_xpath(~S{/feed/link[@rel="hub"]/@href}, doc) do - {:ok, %{url: url, hub: hub}} + + name = XML.string_from_xpath("/feed/author[1]/name", doc) + preferredUsername = XML.string_from_xpath("/feed/author[1]/poco:preferredUsername", doc) + displayName = XML.string_from_xpath("/feed/author[1]/poco:displayName", doc) + + {:ok, %{ + uri: uri, + hub: hub, + nickname: preferredUsername || name, + name: displayName || name + }} else e -> {:error, e} end -- cgit v1.2.3 From 427bac0966c551eb16eaa6595d99fc5361a32ea9 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sat, 29 Apr 2017 19:06:01 +0200 Subject: Rework remote user subscription. --- lib/pleroma/web/ostatus/ostatus.ex | 44 ++++++++++++-------------------- lib/pleroma/web/web_finger/web_finger.ex | 18 ++++++++++--- lib/pleroma/web/websub/websub.ex | 10 +++++--- 3 files changed, 37 insertions(+), 35 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 90be86755..3e239179e 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -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. diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index 1d8c4d0c8..49796dab8 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -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} diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index c1d48ad7a..8e3e0a54e 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -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 -- cgit v1.2.3 From ba1ea770012893ea818f248e9a0a2ee3ab854676 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sat, 29 Apr 2017 19:47:56 +0200 Subject: Make key fetching use ostatus fetching. --- lib/pleroma/web/salmon/salmon.ex | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex index 99cca1f55..777898cfa 100644 --- a/lib/pleroma/web/salmon/salmon.ex +++ b/lib/pleroma/web/salmon/salmon.ex @@ -21,24 +21,16 @@ defmodule Pleroma.Web.Salmon do [data, type, encoding, alg, sig] end + # TODO rewrite in with-stile + # Make it fetch the key from the saved user if there is one def fetch_magic_key(salmon) do [data, _, _, _, _] = decode(salmon) doc = XML.parse_document(data) - {:xmlObj, :string, uri} = :xmerl_xpath.string('string(//author[1]/uri)', doc) + uri = XML.string_from_xpath("/entry/author[1]/uri", doc) - uri = to_string(uri) - base = URI.parse(uri).host + {:ok, info} = Pleroma.Web.OStatus.gather_user_info(uri) - # TODO: Find out if this endpoint is mandated by the standard. - # At least diaspora does it differently - {:ok, response} = HTTPoison.get(base <> "/.well-known/webfinger", ["Accept": "application/xrd+xml"], [params: [resource: uri]]) - - doc = XML.parse_document(response.body) - - {:xmlObj, :string, magickey} = :xmerl_xpath.string('string(//Link[@rel="magic-public-key"]/@href)', doc) - "data:application/magic-public-key," <> magickey = to_string(magickey) - - magickey + info.magic_key end def decode_and_validate(magickey, salmon) do -- cgit v1.2.3 From 20015b4b67cf0dfab6bdb658c9eb0e1ae04febdc Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sat, 29 Apr 2017 20:08:45 +0200 Subject: Save remote users with fqn as nickname. --- lib/pleroma/web/ostatus/ostatus.ex | 4 +++- lib/pleroma/web/websub/websub.ex | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 3e239179e..59c5d8e9e 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -96,10 +96,12 @@ defmodule Pleroma.Web.OStatus do data = %{ local: false, name: info.name, - nickname: info.nickname, + nickname: info.nickname <> "@" <> info.host, ap_id: info.uri, info: info } + # TODO: Make remote user changeset + # SHould enforce fqn nickname Repo.insert(Ecto.Changeset.change(%User{}, data)) end end diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index 8e3e0a54e..3fd779fba 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -139,7 +139,8 @@ defmodule Pleroma.Web.Websub do uri: uri, hub: hub, nickname: preferredUsername || name, - name: displayName || name + name: displayName || name, + host: URI.parse(uri).host }} else e -> {:error, e} -- cgit v1.2.3 From a16da387d251edc4d1bae949146c807d217cee1f Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sat, 29 Apr 2017 21:13:21 +0200 Subject: Handle full incoming feeds. --- lib/pleroma/web/ostatus/ostatus.ex | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 59c5d8e9e..9f85d971a 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -21,26 +21,32 @@ defmodule Pleroma.Web.OStatus do def handle_incoming(xml_string) do doc = parse_document(xml_string) - - {:xmlObj, :string, object_type } = :xmerl_xpath.string('string(/entry/activity:object-type[1])', doc) - - case object_type do - 'http://activitystrea.ms/schema/1.0/note' -> - handle_note(doc) - _ -> - Logger.error("Couldn't parse incoming document") - end + entries = :xmerl_xpath.string('//entry', doc) + + activities = Enum.map(entries, fn (entry) -> + {:xmlObj, :string, object_type } = :xmerl_xpath.string('string(/entry/activity:object-type[1])', entry) + + case object_type do + 'http://activitystrea.ms/schema/1.0/note' -> + {:ok, activity} = handle_note(entry, doc) + activity + _ -> + Logger.error("Couldn't parse incoming document") + nil + end + end) + {:ok, activities} end # TODO # wire up replies - def handle_note(doc) do - content_html = string_from_xpath("/entry/content[1]", doc) + def handle_note(entry, doc \\ nil) do + content_html = string_from_xpath("/entry/content[1]", entry) - uri = string_from_xpath("/entry/author/uri[1]", doc) + uri = string_from_xpath("/entry/author/uri[1]", entry) || string_from_xpath("/feed/author/uri[1]", doc) {:ok, actor} = find_or_make_user(uri) - context = string_from_xpath("/entry/ostatus:conversation[1]", doc) |> String.trim + context = string_from_xpath("/entry/ostatus:conversation[1]", entry) |> String.trim context = if String.length(context) > 0 do context else @@ -51,12 +57,12 @@ defmodule Pleroma.Web.OStatus do "https://www.w3.org/ns/activitystreams#Public" ] - mentions = :xmerl_xpath.string('/entry/link[@rel="mentioned" and @ostatus:object-type="http://activitystrea.ms/schema/1.0/person"]', doc) + mentions = :xmerl_xpath.string('/entry/link[@rel="mentioned" and @ostatus:object-type="http://activitystrea.ms/schema/1.0/person"]', entry) |> Enum.map(fn(person) -> string_from_xpath("@href", person) end) to = to ++ mentions - date = string_from_xpath("/entry/published", doc) + date = string_from_xpath("/entry/published", entry) object = %{ "type" => "Note", @@ -67,7 +73,7 @@ defmodule Pleroma.Web.OStatus do "actor" => actor.ap_id } - inReplyTo = string_from_xpath("/entry/thr:in-reply-to[1]/@href", doc) + inReplyTo = string_from_xpath("/entry/thr:in-reply-to[1]/@href", entry) object = if inReplyTo do Map.put(object, "inReplyTo", inReplyTo) -- cgit v1.2.3 From 8a0d2b33d8c9a1cef347c5daf5589a2245eb01b0 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 30 Apr 2017 09:25:46 +0200 Subject: Keep ostatus id as activity id. --- lib/pleroma/web/ostatus/ostatus.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 9f85d971a..f8e33bc7e 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -63,6 +63,7 @@ defmodule Pleroma.Web.OStatus do to = to ++ mentions date = string_from_xpath("/entry/published", entry) + id = string_from_xpath("/entry/id", entry) object = %{ "type" => "Note", @@ -81,7 +82,7 @@ defmodule Pleroma.Web.OStatus do object end - ActivityPub.create(to, actor, context, object, %{}, date) + ActivityPub.create(to, actor, context, object, %{"id" => id}, date) end def find_or_make_user(uri) do -- cgit v1.2.3 From ffc604a2c2d963b63e6cd13d0ee7cc9024f632a4 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 30 Apr 2017 10:04:54 +0200 Subject: Use cache for user info data. Later these should be persisted in the user. --- lib/pleroma/user.ex | 5 +++++ lib/pleroma/web/twitter_api/representers/user_representer.ex | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 9b7912c5b..cd6104680 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -122,4 +122,9 @@ defmodule Pleroma.User do key = "nickname:#{nickname}" Cachex.get!(:user_cache, key, fallback: fn(_) -> Repo.get_by(User, nickname: nickname) end) end + + def get_cached_user_info(user) do + key = "user_info:#{user.id}" + Cachex.get!(:user_cache, key, fallback: fn(_) -> user_info(user) end) + end end diff --git a/lib/pleroma/web/twitter_api/representers/user_representer.ex b/lib/pleroma/web/twitter_api/representers/user_representer.ex index ab7d6d353..29c7451f4 100644 --- a/lib/pleroma/web/twitter_api/representers/user_representer.ex +++ b/lib/pleroma/web/twitter_api/representers/user_representer.ex @@ -11,7 +11,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.UserRepresenter do false end - user_info = User.user_info(user) + user_info = User.get_cached_user_info(user) map = %{ "id" => user.id, -- cgit v1.2.3 From 11ea08649d5a5e5d2ac9ee29406f53240be77ec4 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 30 Apr 2017 10:06:57 +0200 Subject: Make cache bigger and longer lived. --- lib/pleroma/application.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 86b6c0c1e..6267d0695 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -15,9 +15,9 @@ defmodule Pleroma.Application do # Start your own worker by calling: Pleroma.Worker.start_link(arg1, arg2, arg3) # worker(Pleroma.Worker, [arg1, arg2, arg3]), worker(Cachex, [:user_cache, [ - default_ttl: 5000, + default_ttl: 25000, ttl_interval: 1000, - limit: 500 + limit: 2500 ]]) ] -- cgit v1.2.3 From 9d7c3190cc346bf2a5576b6b93c26723059ae9a1 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 30 Apr 2017 11:16:41 +0200 Subject: Get create activity from created object id. This is useful for Ostatus federation because ostatus doesn't have different ids for objects and activities... --- lib/pleroma/activity.ex | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 46568bb13..80d96d0f2 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -18,4 +18,9 @@ defmodule Pleroma.Activity do Repo.all(from activity in Activity, where: fragment("? @> ?", activity.data, ^%{object: %{id: ap_id}})) end + + def get_create_activity_by_object_ap_id(ap_id) do + Repo.one(from activity in Activity, + where: fragment("? @> ?", activity.data, ^%{type: "Create", object: %{id: ap_id}})) + end end -- cgit v1.2.3 From d937a8e69567ace33a72d5248c046860305076d7 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 30 Apr 2017 11:17:34 +0200 Subject: Add thr:in-reply-to to ostatus representer. --- lib/pleroma/web/ostatus/activity_representer.ex | 19 ++++++++++++++++++- lib/pleroma/web/ostatus/feed_representer.ex | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex index 30e695bcc..07b9033b9 100644 --- a/lib/pleroma/web/ostatus/activity_representer.ex +++ b/lib/pleroma/web/ostatus/activity_representer.ex @@ -1,4 +1,19 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do + alias Pleroma.Activity + require Logger + + defp get_in_reply_to(%{"object" => %{ "inReplyTo" => in_reply_to}}) do + with %Activity{data: %{"id" => id}} <- Activity.get_create_activity_by_object_ap_id(in_reply_to) do + [{:"thr:in-reply-to", [ref: to_charlist(id)], []}] + else _e -> + Logger.debug("Couldn't find replied-to activity:") + Logger.debug(in_reply_to) + [] + end + end + + defp get_in_reply_to(_), do: [] + def to_simple_form(%{data: %{"object" => %{"type" => "Note"}}} = activity, user) do h = fn(str) -> [to_charlist(str)] end @@ -12,6 +27,8 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do {:link, [rel: 'enclosure', href: to_charlist(url["href"]), type: to_charlist(url["mediaType"])], []} end) + in_reply_to = get_in_reply_to(activity.data) + [ {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/note']}, {:"activity:verb", ['http://activitystrea.ms/schema/1.0/post']}, @@ -22,7 +39,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do {:updated, h.(updated_at)}, {:"ostatus:conversation", [], h.(activity.data["context"])}, {:link, [href: h.(activity.data["context"]), rel: 'ostatus:conversation'], []} - ] ++ attachments + ] ++ attachments ++ in_reply_to end def to_simple_form(_,_), do: nil diff --git a/lib/pleroma/web/ostatus/feed_representer.ex b/lib/pleroma/web/ostatus/feed_representer.ex index 10a1ffb25..db7b685f3 100644 --- a/lib/pleroma/web/ostatus/feed_representer.ex +++ b/lib/pleroma/web/ostatus/feed_representer.ex @@ -16,6 +16,7 @@ defmodule Pleroma.Web.OStatus.FeedRepresenter do [{ :feed, [ xmlns: 'http://www.w3.org/2005/Atom', + "xmlns:thr": 'http://purl.org/syndication/thread/1.0', "xmlns:activity": 'http://activitystrea.ms/spec/1.0/', "xmlns:poco": 'http://portablecontacts.net/spec/1.0', "xmlns:ostatus": 'http://ostatus.org/schema/1.0' -- cgit v1.2.3 From 84027ff00b7fc63934f12129f84b5c7ee1d39248 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 30 Apr 2017 11:39:27 +0200 Subject: Handle comments. --- lib/pleroma/web/ostatus/ostatus.ex | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index f8e33bc7e..cd471f860 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -30,6 +30,9 @@ defmodule Pleroma.Web.OStatus do 'http://activitystrea.ms/schema/1.0/note' -> {:ok, activity} = handle_note(entry, doc) activity + 'http://activitystrea.ms/schema/1.0/comment' -> + {:ok, activity} = handle_note(entry, doc) + activity _ -> Logger.error("Couldn't parse incoming document") nil @@ -74,7 +77,7 @@ defmodule Pleroma.Web.OStatus do "actor" => actor.ap_id } - inReplyTo = string_from_xpath("/entry/thr:in-reply-to[1]/@href", entry) + inReplyTo = string_from_xpath("/entry/thr:in-reply-to[1]/@ref", entry) object = if inReplyTo do Map.put(object, "inReplyTo", inReplyTo) -- cgit v1.2.3 From 62607f37dcf3ab149baa09fe144959a25322be69 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 30 Apr 2017 11:55:19 +0200 Subject: Federate object id for posts in ostatus. This is because ostatus doens't have an id for the activities. --- lib/pleroma/web/ostatus/activity_representer.ex | 10 ++-------- lib/pleroma/web/ostatus/ostatus.ex | 3 ++- 2 files changed, 4 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex index 07b9033b9..274111ac9 100644 --- a/lib/pleroma/web/ostatus/activity_representer.ex +++ b/lib/pleroma/web/ostatus/activity_representer.ex @@ -3,13 +3,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do require Logger defp get_in_reply_to(%{"object" => %{ "inReplyTo" => in_reply_to}}) do - with %Activity{data: %{"id" => id}} <- Activity.get_create_activity_by_object_ap_id(in_reply_to) do - [{:"thr:in-reply-to", [ref: to_charlist(id)], []}] - else _e -> - Logger.debug("Couldn't find replied-to activity:") - Logger.debug(in_reply_to) - [] - end + [{:"thr:in-reply-to", [ref: to_charlist(in_reply_to)], []}] end defp get_in_reply_to(_), do: [] @@ -32,7 +26,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do [ {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/note']}, {:"activity:verb", ['http://activitystrea.ms/schema/1.0/post']}, - {:id, h.(activity.data["id"])}, + {:id, h.(activity.data["object"]["id"])}, # For notes, federate the object id. {:title, ['New note by #{user.nickname}']}, {:content, [type: 'html'], h.(activity.data["object"]["content"])}, {:published, h.(inserted_at)}, diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index cd471f860..6f169af73 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -69,6 +69,7 @@ defmodule Pleroma.Web.OStatus do id = string_from_xpath("/entry/id", entry) object = %{ + "id" => id, "type" => "Note", "to" => to, "content" => content_html, @@ -85,7 +86,7 @@ defmodule Pleroma.Web.OStatus do object end - ActivityPub.create(to, actor, context, object, %{"id" => id}, date) + ActivityPub.create(to, actor, context, object, %{}, date) end def find_or_make_user(uri) do -- cgit v1.2.3 From 18edc299b262974d3acb9d6f9c3758629b2c0968 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 30 Apr 2017 12:36:47 +0200 Subject: Handle duplicates. --- lib/pleroma/web/ostatus/ostatus.ex | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 6f169af73..16b6ac421 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -3,7 +3,7 @@ defmodule Pleroma.Web.OStatus do import Pleroma.Web.XML require Logger - alias Pleroma.{Repo, User, Web} + alias Pleroma.{Repo, User, Web, Object} alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.{WebFinger, Websub} @@ -28,11 +28,9 @@ defmodule Pleroma.Web.OStatus do case object_type do 'http://activitystrea.ms/schema/1.0/note' -> - {:ok, activity} = handle_note(entry, doc) - activity + with {:ok, activity} <- handle_note(entry, doc), do: activity 'http://activitystrea.ms/schema/1.0/comment' -> - {:ok, activity} = handle_note(entry, doc) - activity + with {:ok, activity} <- handle_note(entry, doc), do: activity _ -> Logger.error("Couldn't parse incoming document") nil @@ -86,7 +84,12 @@ defmodule Pleroma.Web.OStatus do object end - ActivityPub.create(to, actor, context, object, %{}, date) + # TODO: Bail out sooner and use transaction. + if Object.get_by_ap_id(id) do + {:error, "duplicate activity"} + else + ActivityPub.create(to, actor, context, object, %{}, date) + end end def find_or_make_user(uri) do -- cgit v1.2.3 From f9912599c4688a8609bd3500e0548eb2bf06c4a9 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 30 Apr 2017 12:53:49 +0200 Subject: Pull in remote avatar on federation. --- lib/pleroma/web/ostatus/ostatus.ex | 11 +++++------ lib/pleroma/web/websub/websub.ex | 4 +++- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 16b6ac421..01d6745ef 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -39,8 +39,6 @@ defmodule Pleroma.Web.OStatus do {:ok, activities} end - # TODO - # wire up replies def handle_note(entry, doc \\ nil) do content_html = string_from_xpath("/entry/content[1]", entry) @@ -112,7 +110,8 @@ defmodule Pleroma.Web.OStatus do name: info.name, nickname: info.nickname <> "@" <> info.host, ap_id: info.uri, - info: info + info: info, + avatar: info.avatar } # TODO: Make remote user changeset # SHould enforce fqn nickname @@ -121,9 +120,9 @@ defmodule Pleroma.Web.OStatus do end # TODO: Just takes the first one for now. - defp make_avatar_object(author_doc) do - href = string_from_xpath("/author[1]/link[@rel=\"avatar\"]/@href", author_doc) - type = string_from_xpath("/author[1]/link[@rel=\"avatar\"]/@type", author_doc) + def make_avatar_object(author_doc) do + href = string_from_xpath("/feed/author[1]/link[@rel=\"avatar\"]/@href", author_doc) + type = string_from_xpath("/feed/author[1]/link[@rel=\"avatar\"]/@type", author_doc) if href do %{ diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index 3fd779fba..63a91055a 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -134,13 +134,15 @@ defmodule Pleroma.Web.Websub do name = XML.string_from_xpath("/feed/author[1]/name", doc) preferredUsername = XML.string_from_xpath("/feed/author[1]/poco:preferredUsername", doc) displayName = XML.string_from_xpath("/feed/author[1]/poco:displayName", doc) + avatar = OStatus.make_avatar_object(doc) {:ok, %{ uri: uri, hub: hub, nickname: preferredUsername || name, name: displayName || name, - host: URI.parse(uri).host + host: URI.parse(uri).host, + avatar: avatar }} else e -> {:error, e} -- cgit v1.2.3 From 4c8111c3342aa57cf38accf64f0aa06be6958704 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 30 Apr 2017 13:53:26 +0200 Subject: Use conversation mapping objects to get / retrieve context from TwAPI. --- lib/pleroma/object.ex | 4 ++++ .../representers/activity_representer.ex | 10 +++++++-- lib/pleroma/web/twitter_api/twitter_api.ex | 25 ++++++++++++++++------ 3 files changed, 31 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index f932034d7..a924c3199 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -13,4 +13,8 @@ defmodule Pleroma.Object do Repo.one(from object in Object, where: fragment("? @> ?", object.data, ^%{id: ap_id})) end + + def context_mapping(context) do + %Object{data: %{"id" => context}} + end end diff --git a/lib/pleroma/web/twitter_api/representers/activity_representer.ex b/lib/pleroma/web/twitter_api/representers/activity_representer.ex index f2bf93abb..bfaabb4e4 100644 --- a/lib/pleroma/web/twitter_api/representers/activity_representer.ex +++ b/lib/pleroma/web/twitter_api/representers/activity_representer.ex @@ -1,9 +1,9 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do use Pleroma.Web.TwitterAPI.Representers.BaseRepresenter alias Pleroma.Web.TwitterAPI.Representers.{UserRepresenter, ObjectRepresenter} + alias Pleroma.Web.TwitterAPI.TwitterAPI alias Pleroma.Activity - defp user_by_ap_id(user_list, ap_id) do Enum.find(user_list, fn (%{ap_id: user_id}) -> ap_id == user_id end) end @@ -82,6 +82,12 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do |> Enum.filter(&(&1)) |> Enum.map(fn (user) -> UserRepresenter.to_map(user, opts) end) + + conversation_id = with context when not is_nil(context) <- activity.data["context"] do + TwitterAPI.context_to_conversation_id(context) + else _e -> nil + end + %{ "id" => activity.id, "user" => UserRepresenter.to_map(user, opts), @@ -92,7 +98,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do "is_post_verb" => true, "created_at" => created_at, "in_reply_to_status_id" => activity.data["object"]["inReplyToStatusId"], - "statusnet_conversation_id" => activity.data["object"]["statusnetConversationId"], + "statusnet_conversation_id" => conversation_id, "attachments" => (activity.data["object"]["attachment"] || []) |> ObjectRepresenter.enum_to_list(opts), "attentions" => attentions, "fave_num" => like_count, diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 1c3396d27..b2fb72a81 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -102,12 +102,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do end def fetch_conversation(user, id) do - query = from activity in Activity, - where: fragment("? @> ?", activity.data, ^%{ statusnetConversationId: id}), - limit: 1 - - with %Activity{} = activity <- Repo.one(query), - context <- activity.data["context"], + with context when is_binary(context) <- conversation_id_to_context(id), activities <- ActivityPub.fetch_activities_for_context(context), statuses <- activities |> activities_to_statuses(%{for: user}) do @@ -322,4 +317,22 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do defp make_date do DateTime.utc_now() |> DateTime.to_iso8601 end + + def context_to_conversation_id(context) do + with %Object{id: id} <- Object.get_by_ap_id(context) do + id + else _e -> + changeset = Object.context_mapping(context) + {:ok, %{id: id}} = Repo.insert(changeset) + id + end + end + + def conversation_id_to_context(id) do + with %Object{data: %{"id" => context}} <- Repo.get(Object, id) do + context + else _e -> + {:error, "No such conversation"} + end + end end -- cgit v1.2.3 From 379caca01d818613ba7e013e8f0bebba160c6871 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 30 Apr 2017 13:58:40 +0200 Subject: Wrap context creation in transaction. --- lib/pleroma/web/twitter_api/twitter_api.ex | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index b2fb72a81..13dc3bd49 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -319,13 +319,16 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do end def context_to_conversation_id(context) do - with %Object{id: id} <- Object.get_by_ap_id(context) do - id - else _e -> - changeset = Object.context_mapping(context) - {:ok, %{id: id}} = Repo.insert(changeset) - id - end + {:ok, id} = Repo.transaction(fn -> + with %Object{id: id} <- Object.get_by_ap_id(context) do + id + else _e -> + changeset = Object.context_mapping(context) + {:ok, %{id: id}} = Repo.insert(changeset) + id + end + end) + id end def conversation_id_to_context(id) do -- cgit v1.2.3 From 009fcd2acfdc3ae3ba4b706eb71c50015227de50 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 30 Apr 2017 14:02:04 +0200 Subject: Stop adding statusnetConversationIds. --- lib/pleroma/web/activity_pub/activity_pub.ex | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 82f9fcc1c..9441a37ab 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -33,8 +33,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> Map.merge(additional) with {:ok, activity} <- insert(activity) do - {:ok, activity} = add_conversation_id(activity) - if actor.local do Pleroma.Web.Federator.enqueue(:publish, activity) end @@ -43,24 +41,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end - defp add_conversation_id(activity) do - if is_integer(activity.data["statusnetConversationId"]) do - {:ok, activity} - else - data = activity.data - |> put_in(["object", "statusnetConversationId"], activity.id) - |> put_in(["statusnetConversationId"], activity.id) - - object = Object.get_by_ap_id(activity.data["object"]["id"]) - - changeset = Ecto.Changeset.change(object, data: data["object"]) - Repo.update(changeset) - - changeset = Ecto.Changeset.change(activity, data: data) - Repo.update(changeset) - end - end - def like(%User{ap_id: ap_id} = user, %Object{data: %{ "id" => id}} = object) do cond do # There's already a like here, so return the original activity. -- cgit v1.2.3 From 09f7ed421497e12797f30ae34e0f2346f1b6a428 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 30 Apr 2017 14:26:29 +0200 Subject: Don't set statusnetConversationIds on replies anymore. --- lib/pleroma/web/twitter_api/twitter_api.ex | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 13dc3bd49..85fac9146 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -58,11 +58,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do "actor" => user.ap_id, "inReplyTo" => inReplyTo.data["object"]["id"], "inReplyToStatusId" => inReplyTo.id, - "statusnetConversationId" => inReplyTo.data["statusnetConversationId"] - } - additional = %{ - "statusnetConversationId" => inReplyTo.data["statusnetConversationId"] } + additional = %{} [to, context, object, additional] else -- cgit v1.2.3 From bb1d08a47c34c70d42f6c3afa08232765a24884d Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 30 Apr 2017 15:00:04 +0200 Subject: Return keys in webfinger. --- lib/pleroma/user.ex | 2 +- lib/pleroma/web/web_finger/web_finger.ex | 22 ++++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index cd6104680..49ba9b22e 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -16,7 +16,7 @@ defmodule Pleroma.User do field :ap_id, :string field :avatar, :map field :local, :boolean, default: true - field :info, :map + field :info, :map, default: %{} timestamps() end diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index 49796dab8..13e3baad6 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -1,8 +1,7 @@ defmodule Pleroma.Web.WebFinger do alias Pleroma.XmlBuilder - alias Pleroma.User - alias Pleroma.Web.OStatus - alias Pleroma.Web.XML + alias Pleroma.{Repo, User} + alias Pleroma.Web.{XML, Salmon, OStatus} require Logger def host_meta() do @@ -28,18 +27,33 @@ defmodule Pleroma.Web.WebFinger do end def represent_user(user) do + {:ok, user} = ensure_keys_present(user) + {:ok, _private, public} = Salmon.keys_from_pem(user.info["keys"]) + magic_key = Salmon.encode_key(public) { :XRD, %{xmlns: "http://docs.oasis-open.org/ns/xri/xrd-1.0"}, [ {:Subject, "acct:#{user.nickname}@#{Pleroma.Web.host}"}, {:Alias, user.ap_id}, {:Link, %{rel: "http://schemas.google.com/g/2010#updates-from", type: "application/atom+xml", href: OStatus.feed_path(user)}}, - {:Link, %{rel: "salmon", href: OStatus.salmon_path(user)}} + {:Link, %{rel: "salmon", href: OStatus.salmon_path(user)}}, + {:Link, %{rel: "magic-public-key", href: "data:application/magic-public-key,#{magic_key}"}} ] } |> XmlBuilder.to_doc end + def ensure_keys_present(user) do + info = user.info || %{} + if info["keys"] do + {:ok, user} + else + {:ok, pem} = Salmon.generate_rsa_pem + info = Map.put(info, "keys", pem) + Repo.update(Ecto.Changeset.change(user, info: info)) + end + end + # FIXME: Make this call the host-meta to find the actual address. defp webfinger_address(domain) do "//#{domain}/.well-known/webfinger" -- cgit v1.2.3 From a173fb9e417cbb4fc7694672dd31bce90a3f9099 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 30 Apr 2017 15:05:16 +0200 Subject: Get users fresh, might so we don't make new keys all the time. --- lib/pleroma/user.ex | 4 ++++ lib/pleroma/web/web_finger/web_finger.ex | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 49ba9b22e..2c297433a 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -123,6 +123,10 @@ defmodule Pleroma.User do Cachex.get!(:user_cache, key, fallback: fn(_) -> Repo.get_by(User, nickname: nickname) end) end + def get_cached_by_nickname(nickname) do + Repo.get_by(User, nickname: nickname) + end + def get_cached_user_info(user) do key = "user_info:#{user.id}" Cachex.get!(:user_cache, key, fallback: fn(_) -> user_info(user) end) diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index 13e3baad6..7ceca042b 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -20,7 +20,7 @@ defmodule Pleroma.Web.WebFinger do regex = ~r/(acct:)?(?\w+)@#{host}/ case Regex.named_captures(regex, resource) do %{"username" => username} -> - user = User.get_cached_by_nickname(username) + user = User.get_by_nickname(username) {:ok, represent_user(user)} _ -> nil end -- cgit v1.2.3 From eb12a89d22c09bccad7cb13780e0313de8be8e93 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 30 Apr 2017 15:06:22 +0200 Subject: Rename wrongly-named function. --- lib/pleroma/user.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 2c297433a..58f89a915 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -123,7 +123,7 @@ defmodule Pleroma.User do Cachex.get!(:user_cache, key, fallback: fn(_) -> Repo.get_by(User, nickname: nickname) end) end - def get_cached_by_nickname(nickname) do + def get_by_nickname(nickname) do Repo.get_by(User, nickname: nickname) end -- cgit v1.2.3 From bed0b398139897ebe9f839d1263acf6934c4a42f Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 30 Apr 2017 18:48:48 +0200 Subject: Add function to fetch users from fqn. --- lib/pleroma/user.ex | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 58f89a915..c264d7e90 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -3,6 +3,7 @@ defmodule Pleroma.User do import Ecto.Changeset import Ecto.Query alias Pleroma.{Repo, User, Activity, Object} + alias Pleroma.Web.OStatus schema "users" do field :bio, :string @@ -131,4 +132,15 @@ defmodule Pleroma.User do key = "user_info:#{user.id}" Cachex.get!(:user_cache, key, fallback: fn(_) -> user_info(user) end) end + + def get_or_fetch_by_nickname(nickname) do + with %User{} = user <- get_by_nickname(nickname) do + user + else _e -> + with {:ok, user} <- OStatus.make_user(nickname) do + user + else _e -> nil + end + end + end end -- cgit v1.2.3 From 6843755834192c671aebece505a1ab9322e57eee Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 1 May 2017 13:14:58 +0200 Subject: Make outgoing salmons work. --- lib/pleroma/user.ex | 5 ++-- lib/pleroma/web/federator/federator.ex | 4 +++ lib/pleroma/web/ostatus/activity_representer.ex | 31 ++++++++++++++++++--- lib/pleroma/web/salmon/salmon.ex | 36 +++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index c264d7e90..01cbfe796 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -121,7 +121,7 @@ defmodule Pleroma.User do def get_cached_by_nickname(nickname) do key = "nickname:#{nickname}" - Cachex.get!(:user_cache, key, fallback: fn(_) -> Repo.get_by(User, nickname: nickname) end) + Cachex.get!(:user_cache, key, fallback: fn(_) -> get_or_fetch_by_nickname(nickname) end) end def get_by_nickname(nickname) do @@ -137,7 +137,8 @@ defmodule Pleroma.User do with %User{} = user <- get_by_nickname(nickname) do user else _e -> - with {:ok, user} <- OStatus.make_user(nickname) do + with [nick, domain] <- String.split(nickname, "@"), + {:ok, user} <- OStatus.make_user(nickname) do user else _e -> nil end diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index 38df13540..5293507b5 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -7,7 +7,11 @@ defmodule Pleroma.Web.Federator do def handle(:publish, activity) do Logger.debug("Running publish for #{activity.data["id"]}") with actor when not is_nil(actor) <- User.get_cached_by_ap_id(activity.data["actor"]) do + Logger.debug("Sending #{activity.data["id"]} out via websub") Pleroma.Web.Websub.publish(Pleroma.Web.OStatus.feed_path(actor), actor, activity) + + Logger.debug("Sending #{activity.data["id"]} out via salmon") + Pleroma.Web.Salmon.publish(actor, activity) end end diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex index 274111ac9..c64bb3a3b 100644 --- a/lib/pleroma/web/ostatus/activity_representer.ex +++ b/lib/pleroma/web/ostatus/activity_representer.ex @@ -1,5 +1,6 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do alias Pleroma.Activity + alias Pleroma.Web.OStatus.UserRepresenter require Logger defp get_in_reply_to(%{"object" => %{ "inReplyTo" => in_reply_to}}) do @@ -8,7 +9,17 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do defp get_in_reply_to(_), do: [] - def to_simple_form(%{data: %{"object" => %{"type" => "Note"}}} = activity, user) do + defp get_mentions(to) do + Enum.map(to, fn + ("https://www.w3.org/ns/activitystreams#Public") -> + {:link, [rel: "mentioned", "ostatus:object-type": "http://activitystrea.ms/schema/1.0/collection", href: "http://activityschema.org/collection/public"], []} + (id) -> + {:link, [rel: "mentioned", "ostatus:object-type": "http://activitystrea.ms/schema/1.0/person", href: id], []} + end) + end + + def to_simple_form(activity, user, with_author \\ false) + def to_simple_form(%{data: %{"object" => %{"type" => "Note"}}} = activity, user, with_author) do h = fn(str) -> [to_charlist(str)] end updated_at = activity.updated_at @@ -22,6 +33,8 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do end) in_reply_to = get_in_reply_to(activity.data) + author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: [] + mentions = activity.data["to"] |> get_mentions [ {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/note']}, @@ -33,8 +46,20 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do {:updated, h.(updated_at)}, {:"ostatus:conversation", [], h.(activity.data["context"])}, {:link, [href: h.(activity.data["context"]), rel: 'ostatus:conversation'], []} - ] ++ attachments ++ in_reply_to + ] ++ attachments ++ in_reply_to ++ author ++ mentions + end + + def wrap_with_entry(simple_form) do + [{ + :entry, [ + xmlns: 'http://www.w3.org/2005/Atom', + "xmlns:thr": 'http://purl.org/syndication/thread/1.0', + "xmlns:activity": 'http://activitystrea.ms/spec/1.0/', + "xmlns:poco": 'http://portablecontacts.net/spec/1.0', + "xmlns:ostatus": 'http://ostatus.org/schema/1.0' + ], simple_form + }] end - def to_simple_form(_,_), do: nil + def to_simple_form(_,_,_), do: nil end diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex index 777898cfa..b4f214d46 100644 --- a/lib/pleroma/web/salmon/salmon.ex +++ b/lib/pleroma/web/salmon/salmon.ex @@ -1,6 +1,9 @@ defmodule Pleroma.Web.Salmon do use Bitwise alias Pleroma.Web.XML + alias Pleroma.Web.OStatus.ActivityRepresenter + alias Pleroma.User + require Logger def decode(salmon) do doc = XML.parse_document(salmon) @@ -118,4 +121,37 @@ defmodule Pleroma.Web.Salmon do {:ok, salmon} end + + def remote_users(%{data: %{"to" => to}}) do + to + |> Enum.map(fn(id) -> User.get_cached_by_ap_id(id) end) + |> Enum.filter(fn(user) -> user && !user.local end) + end + + defp send_to_user(%{info: %{"salmon" => salmon}}, feed, poster) do + poster.(salmon, feed, [{"Content-Type", "application/magic-envelope+xml"}]) + end + + defp send_to_user(_,_,_), do: nil + + def publish(user, activity, poster \\ &HTTPoison.post/3) + def publish(%{info: %{"keys" => keys}} = user, activity, poster) do + feed = ActivityRepresenter.to_simple_form(activity, user, true) + |> ActivityRepresenter.wrap_with_entry + |> :xmerl.export_simple(:xmerl_xml) + |> to_string + + if feed do + {:ok, private, _} = keys_from_pem(keys) + {:ok, feed} = encode(private, feed) + + remote_users(activity) + |> Enum.each(fn(remote_user) -> + Logger.debug("sending salmon to #{remote_user.ap_id}") + send_to_user(remote_user, feed, poster) + end) + end + end + + def publish(%{id: id}, _, _), do: Logger.debug("Keys missing for user #{id}") end -- cgit v1.2.3 From e54e592d6c1d0ff5de5a029ae1fccee447f97149 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 1 May 2017 13:51:17 +0200 Subject: Return webfinger for ap_ids. --- lib/pleroma/web/web_finger/web_finger.ex | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index 7ceca042b..f8f4d5e42 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -18,11 +18,15 @@ defmodule Pleroma.Web.WebFinger do def webfinger(resource) do host = Pleroma.Web.host regex = ~r/(acct:)?(?\w+)@#{host}/ - case Regex.named_captures(regex, resource) do - %{"username" => username} -> - user = User.get_by_nickname(username) + with %{"username" => username} <- Regex.named_captures(regex, resource) do + user = User.get_by_nickname(username) + {:ok, represent_user(user)} + else _e -> + with user when not is_nil(user) <- User.get_cached_by_ap_id(resource) do {:ok, represent_user(user)} - _ -> nil + else _e -> + {:error, "Couldn't find user"} + end end end -- cgit v1.2.3 From 35938656ab4186912ee6593cc09754ef945e17fc Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 1 May 2017 14:07:29 +0200 Subject: Make user keys on usage. --- lib/pleroma/web/federator/federator.ex | 2 ++ lib/pleroma/web/web_finger/web_finger.ex | 1 + 2 files changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index 5293507b5..675e804a2 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -1,5 +1,6 @@ defmodule Pleroma.Web.Federator do alias Pleroma.User + alias Pleroma.Web.WebFinger require Logger @websub Application.get_env(:pleroma, :websub) @@ -10,6 +11,7 @@ defmodule Pleroma.Web.Federator do Logger.debug("Sending #{activity.data["id"]} out via websub") Pleroma.Web.Websub.publish(Pleroma.Web.OStatus.feed_path(actor), actor, activity) + {:ok, actor} = WebFinger.ensure_keys_present(actor) Logger.debug("Sending #{activity.data["id"]} out via salmon") Pleroma.Web.Salmon.publish(actor, activity) end diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index f8f4d5e42..ff10173ef 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -47,6 +47,7 @@ defmodule Pleroma.Web.WebFinger do |> XmlBuilder.to_doc end + # This seems a better fit in Salmon def ensure_keys_present(user) do info = user.info || %{} if info["keys"] do -- cgit v1.2.3 From d187a4965fbba93149621478e5257fcca2cea4f9 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 1 May 2017 14:07:41 +0200 Subject: Return feed for xml requests of the user. --- lib/pleroma/web/router.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 2ff75ec5d..e875839df 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -74,6 +74,7 @@ defmodule Pleroma.Web.Router do pipe_through :ostatus get "/users/:nickname/feed", OStatus.OStatusController, :feed + get "/users/:nickname", OStatus.OStatusController, :feed post "/users/:nickname/salmon", OStatus.OStatusController, :salmon_incoming post "/push/hub/:nickname", Websub.WebsubController, :websub_subscription_request get "/push/subscriptions/:id", Websub.WebsubController, :websub_subscription_confirmation -- cgit v1.2.3 From f169de34544a12c174c454da59781a694b8c2387 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 1 May 2017 16:12:20 +0200 Subject: Cache objects in dev and prod. --- lib/pleroma/object.ex | 9 +++++++++ lib/pleroma/web/twitter_api/twitter_api.ex | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index a924c3199..168843bd9 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -14,6 +14,15 @@ defmodule Pleroma.Object do where: fragment("? @> ?", object.data, ^%{id: ap_id})) end + def get_cached_by_ap_id(ap_id) do + if Mix.env == :test do + get_by_ap_id(ap_id) + else + key = "object:#{ap_id}" + Cachex.get!(:user_cache, key, fallback: fn(_) -> get_by_ap_id(ap_id) end) + end + end + def context_mapping(context) do %Object{data: %{"id" => context}} end diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 85fac9146..941bacaa9 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -317,7 +317,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do def context_to_conversation_id(context) do {:ok, id} = Repo.transaction(fn -> - with %Object{id: id} <- Object.get_by_ap_id(context) do + with %Object{id: id} <- Object.get_cached_by_ap_id(context) do id else _e -> changeset = Object.context_mapping(context) -- cgit v1.2.3 From 3cb518270ab8c41f73ed449f0c12127c3625c6ca Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 1 May 2017 16:15:21 +0200 Subject: Remove superfluous transaction. --- lib/pleroma/web/twitter_api/twitter_api.ex | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 941bacaa9..e6f5fc906 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -316,16 +316,13 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do end def context_to_conversation_id(context) do - {:ok, id} = Repo.transaction(fn -> - with %Object{id: id} <- Object.get_cached_by_ap_id(context) do - id - else _e -> - changeset = Object.context_mapping(context) - {:ok, %{id: id}} = Repo.insert(changeset) - id - end - end) - id + with %Object{id: id} <- Object.get_cached_by_ap_id(context) do + id + else _e -> + changeset = Object.context_mapping(context) + {:ok, %{id: id}} = Repo.insert(changeset) + id + end end def conversation_id_to_context(id) do -- cgit v1.2.3 From 108573265aaf237a37937544c3f416b85f57e0fb Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 1 May 2017 16:28:40 +0200 Subject: Don't commit nil values in object cache. --- lib/pleroma/object.ex | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 168843bd9..949ccb0f6 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -19,7 +19,14 @@ defmodule Pleroma.Object do get_by_ap_id(ap_id) else key = "object:#{ap_id}" - Cachex.get!(:user_cache, key, fallback: fn(_) -> get_by_ap_id(ap_id) end) + Cachex.get!(:user_cache, key, fallback: fn(_) -> + object = get_by_ap_id(ap_id) + if object do + {:commit, object} + else + {:ignore, object} + end + end) end end -- cgit v1.2.3 From 1854842b093524c25e08ece0b33150172036f53c Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 1 May 2017 17:28:49 +0200 Subject: Log subscription error. --- lib/pleroma/web/websub/websub.ex | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index 63a91055a..67055a116 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -78,6 +78,9 @@ defmodule Pleroma.Web.Websub do {:ok, websub} else {:error, reason} -> + Logger.debug("Couldn't create subscription.") + Logger.debug(inspect(reason)) + {:error, reason} end end -- cgit v1.2.3 From 92a8944dfe043444af6b4b422789129c04bd34a0 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 1 May 2017 18:05:02 +0200 Subject: Redirect to user feed instead of directly serving it. --- lib/pleroma/web/ostatus/ostatus_controller.ex | 6 ++++++ lib/pleroma/web/router.ex | 2 +- lib/pleroma/web/websub/websub.ex | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 4174db786..1c609f6f2 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -4,8 +4,14 @@ defmodule Pleroma.Web.OStatus.OStatusController do alias Pleroma.{User, Activity} alias Pleroma.Web.OStatus.FeedRepresenter alias Pleroma.Repo + alias Pleroma.Web.OStatus import Ecto.Query + def feed_redirect(conn, %{"nickname" => nickname}) do + user = User.get_cached_by_nickname(nickname) + redirect conn, external: OStatus.feed_path(user) + end + def feed(conn, %{"nickname" => nickname}) do user = User.get_cached_by_nickname(nickname) query = from activity in Activity, diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index e875839df..e1475a03e 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -74,7 +74,7 @@ defmodule Pleroma.Web.Router do pipe_through :ostatus get "/users/:nickname/feed", OStatus.OStatusController, :feed - get "/users/:nickname", OStatus.OStatusController, :feed + get "/users/:nickname", OStatus.OStatusController, :feed_redirect post "/users/:nickname/salmon", OStatus.OStatusController, :salmon_incoming post "/push/hub/:nickname", Websub.WebsubController, :websub_subscription_request get "/push/subscriptions/:id", Websub.WebsubController, :websub_subscription_confirmation diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index 67055a116..b279a5060 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -99,7 +99,7 @@ defmodule Pleroma.Web.Websub do defp valid_topic(%{"hub.topic" => topic}, user) do if topic == OStatus.feed_path(user) do - {:ok, topic} + {:ok, OStatus.feed_path(user)} else {:error, "Wrong topic requested, expected #{OStatus.feed_path(user)}, got #{topic}"} end -- cgit v1.2.3 From 97d11dec0ee78d24fea398f23d123baf0111362a Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 1 May 2017 18:07:50 +0200 Subject: Also accept user id as feed topic. --- lib/pleroma/web/websub/websub.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index b279a5060..fc253b930 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -98,7 +98,7 @@ defmodule Pleroma.Web.Websub do end defp valid_topic(%{"hub.topic" => topic}, user) do - if topic == OStatus.feed_path(user) do + if topic == OStatus.feed_path(user) || topic == Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :feed_redirect, user.nickname) do {:ok, OStatus.feed_path(user)} else {:error, "Wrong topic requested, expected #{OStatus.feed_path(user)}, got #{topic}"} -- cgit v1.2.3 From e88062494e04c257b1dea33965764a51e04cbdf7 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 1 May 2017 18:34:15 +0200 Subject: Revert "Also accept user id as feed topic." This reverts commit 97d11dec0ee78d24fea398f23d123baf0111362a. --- lib/pleroma/web/websub/websub.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index fc253b930..b279a5060 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -98,7 +98,7 @@ defmodule Pleroma.Web.Websub do end defp valid_topic(%{"hub.topic" => topic}, user) do - if topic == OStatus.feed_path(user) || topic == Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :feed_redirect, user.nickname) do + if topic == OStatus.feed_path(user) do {:ok, OStatus.feed_path(user)} else {:error, "Wrong topic requested, expected #{OStatus.feed_path(user)}, got #{topic}"} -- cgit v1.2.3 From ceb2f68432e2861f09f7ba34b98bef259be9158a Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 1 May 2017 18:40:36 +0200 Subject: Add type to rel=self link in feed. --- lib/pleroma/web/ostatus/feed_representer.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/feed_representer.ex b/lib/pleroma/web/ostatus/feed_representer.ex index db7b685f3..7f9d6a46b 100644 --- a/lib/pleroma/web/ostatus/feed_representer.ex +++ b/lib/pleroma/web/ostatus/feed_representer.ex @@ -26,7 +26,7 @@ defmodule Pleroma.Web.OStatus.FeedRepresenter do {:updated, h.(most_recent_update)}, {:link, [rel: 'hub', href: h.(OStatus.pubsub_path(user))], []}, {:link, [rel: 'salmon', href: h.(OStatus.salmon_path(user))], []}, - {:link, [rel: 'self', href: h.(OStatus.feed_path(user))], []}, + {:link, [rel: 'self', href: h.(OStatus.feed_path(user)), type: 'application/atom+xml'], []}, {:author, UserRepresenter.to_simple_form(user)}, ] ++ entries }] -- cgit v1.2.3 From 76e653b0d80279491a4b57278aec7a83efa003d0 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 1 May 2017 20:02:32 +0200 Subject: Add user profile page link. --- lib/pleroma/web/web_finger/web_finger.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index ff10173ef..217b09dc5 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -40,6 +40,7 @@ defmodule Pleroma.Web.WebFinger do {:Subject, "acct:#{user.nickname}@#{Pleroma.Web.host}"}, {:Alias, user.ap_id}, {:Link, %{rel: "http://schemas.google.com/g/2010#updates-from", type: "application/atom+xml", href: OStatus.feed_path(user)}}, + {:Link, %{rel: "ttp://webfinger.net/rel/profile-page", type: "text/html", href: user.ap_id}}, {:Link, %{rel: "salmon", href: OStatus.salmon_path(user)}}, {:Link, %{rel: "magic-public-key", href: "data:application/magic-public-key,#{magic_key}"}} ] -- cgit v1.2.3 From 703d9f36281e90ef049bfe0a0d579e4e07b38bb6 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 1 May 2017 20:04:32 +0200 Subject: Not enough h. --- lib/pleroma/web/web_finger/web_finger.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index 217b09dc5..402184d3f 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -40,7 +40,7 @@ defmodule Pleroma.Web.WebFinger do {:Subject, "acct:#{user.nickname}@#{Pleroma.Web.host}"}, {:Alias, user.ap_id}, {:Link, %{rel: "http://schemas.google.com/g/2010#updates-from", type: "application/atom+xml", href: OStatus.feed_path(user)}}, - {:Link, %{rel: "ttp://webfinger.net/rel/profile-page", type: "text/html", href: user.ap_id}}, + {:Link, %{rel: "http://webfinger.net/rel/profile-page", type: "text/html", href: user.ap_id}}, {:Link, %{rel: "salmon", href: OStatus.salmon_path(user)}}, {:Link, %{rel: "magic-public-key", href: "data:application/magic-public-key,#{magic_key}"}} ] -- cgit v1.2.3 From aa209414164cf098376d8aefb3f2af16111bd220 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 1 May 2017 20:09:00 +0200 Subject: Some servers send empty lease_seconds requests... --- lib/pleroma/web/websub/websub.ex | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index b279a5060..905c237a0 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -89,6 +89,11 @@ defmodule Pleroma.Web.Websub do Repo.get_by(WebsubServerSubscription, topic: topic, callback: callback) || %WebsubServerSubscription{} end + # Temp hack for mastodon. + defp lease_time(%{"hub.lease_seconds" => ""}) do + {:ok, 60 * 60 * 24 * 3} # three days + end + defp lease_time(%{"hub.lease_seconds" => lease_seconds}) do {:ok, String.to_integer(lease_seconds)} end -- cgit v1.2.3 From 8ae13d94dc69e4fcb7f454c2eb7665955c8e37fb Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 1 May 2017 20:38:01 +0200 Subject: Use empty context id if we get none Thanks mastodon. --- lib/pleroma/web/ostatus/ostatus.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 01d6745ef..6a6f43acf 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -45,7 +45,7 @@ defmodule Pleroma.Web.OStatus do uri = string_from_xpath("/entry/author/uri[1]", entry) || string_from_xpath("/feed/author/uri[1]", doc) {:ok, actor} = find_or_make_user(uri) - context = string_from_xpath("/entry/ostatus:conversation[1]", entry) |> String.trim + context = (string_from_xpath("/entry/ostatus:conversation[1]", entry) || "") |> String.trim context = if String.length(context) > 0 do context else -- cgit v1.2.3 From 89c1e90eb2a5da0a6f635a6158fe880076518a38 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 1 May 2017 22:02:07 +0200 Subject: Don't crypt raw iolists. --- lib/pleroma/web/websub/websub.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index 905c237a0..546bfb5a4 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -41,6 +41,7 @@ defmodule Pleroma.Web.Websub do Enum.each(subscriptions, fn(sub) -> response = FeedRepresenter.to_simple_form(user, [activity], [user]) |> :xmerl.export_simple(:xmerl_xml) + |> to_string signature = sign(sub.secret, response) HTTPoison.post(sub.callback, response, [ @@ -51,7 +52,7 @@ defmodule Pleroma.Web.Websub do end def sign(secret, doc) do - :crypto.hmac(:sha, secret, doc) |> Base.encode16 + :crypto.hmac(:sha, secret, to_string(doc)) |> Base.encode16 end def incoming_subscription_request(user, %{"hub.mode" => "subscribe"} = params) do -- cgit v1.2.3 From 56bacc90d1f401f8867e4ca7a052f7d15e18a304 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 2 May 2017 10:43:35 +0200 Subject: Fix specs, add local marker to actitivies. --- lib/pleroma/activity.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 80d96d0f2..d77c88997 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Activity do schema "activities" do field :data, :map + field :local, :boolean, default: true timestamps() end -- cgit v1.2.3 From 6dd8335477ff3adc2dda5fe4e45b0e1b38dc5b9b Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 2 May 2017 10:47:04 +0200 Subject: Mark incoming activties as non-local. --- lib/pleroma/web/activity_pub/activity_pub.ex | 8 ++++---- lib/pleroma/web/ostatus/ostatus.ex | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 9441a37ab..4eab2e2d0 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -3,7 +3,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.{Activity, Object, Upload, User} import Ecto.Query - def insert(map) when is_map(map) do + def insert(map, local \\ true) when is_map(map) do map = map |> Map.put_new_lazy("id", &generate_activity_id/0) |> Map.put_new_lazy("published", &make_date/0) @@ -16,10 +16,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do map end - Repo.insert(%Activity{data: map}) + Repo.insert(%Activity{data: map, local: local}) end - def create(to, actor, context, object, additional \\ %{}, published \\ nil) do + def create(to, actor, context, object, additional \\ %{}, published \\ nil, local \\ true) do published = published || make_date() activity = %{ @@ -32,7 +32,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do } |> Map.merge(additional) - with {:ok, activity} <- insert(activity) do + with {:ok, activity} <- insert(activity, local) do if actor.local do Pleroma.Web.Federator.enqueue(:publish, activity) end diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 6a6f43acf..db32d2c35 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -86,7 +86,7 @@ defmodule Pleroma.Web.OStatus do if Object.get_by_ap_id(id) do {:error, "duplicate activity"} else - ActivityPub.create(to, actor, context, object, %{}, date) + ActivityPub.create(to, actor, context, object, %{}, date, false) end end -- cgit v1.2.3 From 32a95d73daf94a1186ccdbcdc9ce0f91b559119c Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 2 May 2017 14:12:43 +0200 Subject: Add twkn timeline. --- lib/pleroma/web/activity_pub/activity_pub.ex | 6 ++++++ lib/pleroma/web/router.ex | 2 +- lib/pleroma/web/twitter_api/twitter_api.ex | 6 ++++++ lib/pleroma/web/twitter_api/twitter_api_controller.ex | 8 ++++++++ 4 files changed, 21 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 4eab2e2d0..0fb8db520 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -149,6 +149,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do query = from activity in query, where: activity.id > ^since_id + query = if opts["local_only"] do + from activity in query, where: activity.local == true + else + query + end + query = if opts["max_id"] do from activity in query, where: activity.id < ^opts["max_id"] else diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index e1475a03e..b0c1dcd91 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -30,7 +30,7 @@ defmodule Pleroma.Web.Router do get "/statusnet/config", TwitterAPI.Controller, :config get "/statuses/public_timeline", TwitterAPI.Controller, :public_timeline - get "/statuses/public_and_external_timeline", TwitterAPI.Controller, :public_timeline + get "/statuses/public_and_external_timeline", TwitterAPI.Controller, :public_and_external_timeline get "/statuses/user_timeline", TwitterAPI.Controller, :user_timeline get "/statuses/show/:id", TwitterAPI.Controller, :fetch_status diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index e6f5fc906..b1759a6f0 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -84,6 +84,12 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do end def fetch_public_statuses(user, opts \\ %{}) do + opts = Map.put(opts, "local_only", true) + ActivityPub.fetch_public_activities(opts) + |> activities_to_statuses(%{for: user}) + end + + def fetch_public_and_external_statuses(user, opts \\ %{}) do ActivityPub.fetch_public_activities(opts) |> activities_to_statuses(%{for: user}) end diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index b5b829ca0..4b329a21f 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -41,6 +41,14 @@ defmodule Pleroma.Web.TwitterAPI.Controller do end end + def public_and_external_timeline(%{assigns: %{user: user}} = conn, params) do + statuses = TwitterAPI.fetch_public_and_external_statuses(user, params) + {:ok, json} = Poison.encode(statuses) + + conn + |> json_reply(200, json) + end + def public_timeline(%{assigns: %{user: user}} = conn, params) do statuses = TwitterAPI.fetch_public_statuses(user, params) {:ok, json} = Poison.encode(statuses) -- cgit v1.2.3 From 16f8406eb60562b961536ecfabecde8e15160aa6 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 2 May 2017 14:36:04 +0200 Subject: Add statusnet_profile_url to the TwAPI. --- lib/pleroma/web/twitter_api/representers/user_representer.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/representers/user_representer.ex b/lib/pleroma/web/twitter_api/representers/user_representer.ex index 29c7451f4..493077413 100644 --- a/lib/pleroma/web/twitter_api/representers/user_representer.ex +++ b/lib/pleroma/web/twitter_api/representers/user_representer.ex @@ -28,7 +28,8 @@ defmodule Pleroma.Web.TwitterAPI.Representers.UserRepresenter do "profile_image_url_https" => image, "profile_image_url_profile_size" => image, "profile_image_url_original" => image, - "rights" => %{} + "rights" => %{}, + "statusnet_profile_url" => user.ap_id } map -- cgit v1.2.3 From a3e82c5c246a4852d7bfaa5f6e216145b89fe0d8 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 2 May 2017 15:54:14 +0200 Subject: Save context in likes / announces. --- lib/pleroma/web/activity_pub/activity_pub.ex | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 0fb8db520..e9de3573e 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -55,7 +55,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do "type" => "Like", "actor" => ap_id, "object" => id, - "to" => [User.ap_followers(user), object.data["actor"]] + "to" => [User.ap_followers(user), object.data["actor"]], + "context" => object.data["context"] } {:ok, activity} = insert(data) @@ -177,7 +178,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do "type" => "Announce", "actor" => ap_id, "object" => id, - "to" => [User.ap_followers(user), object.data["actor"]] + "to" => [User.ap_followers(user), object.data["actor"]], + "context" => object.data["context"] } {:ok, activity} = insert(data) -- cgit v1.2.3 From 93de6039667b9fe6f3b9019c4c2297d4f23b3a1a Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 2 May 2017 16:35:53 +0200 Subject: Add an ostatus representer for like activities. --- lib/pleroma/web/ostatus/activity_representer.ex | 45 ++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex index c64bb3a3b..cf6aae727 100644 --- a/lib/pleroma/web/ostatus/activity_representer.ex +++ b/lib/pleroma/web/ostatus/activity_representer.ex @@ -10,11 +10,17 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do defp get_in_reply_to(_), do: [] defp get_mentions(to) do - Enum.map(to, fn - ("https://www.w3.org/ns/activitystreams#Public") -> - {:link, [rel: "mentioned", "ostatus:object-type": "http://activitystrea.ms/schema/1.0/collection", href: "http://activityschema.org/collection/public"], []} - (id) -> - {:link, [rel: "mentioned", "ostatus:object-type": "http://activitystrea.ms/schema/1.0/person", href: id], []} + Enum.map(to, fn (id) -> + cond do + # Special handling for the AP/Ostatus public collections + "https://www.w3.org/ns/activitystreams#Public" == id -> + {:link, [rel: "mentioned", "ostatus:object-type": "http://activitystrea.ms/schema/1.0/collection", href: "http://activityschema.org/collection/public"], []} + # Ostatus doesn't handle follower collections, ignore these. + Regex.match?(~r/^#{Pleroma.Web.base_url}.+followers$/, id) -> + [] + true -> + {:link, [rel: "mentioned", "ostatus:object-type": "http://activitystrea.ms/schema/1.0/person", href: id], []} + end end) end @@ -49,6 +55,35 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do ] ++ attachments ++ in_reply_to ++ author ++ mentions end + def to_simple_form(%{data: %{"type" => "Like"}} = activity, user, with_author) do + h = fn(str) -> [to_charlist(str)] end + + updated_at = activity.updated_at + |> NaiveDateTime.to_iso8601 + inserted_at = activity.inserted_at + |> NaiveDateTime.to_iso8601 + + in_reply_to = get_in_reply_to(activity.data) + author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: [] + mentions = activity.data["to"] |> get_mentions + + [ + {:"activity:verb", ['http://activitystrea.ms/schema/1.0/favorite']}, + {:id, h.(activity.data["id"])}, + {:title, ['New favorite by #{user.nickname}']}, + {:content, [type: 'html'], ['#{user.nickname} favorited something']}, + {:published, h.(inserted_at)}, + {:updated, h.(updated_at)}, + {:"activity:object", [ + {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/note']}, + {:id, h.(activity.data["object"])}, # For notes, federate the object id. + ]}, + {:"ostatus:conversation", [], h.(activity.data["context"])}, + {:link, [href: h.(activity.data["context"]), rel: 'ostatus:conversation'], []}, + {:"thr:in-reply-to", [ref: to_charlist(activity.data["object"])], []} + ] ++ author ++ mentions + end + def wrap_with_entry(simple_form) do [{ :entry, [ -- cgit v1.2.3 From 945b4b55e651341ae9452c9799f432ec2de11787 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 2 May 2017 16:45:54 +0200 Subject: Federate likes. --- lib/pleroma/web/activity_pub/activity_pub.ex | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index e9de3573e..12d6912df 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -72,6 +72,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do update_object_in_activities(object) + if user.local do + Pleroma.Web.Federator.enqueue(:publish, activity) + end + {:ok, activity, object} end end -- cgit v1.2.3 From 102455bf296165a88578a04f0ded259c32349d7f Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 2 May 2017 17:13:41 +0200 Subject: Add avatar updating from incoming messages. --- lib/pleroma/web/ostatus/ostatus.ex | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index db32d2c35..4c72e9cd1 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -90,6 +90,19 @@ defmodule Pleroma.Web.OStatus do end end + def find_make_or_update_user(doc) do + uri = string_from_xpath("//author/uri[1]", doc) + with {:ok, user} <- find_or_make_user(uri) do + avatar = make_avatar_object(doc) + if user.avatar != avatar do + change = Ecto.Changeset.change(user, %{avatar: avatar}) + Repo.update(change) + else + {:ok, user} + end + end + end + def find_or_make_user(uri) do query = from user in User, where: user.local == false and fragment("? @> ?", user.info, ^%{uri: uri}) @@ -121,8 +134,8 @@ defmodule Pleroma.Web.OStatus do # TODO: Just takes the first one for now. def make_avatar_object(author_doc) do - href = string_from_xpath("/feed/author[1]/link[@rel=\"avatar\"]/@href", author_doc) - type = string_from_xpath("/feed/author[1]/link[@rel=\"avatar\"]/@type", author_doc) + href = string_from_xpath("//author[1]/link[@rel=\"avatar\"]/@href", author_doc) + type = string_from_xpath("//author[1]/link[@rel=\"avatar\"]/@type", author_doc) if href do %{ -- cgit v1.2.3 From 96014f8e0b7bc6b28170f06914ef646f3f22ecfc Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 2 May 2017 17:16:01 +0200 Subject: Update incoming new avatars. --- lib/pleroma/web/ostatus/ostatus.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 4c72e9cd1..340228dcf 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -42,8 +42,8 @@ defmodule Pleroma.Web.OStatus do def handle_note(entry, doc \\ nil) do content_html = string_from_xpath("/entry/content[1]", entry) - uri = string_from_xpath("/entry/author/uri[1]", entry) || string_from_xpath("/feed/author/uri[1]", doc) - {:ok, actor} = find_or_make_user(uri) + [author] = :xmerl_xpath.string('//author[1]', doc) + {:ok, actor} = find_make_or_update_user(author) context = (string_from_xpath("/entry/ostatus:conversation[1]", entry) || "") |> String.trim context = if String.length(context) > 0 do -- cgit v1.2.3 From b104348fa52c6ea51b9a159b145a48ca74a22332 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 2 May 2017 17:44:55 +0200 Subject: Follow webfinger redirects. --- lib/pleroma/web/web_finger/web_finger.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index 402184d3f..d16bdd982 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -92,7 +92,7 @@ defmodule Pleroma.Web.WebFinger do 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]]) + getter.("http:" <> address, ["Accept": "application/xrd+xml"], [params: [resource: account], follow_redirect: true]) end with {:ok, %{status_code: status_code, body: body}} when status_code in 200..299 <- response, -- cgit v1.2.3 From 33c803d6da91e0253a100cbd480d253706c44964 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 2 May 2017 18:25:39 +0200 Subject: Add attachment link to posts. --- lib/pleroma/web/twitter_api/twitter_api.ex | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index b1759a6f0..7656d4d33 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -32,11 +32,23 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do def get_replied_to_activity(_), do: nil + def add_attachments(text, attachments) do + attachment_text = Enum.map(attachments, fn + (%{"url" => [%{"href" => href} | _]}) -> + "#{href}" + _ -> "" + end) + Enum.join([text | attachment_text], "
") + end + def create_status(user = %User{}, data = %{"status" => status}) do attachments = attachments_from_ids(data["media_ids"]) context = ActivityPub.generate_context_id mentions = parse_mentions(status) - content_html = format_input(status, mentions) + content_html = status + |> format_input(mentions) + |> add_attachments(attachments) + to = to_for_user_and_mentions(user, mentions) date = make_date() -- cgit v1.2.3 From 018a1a390fdb72652c615c28ac36f1b9a6a84d82 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 2 May 2017 21:31:01 +0200 Subject: Use inReplyTo to find context. --- lib/pleroma/web/ostatus/ostatus.ex | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 340228dcf..7aa1ac4ac 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -44,13 +44,19 @@ defmodule Pleroma.Web.OStatus do [author] = :xmerl_xpath.string('//author[1]', doc) {:ok, actor} = find_make_or_update_user(author) + inReplyTo = string_from_xpath("/entry/thr:in-reply-to[1]/@ref", entry) context = (string_from_xpath("/entry/ostatus:conversation[1]", entry) || "") |> String.trim - context = if String.length(context) > 0 do - context - else - ActivityPub.generate_context_id - end + + context = with %{data: %{"context" => context}} <- Object.get_cached_by_ap_id(inReplyTo) do + context + else _e -> + if String.length(context) > 0 do + context + else + ActivityPub.generate_context_id + end + end to = [ "https://www.w3.org/ns/activitystreams#Public" @@ -74,8 +80,6 @@ defmodule Pleroma.Web.OStatus do "actor" => actor.ap_id } - inReplyTo = string_from_xpath("/entry/thr:in-reply-to[1]/@ref", entry) - object = if inReplyTo do Map.put(object, "inReplyTo", inReplyTo) else -- cgit v1.2.3 From 9c42453e068b683517f6a72602c08527222f8fea Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Wed, 3 May 2017 09:54:17 +0200 Subject: Return note objects as ostatus post activities. --- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- lib/pleroma/web/ostatus/ostatus_controller.ex | 15 +++++++++++++++ lib/pleroma/web/router.ex | 4 +++- 3 files changed, 19 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 12d6912df..194a5ec3d 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -126,7 +126,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end def generate_object_id do - generate_id("objects") + Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :object, Ecto.UUID.generate) end def generate_id(type) do diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 1c609f6f2..6a4199846 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -41,4 +41,19 @@ defmodule Pleroma.Web.OStatus.OStatusController do conn |> send_resp(200, "") end + + def object(conn, %{"uuid" => uuid}) do + IO.inspect(uuid) + id = o_status_url(conn, :object, uuid) + activity = Activity.get_create_activity_by_object_ap_id(id) + user = User.get_cached_by_ap_id(activity.data["actor"]) + + response = FeedRepresenter.to_simple_form(user, [activity], [user]) + |> :xmerl.export_simple(:xmerl_xml) + |> to_string + + conn + |> put_resp_content_type("application/atom+xml") + |> send_resp(200, response) + end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index b0c1dcd91..ac9d97e0f 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -73,6 +73,8 @@ defmodule Pleroma.Web.Router do scope "/", Pleroma.Web do pipe_through :ostatus + get "/objects/:uuid", OStatus.OStatusController, :object + get "/users/:nickname/feed", OStatus.OStatusController, :feed get "/users/:nickname", OStatus.OStatusController, :feed_redirect post "/users/:nickname/salmon", OStatus.OStatusController, :salmon_incoming @@ -96,5 +98,5 @@ end defmodule Fallback.RedirectController do use Pleroma.Web, :controller - def redirector(conn, _params), do: send_file(conn, 200, "priv/static/index.html") + def redirector(conn, _params), do: (if Mix.env != :test, do: send_file(conn, 200, "priv/static/index.html")) end -- cgit v1.2.3 From 16afea399d330c28de05c77649fe0540598ee8ec Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Wed, 3 May 2017 10:01:26 +0200 Subject: Just give out the entry, not the whole feed. --- lib/pleroma/web/ostatus/ostatus_controller.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 6a4199846..c6700ae78 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -2,7 +2,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do use Pleroma.Web, :controller alias Pleroma.{User, Activity} - alias Pleroma.Web.OStatus.FeedRepresenter + alias Pleroma.Web.OStatus.{FeedRepresenter, ActivityRepresenter} alias Pleroma.Repo alias Pleroma.Web.OStatus import Ecto.Query @@ -43,12 +43,12 @@ defmodule Pleroma.Web.OStatus.OStatusController do end def object(conn, %{"uuid" => uuid}) do - IO.inspect(uuid) id = o_status_url(conn, :object, uuid) activity = Activity.get_create_activity_by_object_ap_id(id) user = User.get_cached_by_ap_id(activity.data["actor"]) - response = FeedRepresenter.to_simple_form(user, [activity], [user]) + response = ActivityRepresenter.to_simple_form(activity, user, true) + |> ActivityRepresenter.wrap_with_entry |> :xmerl.export_simple(:xmerl_xml) |> to_string -- cgit v1.2.3 From 8141024259ee4bebd58d6ecd963f181aad420846 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Wed, 3 May 2017 14:26:49 +0200 Subject: Attachment parsing, better magic key fetching. --- lib/pleroma/web/ostatus/ostatus.ex | 35 +++++++++++++++++++++------ lib/pleroma/web/ostatus/ostatus_controller.ex | 2 +- lib/pleroma/web/salmon/salmon.ex | 15 +++++------- lib/pleroma/web/web.ex | 22 +---------------- lib/pleroma/web/web_finger/web_finger.ex | 12 ++++----- lib/pleroma/web/websub/websub.ex | 12 ++++----- 6 files changed, 48 insertions(+), 50 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 7aa1ac4ac..f81751a25 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -39,6 +39,24 @@ defmodule Pleroma.Web.OStatus do {:ok, activities} end + def get_attachments(entry) do + :xmerl_xpath.string('/entry/link[@rel="enclosure"]', entry) + |> Enum.map(fn (enclosure) -> + with href when not is_nil(href) <- string_from_xpath("/link/@href", enclosure), + type when not is_nil(type) <- string_from_xpath("/link/@type", enclosure) do + %{ + "type" => "Attachment", + "url" => [%{ + "type" => "Link", + "mediaType" => type, + "href" => href + }] + } + end + end) + |> Enum.filter(&(&1)) + end + def handle_note(entry, doc \\ nil) do content_html = string_from_xpath("/entry/content[1]", entry) @@ -48,6 +66,8 @@ defmodule Pleroma.Web.OStatus do context = (string_from_xpath("/entry/ostatus:conversation[1]", entry) || "") |> String.trim + attachments = get_attachments(entry) + context = with %{data: %{"context" => context}} <- Object.get_cached_by_ap_id(inReplyTo) do context else _e -> @@ -77,7 +97,8 @@ defmodule Pleroma.Web.OStatus do "content" => content_html, "published" => date, "context" => context, - "actor" => actor.ap_id + "actor" => actor.ap_id, + "attachment" => attachments } object = if inReplyTo do @@ -124,11 +145,11 @@ defmodule Pleroma.Web.OStatus do with {:ok, info} <- gather_user_info(uri) do data = %{ local: false, - name: info.name, - nickname: info.nickname <> "@" <> info.host, - ap_id: info.uri, + name: info["name"], + nickname: info["nickname"] <> "@" <> info["host"], + ap_id: info["uri"], info: info, - avatar: info.avatar + avatar: info["avatar"] } # TODO: Make remote user changeset # SHould enforce fqn nickname @@ -158,8 +179,8 @@ defmodule Pleroma.Web.OStatus do def gather_user_info(username) do with {:ok, webfinger_data} <- WebFinger.finger(username), - {:ok, feed_data} <- Websub.gather_feed_data(webfinger_data.topic) do - {:ok, Map.merge(webfinger_data, feed_data) |> Map.put(:fqn, username)} + {:ok, feed_data} <- Websub.gather_feed_data(webfinger_data["topic"]) do + {:ok, Map.merge(webfinger_data, feed_data) |> Map.put("fqn", username)} else e -> Logger.debug("Couldn't gather info for #{username}") {:error, e} diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index c6700ae78..1f2dedd30 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -33,7 +33,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do def salmon_incoming(conn, params) do {:ok, body, _conn} = read_body(conn) - magic_key = Pleroma.Web.Salmon.fetch_magic_key(body) + {:ok, magic_key} = Pleroma.Web.Salmon.fetch_magic_key(body) {:ok, doc} = Pleroma.Web.Salmon.decode_and_validate(magic_key, body) Pleroma.Web.OStatus.handle_incoming(doc) diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex index b4f214d46..f02cb11dc 100644 --- a/lib/pleroma/web/salmon/salmon.ex +++ b/lib/pleroma/web/salmon/salmon.ex @@ -24,16 +24,13 @@ defmodule Pleroma.Web.Salmon do [data, type, encoding, alg, sig] end - # TODO rewrite in with-stile - # Make it fetch the key from the saved user if there is one def fetch_magic_key(salmon) do - [data, _, _, _, _] = decode(salmon) - doc = XML.parse_document(data) - uri = XML.string_from_xpath("/entry/author[1]/uri", doc) - - {:ok, info} = Pleroma.Web.OStatus.gather_user_info(uri) - - info.magic_key + with [data, _, _, _, _] <- decode(salmon), + doc <- XML.parse_document(data), + uri when not is_nil(uri) <- XML.string_from_xpath("/entry/author[1]/uri", doc), + {:ok, %{info: %{"magic_key" => magic_key}}} <- Pleroma.Web.OStatus.find_or_make_user(uri) do + {:ok, magic_key} + end end def decode_and_validate(magickey, salmon) do diff --git a/lib/pleroma/web/web.ex b/lib/pleroma/web/web.ex index a81e3e6e1..ee7ee78e9 100644 --- a/lib/pleroma/web/web.ex +++ b/lib/pleroma/web/web.ex @@ -61,27 +61,7 @@ defmodule Pleroma.Web do apply(__MODULE__, which, []) end - def host do - settings = Application.get_env(:pleroma, Pleroma.Web.Endpoint) - settings - |> Keyword.fetch!(:url) - |> Keyword.fetch!(:host) - end - def base_url do - settings = Application.get_env(:pleroma, Pleroma.Web.Endpoint) - - host = host() - - protocol = settings |> Keyword.fetch!(:protocol) - - port_fragment = with {:ok, protocol_info} <- settings |> Keyword.fetch(String.to_atom(protocol)), - {:ok, port} <- protocol_info |> Keyword.fetch(:port) - do - ":#{port}" - else _e -> - "" - end - "#{protocol}://#{host}#{port_fragment}" + Pleroma.Web.Endpoint.url end end diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index d16bdd982..5fa69c2c8 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -16,7 +16,7 @@ defmodule Pleroma.Web.WebFinger do end def webfinger(resource) do - host = Pleroma.Web.host + host = Pleroma.Web.Endpoint.host regex = ~r/(acct:)?(?\w+)@#{host}/ with %{"username" => username} <- Regex.named_captures(regex, resource) do user = User.get_by_nickname(username) @@ -37,7 +37,7 @@ defmodule Pleroma.Web.WebFinger do { :XRD, %{xmlns: "http://docs.oasis-open.org/ns/xri/xrd-1.0"}, [ - {:Subject, "acct:#{user.nickname}@#{Pleroma.Web.host}"}, + {:Subject, "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host}"}, {:Alias, user.ap_id}, {:Link, %{rel: "http://schemas.google.com/g/2010#updates-from", type: "application/atom+xml", href: OStatus.feed_path(user)}}, {:Link, %{rel: "http://webfinger.net/rel/profile-page", type: "text/html", href: user.ap_id}}, @@ -72,10 +72,10 @@ defmodule Pleroma.Web.WebFinger do subject = XML.string_from_xpath("//Subject", doc) salmon = XML.string_from_xpath(~s{//Link[@rel="salmon"]/@href}, doc) data = %{ - magic_key: magic_key, - topic: topic, - subject: subject, - salmon: salmon + "magic_key" => magic_key, + "topic" => topic, + "subject" => subject, + "salmon" => salmon } {:ok, data} end diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index 546bfb5a4..e32fc8817 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -146,12 +146,12 @@ defmodule Pleroma.Web.Websub do avatar = OStatus.make_avatar_object(doc) {:ok, %{ - uri: uri, - hub: hub, - nickname: preferredUsername || name, - name: displayName || name, - host: URI.parse(uri).host, - avatar: avatar + "uri" => uri, + "hub" => hub, + "nickname" => preferredUsername || name, + "name" => displayName || name, + "host" => URI.parse(uri).host, + "avatar" => avatar }} else e -> {:error, e} -- cgit v1.2.3 From df71c142cfadaae8866303768bca00c343b8bed1 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Wed, 3 May 2017 16:08:24 +0200 Subject: Remove doubled 'to' recipients. --- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 194a5ec3d..f18f3df2e 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -24,7 +24,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do activity = %{ "type" => "Create", - "to" => to, + "to" => to |> Enum.uniq, "actor" => actor.ap_id, "object" => object, "published" => published, -- cgit v1.2.3 From 138641589dffc6ba69710ec15c690b50769f07b4 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Wed, 3 May 2017 17:39:12 +0200 Subject: OStatus announce representer. --- lib/pleroma/web/ostatus/activity_representer.ex | 33 ++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex index cf6aae727..9e3a9abcb 100644 --- a/lib/pleroma/web/ostatus/activity_representer.ex +++ b/lib/pleroma/web/ostatus/activity_representer.ex @@ -1,5 +1,5 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do - alias Pleroma.Activity + alias Pleroma.{Activity, User} alias Pleroma.Web.OStatus.UserRepresenter require Logger @@ -84,6 +84,37 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do ] ++ author ++ mentions end + def to_simple_form(%{data: %{"type" => "Announce"}} = activity, user, with_author) do + h = fn(str) -> [to_charlist(str)] end + + updated_at = activity.updated_at + |> NaiveDateTime.to_iso8601 + inserted_at = activity.inserted_at + |> NaiveDateTime.to_iso8601 + + in_reply_to = get_in_reply_to(activity.data) + author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: [] + + retweeted_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"]) + retweeted_user = User.get_cached_by_ap_id(retweeted_activity.data["actor"]) + + retweeted_xml = to_simple_form(retweeted_activity, retweeted_user) + + mentions = activity.data["to"] |> get_mentions + [ + {:"activity:verb", ['http://activitystrea.ms/schema/1.0/share']}, + {:id, h.(activity.data["id"])}, + {:title, ['#{user.nickname} repeated a notice']}, + {:content, [type: 'html'], ['RT #{retweeted_activity.data["object"]["content"]}']}, + {:published, h.(inserted_at)}, + {:updated, h.(updated_at)}, + {:"ostatus:conversation", [], h.(activity.data["context"])}, + {:link, [href: h.(activity.data["context"]), rel: 'ostatus:conversation'], []}, + {:"thr:in-reply-to", [ref: to_charlist(activity.data["object"])], []}, + {:"activity:object", retweeted_xml} + ] ++ mentions ++ author + end + def wrap_with_entry(simple_form) do [{ :entry, [ -- cgit v1.2.3 From 861a294cdae313c4c2edfc9840bf1083da0acd6e Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Wed, 3 May 2017 17:41:55 +0200 Subject: Add announce federation. --- lib/pleroma/web/activity_pub/activity_pub.ex | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index f18f3df2e..5583a1f41 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -199,6 +199,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do update_object_in_activities(object) + if user.local do + Pleroma.Web.Federator.enqueue(:publish, activity) + end + {:ok, activity, object} end -- cgit v1.2.3 From b34b046f16a44172ac96709dd0b6f5bced96d0b5 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Wed, 3 May 2017 17:51:36 +0200 Subject: Add user to announced status. --- lib/pleroma/web/ostatus/activity_representer.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex index 9e3a9abcb..d064b09ee 100644 --- a/lib/pleroma/web/ostatus/activity_representer.ex +++ b/lib/pleroma/web/ostatus/activity_representer.ex @@ -98,7 +98,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do retweeted_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"]) retweeted_user = User.get_cached_by_ap_id(retweeted_activity.data["actor"]) - retweeted_xml = to_simple_form(retweeted_activity, retweeted_user) + retweeted_xml = to_simple_form(retweeted_activity, retweeted_user, true) mentions = activity.data["to"] |> get_mentions [ -- cgit v1.2.3 From 5d7831ee3e1ff62c2e54fe47aa1a6cf3474e8578 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Wed, 3 May 2017 18:10:19 +0200 Subject: Add self links to federated statuses. --- lib/pleroma/web/ostatus/activity_representer.ex | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex index d064b09ee..dc7526598 100644 --- a/lib/pleroma/web/ostatus/activity_representer.ex +++ b/lib/pleroma/web/ostatus/activity_representer.ex @@ -51,7 +51,8 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do {:published, h.(inserted_at)}, {:updated, h.(updated_at)}, {:"ostatus:conversation", [], h.(activity.data["context"])}, - {:link, [href: h.(activity.data["context"]), rel: 'ostatus:conversation'], []} + {:link, [href: h.(activity.data["context"]), rel: 'ostatus:conversation'], []}, + {:link, [type: ['application/atom+xml'], href: h.(activity.data["object"]["id"]), rel: 'self'], []} ] ++ attachments ++ in_reply_to ++ author ++ mentions end @@ -80,6 +81,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do ]}, {:"ostatus:conversation", [], h.(activity.data["context"])}, {:link, [href: h.(activity.data["context"]), rel: 'ostatus:conversation'], []}, + {:link, [rel: 'self', type: ['application/atom+xml'], href: h.(activity.data["id"])], []}, {:"thr:in-reply-to", [ref: to_charlist(activity.data["object"])], []} ] ++ author ++ mentions end @@ -102,6 +104,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do mentions = activity.data["to"] |> get_mentions [ + {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/activity']}, {:"activity:verb", ['http://activitystrea.ms/schema/1.0/share']}, {:id, h.(activity.data["id"])}, {:title, ['#{user.nickname} repeated a notice']}, @@ -110,6 +113,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do {:updated, h.(updated_at)}, {:"ostatus:conversation", [], h.(activity.data["context"])}, {:link, [href: h.(activity.data["context"]), rel: 'ostatus:conversation'], []}, + {:link, [rel: 'self', type: ['application/atom+xml'], href: h.(activity.data["id"])], []}, {:"thr:in-reply-to", [ref: to_charlist(activity.data["object"])], []}, {:"activity:object", retweeted_xml} ] ++ mentions ++ author -- cgit v1.2.3 From 53d05af5b61771782af3946181cc3139f3897cca Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Wed, 3 May 2017 19:23:12 +0200 Subject: Fix Mastodon signature bug. --- lib/pleroma/web/websub/websub.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index e32fc8817..0d0d19c88 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -52,7 +52,7 @@ defmodule Pleroma.Web.Websub do end def sign(secret, doc) do - :crypto.hmac(:sha, secret, to_string(doc)) |> Base.encode16 + :crypto.hmac(:sha, secret, to_string(doc)) |> Base.encode16 |> String.downcase end def incoming_subscription_request(user, %{"hub.mode" => "subscribe"} = params) do -- cgit v1.2.3 From 1077c5c58d13325cd61893c609cad6505ad1d32e Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Wed, 3 May 2017 20:06:00 +0200 Subject: Remove reply-to for shares, mastodon gets confused. --- lib/pleroma/web/ostatus/activity_representer.ex | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex index dc7526598..41a42b7cb 100644 --- a/lib/pleroma/web/ostatus/activity_representer.ex +++ b/lib/pleroma/web/ostatus/activity_representer.ex @@ -114,7 +114,6 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do {:"ostatus:conversation", [], h.(activity.data["context"])}, {:link, [href: h.(activity.data["context"]), rel: 'ostatus:conversation'], []}, {:link, [rel: 'self', type: ['application/atom+xml'], href: h.(activity.data["id"])], []}, - {:"thr:in-reply-to", [ref: to_charlist(activity.data["object"])], []}, {:"activity:object", retweeted_xml} ] ++ mentions ++ author end -- cgit v1.2.3 From 97257c692c5786b370d8f0769533d11c1d00334e Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Wed, 3 May 2017 20:06:20 +0200 Subject: Fix specs. --- lib/pleroma/web/websub/websub_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/websub/websub_controller.ex b/lib/pleroma/web/websub/websub_controller.ex index e5ecf6523..e860ec9e5 100644 --- a/lib/pleroma/web/websub/websub_controller.ex +++ b/lib/pleroma/web/websub/websub_controller.ex @@ -34,7 +34,7 @@ defmodule Pleroma.Web.Websub.WebsubController do def websub_incoming(conn, %{"id" => id}) do with "sha1=" <> signature <- hd(get_req_header(conn, "x-hub-signature")), - signature <- String.upcase(signature), + signature <- String.downcase(signature), %WebsubClientSubscription{} = websub <- Repo.get(WebsubClientSubscription, id), {:ok, body, _conn} = read_body(conn), ^signature <- Websub.sign(websub.secret, body) do -- cgit v1.2.3 From 151da344beca98b2c007397cb0f8e47510bf747a Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Thu, 4 May 2017 09:54:22 +0200 Subject: Add debugging logs. --- lib/pleroma/web/websub/websub.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index 0d0d19c88..c1532b6ce 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -44,6 +44,7 @@ defmodule Pleroma.Web.Websub do |> to_string signature = sign(sub.secret, response) + Logger.debug("Pushing to #{sub.callback}") HTTPoison.post(sub.callback, response, [ {"Content-Type", "application/atom+xml"}, {"X-Hub-Signature", "sha1=#{signature}"} -- cgit v1.2.3 From 5d9f3df714fa986367e105c2267324c8478ccf9c Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Thu, 4 May 2017 09:57:11 +0200 Subject: Just sign with an empty string if needed. --- lib/pleroma/web/websub/websub.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index c1532b6ce..ba86db50e 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -43,7 +43,7 @@ defmodule Pleroma.Web.Websub do |> :xmerl.export_simple(:xmerl_xml) |> to_string - signature = sign(sub.secret, response) + signature = sign(sub.secret || "", response) Logger.debug("Pushing to #{sub.callback}") HTTPoison.post(sub.callback, response, [ {"Content-Type", "application/atom+xml"}, -- cgit v1.2.3 From c85998ab8a21f042ab57345a7baa9e1e27c308d1 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Thu, 4 May 2017 18:42:29 +0200 Subject: Parse incoming retweets. --- lib/pleroma/web/activity_pub/activity_pub.ex | 4 +-- lib/pleroma/web/ostatus/ostatus.ex | 50 ++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 15 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 5583a1f41..1816b2e66 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -177,7 +177,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> Enum.reverse end - def announce(%User{ap_id: ap_id} = user, %Object{data: %{"id" => id}} = object) do + def announce(%User{ap_id: ap_id} = user, %Object{data: %{"id" => id}} = object, local \\ true) do data = %{ "type" => "Announce", "actor" => ap_id, @@ -186,7 +186,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do "context" => object.data["context"] } - {:ok, activity} = insert(data) + {:ok, activity} = insert(data, local) announcements = [ap_id | (object.data["announcements"] || [])] |> Enum.uniq diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index f81751a25..2fab67663 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -25,20 +25,44 @@ defmodule Pleroma.Web.OStatus do activities = Enum.map(entries, fn (entry) -> {:xmlObj, :string, object_type } = :xmerl_xpath.string('string(/entry/activity:object-type[1])', entry) + {:xmlObj, :string, verb } = :xmerl_xpath.string('string(/entry/activity:verb[1])', entry) - case object_type do - 'http://activitystrea.ms/schema/1.0/note' -> - with {:ok, activity} <- handle_note(entry, doc), do: activity - 'http://activitystrea.ms/schema/1.0/comment' -> - with {:ok, activity} <- handle_note(entry, doc), do: activity + case verb do + 'http://activitystrea.ms/schema/1.0/share' -> + with {:ok, activity, retweeted_activity} <- handle_share(entry, doc), do: [activity, retweeted_activity] _ -> - Logger.error("Couldn't parse incoming document") - nil + case object_type do + 'http://activitystrea.ms/schema/1.0/note' -> + with {:ok, activity} <- handle_note(entry, doc), do: activity + 'http://activitystrea.ms/schema/1.0/comment' -> + with {:ok, activity} <- handle_note(entry, doc), do: activity + _ -> + Logger.error("Couldn't parse incoming document") + nil + end end end) {:ok, activities} end + def make_share(entry, doc, retweeted_activity) do + with {:ok, actor} <- find_make_or_update_user(doc), + %Object{} = object <- Object.get_cached_by_ap_id(retweeted_activity.data["object"]["id"]), + {:ok, activity, object} = ActivityPub.announce(actor, object, false) do + {:ok, activity} + end + end + + def handle_share(entry, doc) do + with [object] <- :xmerl_xpath.string('/entry/activity:object', entry), + {:ok, retweeted_activity} <- handle_note(object, object), + {:ok, activity} <- make_share(entry, doc, retweeted_activity) do + {:ok, activity, retweeted_activity} + else + e -> {:error, e} + end + end + def get_attachments(entry) do :xmerl_xpath.string('/entry/link[@rel="enclosure"]', entry) |> Enum.map(fn (enclosure) -> @@ -58,13 +82,13 @@ defmodule Pleroma.Web.OStatus do end def handle_note(entry, doc \\ nil) do - content_html = string_from_xpath("/entry/content[1]", entry) + content_html = string_from_xpath("//content[1]", entry) [author] = :xmerl_xpath.string('//author[1]', doc) {:ok, actor} = find_make_or_update_user(author) - inReplyTo = string_from_xpath("/entry/thr:in-reply-to[1]/@ref", entry) + inReplyTo = string_from_xpath("//thr:in-reply-to[1]/@ref", entry) - context = (string_from_xpath("/entry/ostatus:conversation[1]", entry) || "") |> String.trim + context = (string_from_xpath("//ostatus:conversation[1]", entry) || "") |> String.trim attachments = get_attachments(entry) @@ -82,13 +106,13 @@ defmodule Pleroma.Web.OStatus do "https://www.w3.org/ns/activitystreams#Public" ] - mentions = :xmerl_xpath.string('/entry/link[@rel="mentioned" and @ostatus:object-type="http://activitystrea.ms/schema/1.0/person"]', entry) + mentions = :xmerl_xpath.string('//link[@rel="mentioned" and @ostatus:object-type="http://activitystrea.ms/schema/1.0/person"]', entry) |> Enum.map(fn(person) -> string_from_xpath("@href", person) end) to = to ++ mentions - date = string_from_xpath("/entry/published", entry) - id = string_from_xpath("/entry/id", entry) + date = string_from_xpath("//published", entry) + id = string_from_xpath("//id", entry) object = %{ "id" => id, -- cgit v1.2.3