diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/mix/tasks/pleroma/instance.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/activity.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/http/http.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/notification.ex | 5 | ||||
| -rw-r--r-- | lib/pleroma/object.ex | 22 | ||||
| -rw-r--r-- | lib/pleroma/object_tombstone.ex | 4 | ||||
| -rw-r--r-- | lib/pleroma/user.ex | 55 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub.ex | 15 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub_controller.ex | 62 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/views/user_view.ex | 47 | ||||
| -rw-r--r-- | lib/pleroma/web/common_api/common_api.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 6 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/views/account_view.ex | 84 | ||||
| -rw-r--r-- | lib/pleroma/web/nodeinfo/nodeinfo_controller.ex | 3 | ||||
| -rw-r--r-- | lib/pleroma/web/router.ex | 23 | ||||
| -rw-r--r-- | lib/pleroma/web/salmon/salmon.ex | 18 | ||||
| -rw-r--r-- | lib/pleroma/web/twitter_api/controllers/util_controller.ex | 29 | ||||
| -rw-r--r-- | lib/pleroma/web/twitter_api/twitter_api_controller.ex | 19 | ||||
| -rw-r--r-- | lib/pleroma/web/twitter_api/views/user_view.ex | 55 | 
19 files changed, 355 insertions, 100 deletions
| diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex index 1ef40671c..0a2c891c0 100644 --- a/lib/mix/tasks/pleroma/instance.ex +++ b/lib/mix/tasks/pleroma/instance.ex @@ -75,7 +75,7 @@ defmodule Mix.Tasks.Pleroma.Instance do        name =          Common.get_option(            options, -          :name, +          :instance_name,            "What is the name of your instance? (e.g. Pleroma/Soykaf)"          ) diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 34b665765..a14d1e8c6 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -7,6 +7,8 @@ defmodule Pleroma.Activity do    alias Pleroma.{Repo, Activity, Notification}    import Ecto.Query +  @type t :: %__MODULE__{} +    # https://github.com/tootsuite/mastodon/blob/master/app/models/notification.rb#L19    @mastodon_notification_types %{      "Create" => "mention", diff --git a/lib/pleroma/http/http.ex b/lib/pleroma/http/http.ex index e572dfedf..32d9cf5aa 100644 --- a/lib/pleroma/http/http.ex +++ b/lib/pleroma/http/http.ex @@ -10,6 +10,8 @@ defmodule Pleroma.HTTP do    alias Pleroma.HTTP.Connection    alias Pleroma.HTTP.RequestBuilder, as: Builder +  @type t :: __MODULE__ +    @doc """    Builds and perform http request. diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 301cfd134..b5aadfd17 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -80,9 +80,8 @@ defmodule Pleroma.Notification do    end    def clear(user) do -    query = from(n in Notification, where: n.user_id == ^user.id) - -    Repo.delete_all(query) +    from(n in Notification, where: n.user_id == ^user.id) +    |> Repo.delete_all()    end    def dismiss(%{id: user_id} = _user, id) do diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 99c836309..9a6c256df 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -4,7 +4,8 @@  defmodule Pleroma.Object do    use Ecto.Schema -  alias Pleroma.{Repo, Object, User, Activity, HTML} +  alias Pleroma.{Repo, Object, User, Activity, HTML, ObjectTombstone} +  alias Pleroma.{Repo, Object, User, Activity, ObjectTombstone}    import Ecto.{Query, Changeset}    schema "objects" do @@ -66,8 +67,25 @@ defmodule Pleroma.Object do      Object.change(%Object{}, %{data: %{"id" => context}})    end +  def make_tombstone(%Object{data: %{"id" => id, "type" => type}}, deleted \\ DateTime.utc_now()) do +    %ObjectTombstone{ +      id: id, +      formerType: type, +      deleted: deleted +    } +    |> Map.from_struct() +  end + +  def swap_object_with_tombstone(object) do +    tombstone = make_tombstone(object) + +    object +    |> Object.change(%{data: tombstone}) +    |> Repo.update() +  end +    def delete(%Object{data: %{"id" => id}} = object) do -    with Repo.delete(object), +    with {:ok, _obj} = swap_object_with_tombstone(object),           Repo.delete_all(Activity.all_non_create_by_object_ap_id_q(id)),           {:ok, true} <- Cachex.del(:object_cache, "object:#{id}") do        {:ok, object} diff --git a/lib/pleroma/object_tombstone.ex b/lib/pleroma/object_tombstone.ex new file mode 100644 index 000000000..64d836d3e --- /dev/null +++ b/lib/pleroma/object_tombstone.ex @@ -0,0 +1,4 @@ +defmodule Pleroma.ObjectTombstone do +  @enforce_keys [:id, :formerType, :deleted] +  defstruct [:id, :formerType, :deleted, type: "Tombstone"] +end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index b0b65cbe2..b90a3efae 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -13,6 +13,8 @@ defmodule Pleroma.User do    alias Pleroma.Web.{OStatus, Websub, OAuth}    alias Pleroma.Web.ActivityPub.{Utils, ActivityPub} +  require Logger +    @type t :: %__MODULE__{}    @email_regex ~r/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ @@ -47,6 +49,14 @@ defmodule Pleroma.User do        !Pleroma.Config.get([:instance, :account_activation_required])    end +  def remote_or_auth_active?(%User{} = user), do: !user.local || auth_active?(user) + +  def visible_for?(%User{} = user, for_user \\ nil) do +    User.remote_or_auth_active?(user) || (for_user && for_user.id == user.id) || +      User.superuser?(for_user) +  end + +  def superuser?(nil), do: false    def superuser?(%User{} = user), do: user.info && User.Info.superuser?(user.info)    def avatar_url(user) do @@ -197,6 +207,7 @@ defmodule Pleroma.User do        |> validate_confirmation(:password)        |> unique_constraint(:email)        |> unique_constraint(:nickname) +      |> validate_exclusion(:nickname, Pleroma.Config.get([Pleroma.User, :restricted_nicknames]))        |> validate_format(:nickname, local_nickname_regex())        |> validate_format(:email, @email_regex)        |> validate_length(:bio, max: 1000) @@ -330,6 +341,24 @@ defmodule Pleroma.User do      Enum.member?(follower.following, followed.follower_address)    end +  def follow_import(%User{} = follower, followed_identifiers) +      when is_list(followed_identifiers) do +    Enum.map( +      followed_identifiers, +      fn followed_identifier -> +        with %User{} = followed <- get_or_fetch(followed_identifier), +             {:ok, follower} <- maybe_direct_follow(follower, followed), +             {:ok, _} <- ActivityPub.follow(follower, followed) do +          followed +        else +          err -> +            Logger.debug("follow_import failed for #{followed_identifier} with: #{inspect(err)}") +            err +        end +      end +    ) +  end +    def locked?(%User{} = user) do      user.info.locked || false    end @@ -366,7 +395,11 @@ defmodule Pleroma.User do    end    def get_by_nickname(nickname) do -    Repo.get_by(User, nickname: nickname) +    Repo.get_by(User, nickname: nickname) || +      if Regex.match?(~r(@#{Pleroma.Web.Endpoint.host()})i, nickname) do +        [local_nickname, _] = String.split(nickname, "@") +        Repo.get_by(User, nickname: local_nickname) +      end    end    def get_by_nickname_or_email(nickname_or_email) do @@ -595,6 +628,23 @@ defmodule Pleroma.User do      Repo.all(q)    end +  def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers) do +    Enum.map( +      blocked_identifiers, +      fn blocked_identifier -> +        with %User{} = blocked <- get_or_fetch(blocked_identifier), +             {:ok, blocker} <- block(blocker, blocked), +             {:ok, _} <- ActivityPub.block(blocker, blocked) do +          blocked +        else +          err -> +            Logger.debug("blocks_import failed for #{blocked_identifier} with: #{inspect(err)}") +            err +        end +      end +    ) +  end +    def block(blocker, %User{ap_id: ap_id} = blocked) do      # sever any follow relationships to prevent leaks per activitypub (Pleroma issue #213)      blocker = @@ -648,6 +698,9 @@ defmodule Pleroma.User do        end)    end +  def blocked_users(user), +    do: Repo.all(from(u in User, where: u.ap_id in ^user.info.blocks)) +    def block_domain(user, domain) do      info_cng =        user.info diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 188060780..167471b7b 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -56,10 +56,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do      end    end +  defp check_remote_limit(%{"object" => %{"content" => content}}) do +    limit = Pleroma.Config.get([:instance, :remote_limit]) +    String.length(content) <= limit +  end + +  defp check_remote_limit(_), do: true +    def insert(map, local \\ true) when is_map(map) do      with nil <- Activity.normalize(map),           map <- lazy_put_activity_defaults(map),           :ok <- check_actor_is_active(map["actor"]), +         {_, true} <- {:remote_limit_error, check_remote_limit(map)},           {:ok, map} <- MRF.filter(map),           :ok <- insert_full_object(map) do        {recipients, _, _} = get_recipients(map) @@ -503,6 +511,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do    defp restrict_replies(query, _), do: query +  defp restrict_reblogs(query, %{"exclude_reblogs" => val}) when val == "true" or val == "1" do +    from(activity in query, where: fragment("?->>'type' != 'Announce'", activity.data)) +  end + +  defp restrict_reblogs(query, _), do: query +    # Only search through last 100_000 activities by default    defp restrict_recent(query, %{"whole_db" => true}), do: query @@ -561,6 +575,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do      |> restrict_media(opts)      |> restrict_visibility(opts)      |> restrict_replies(opts) +    |> restrict_reblogs(opts)    end    def fetch_activities(recipients, opts \\ %{}) do diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 7fd6a45f5..e41b14afc 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -4,11 +4,12 @@  defmodule Pleroma.Web.ActivityPub.ActivityPubController do    use Pleroma.Web, :controller -  alias Pleroma.{User, Object} +  alias Pleroma.{Activity, User, Object}    alias Pleroma.Web.ActivityPub.{ObjectView, UserView}    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.ActivityPub.Relay    alias Pleroma.Web.ActivityPub.Utils +  alias Pleroma.Web.ActivityPub.Transmogrifier    alias Pleroma.Web.Federator    require Logger @@ -93,19 +94,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do      end    end -  def outbox(conn, %{"nickname" => nickname, "max_id" => max_id}) do +  def outbox(conn, %{"nickname" => nickname} = params) do      with %User{} = user <- User.get_cached_by_nickname(nickname),           {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do        conn        |> put_resp_header("content-type", "application/activity+json") -      |> json(UserView.render("outbox.json", %{user: user, max_id: max_id})) +      |> json(UserView.render("outbox.json", %{user: user, max_id: params["max_id"]}))      end    end -  def outbox(conn, %{"nickname" => nickname}) do -    outbox(conn, %{"nickname" => nickname, "max_id" => nil}) -  end -    def inbox(%{assigns: %{valid_signature: true}} = conn, %{"nickname" => nickname} = params) do      with %User{} = user <- User.get_cached_by_nickname(nickname),           true <- Utils.recipient_in_message(user.ap_id, params), @@ -156,6 +153,57 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do      end    end +  def read_inbox(%{assigns: %{user: user}} = conn, %{"nickname" => nickname} = params) do +    if nickname == user.nickname do +      conn +      |> put_resp_header("content-type", "application/activity+json") +      |> json(UserView.render("inbox.json", %{user: user, max_id: params["max_id"]})) +    else +      conn +      |> put_status(:forbidden) +      |> json("can't read inbox of #{nickname} as #{user.nickname}") +    end +  end + +  def update_outbox( +        %{assigns: %{user: user}} = conn, +        %{"nickname" => nickname, "type" => "Create"} = params +      ) do +    if nickname == user.nickname do +      actor = user.ap_id() + +      params = +        params +        |> Map.drop(["id"]) +        |> Map.put("actor", actor) +        |> Transmogrifier.fix_addressing() + +      object = +        params["object"] +        |> Map.merge(Map.take(params, ["to", "cc"])) +        |> Map.put("attributedTo", actor) +        |> Transmogrifier.fix_object() + +      with {:ok, %Activity{} = activity} <- +             ActivityPub.create(%{ +               to: params["to"], +               actor: user, +               context: object["context"], +               object: object, +               additional: Map.take(params, ["cc"]) +             }) do +        conn +        |> put_status(:created) +        |> put_resp_header("location", activity.data["id"]) +        |> json(activity.data) +      end +    else +      conn +      |> put_status(:forbidden) +      |> json("can't update outbox of #{nickname} as #{user.nickname}") +    end +  end +    def errors(conn, {:error, :not_found}) do      conn      |> put_status(404) diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index f0c268755..439d834e4 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -176,6 +176,53 @@ defmodule Pleroma.Web.ActivityPub.UserView do      end    end +  def render("inbox.json", %{user: user, max_id: max_qid}) do +    params = %{ +      "limit" => "10" +    } + +    params = +      if max_qid != nil do +        Map.put(params, "max_id", max_qid) +      else +        params +      end + +    activities = ActivityPub.fetch_activities([user.ap_id | user.following], params) + +    min_id = Enum.at(Enum.reverse(activities), 0).id +    max_id = Enum.at(activities, 0).id + +    collection = +      Enum.map(activities, fn act -> +        {:ok, data} = Transmogrifier.prepare_outgoing(act.data) +        data +      end) + +    iri = "#{user.ap_id}/inbox" + +    page = %{ +      "id" => "#{iri}?max_id=#{max_id}", +      "type" => "OrderedCollectionPage", +      "partOf" => iri, +      "totalItems" => -1, +      "orderedItems" => collection, +      "next" => "#{iri}?max_id=#{min_id - 1}" +    } + +    if max_qid == nil do +      %{ +        "id" => iri, +        "type" => "OrderedCollection", +        "totalItems" => -1, +        "first" => page +      } +      |> Map.merge(Utils.make_json_ld_header()) +    else +      page |> Map.merge(Utils.make_json_ld_header()) +    end +  end +    def collection(collection, iri, page, show_items \\ true, total \\ nil) do      offset = (page - 1) * 10      items = Enum.slice(collection, offset, 10) diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 5e5821561..085a95172 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -102,7 +102,7 @@ defmodule Pleroma.Web.CommonAPI do               attachments,               tags,               get_content_type(data["content_type"]), -             data["no_attachment_links"] +             Enum.member?([true, "true"], data["no_attachment_links"])             ),           context <- make_context(inReplyTo),           cw <- data["spoiler_text"], diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 22715bb76..663a0fa08 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -704,11 +704,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      end    end -  # TODO: Use proper query    def blocks(%{assigns: %{user: user}} = conn, _) do -    with blocked_users <- user.info.blocks || [], -         accounts <- Enum.map(blocked_users, fn ap_id -> User.get_cached_by_ap_id(ap_id) end) do -      res = AccountView.render("accounts.json", users: accounts, for: user, as: :user) +    with blocked_accounts <- User.blocked_users(user) do +      res = AccountView.render("accounts.json", users: blocked_accounts, for: user, as: :user)        json(conn, res)      end    end diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index aaaae2035..555383503 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -11,10 +11,55 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do    alias Pleroma.HTML    def render("accounts.json", %{users: users} = opts) do -    render_many(users, AccountView, "account.json", opts) +    users +    |> render_many(AccountView, "account.json", opts) +    |> Enum.filter(&Enum.any?/1)    end    def render("account.json", %{user: user} = opts) do +    if User.visible_for?(user, opts[:for]), +      do: do_render("account.json", opts), +      else: %{} +  end + +  def render("mention.json", %{user: user}) do +    %{ +      id: to_string(user.id), +      acct: user.nickname, +      username: username_from_nickname(user.nickname), +      url: user.ap_id +    } +  end + +  def render("relationship.json", %{user: user, target: target}) do +    follow_activity = Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(user, target) + +    requested = +      if follow_activity do +        follow_activity.data["state"] == "pending" +      else +        false +      end + +    %{ +      id: to_string(target.id), +      following: User.following?(user, target), +      followed_by: User.following?(target, user), +      blocking: User.blocks?(user, target), +      muting: false, +      muting_notifications: false, +      requested: requested, +      domain_blocking: false, +      showing_reblogs: false, +      endorsed: false +    } +  end + +  def render("relationships.json", %{user: user, targets: targets}) do +    render_many(targets, AccountView, "relationship.json", user: user, as: :target) +  end + +  defp do_render("account.json", %{user: user} = opts) do      image = User.avatar_url(user) |> MediaProxy.url()      header = User.banner_url(user) |> MediaProxy.url()      user_info = User.user_info(user) @@ -72,43 +117,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do      }    end -  def render("mention.json", %{user: user}) do -    %{ -      id: to_string(user.id), -      acct: user.nickname, -      username: username_from_nickname(user.nickname), -      url: user.ap_id -    } -  end - -  def render("relationship.json", %{user: user, target: target}) do -    follow_activity = Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(user, target) - -    requested = -      if follow_activity do -        follow_activity.data["state"] == "pending" -      else -        false -      end - -    %{ -      id: to_string(target.id), -      following: User.following?(user, target), -      followed_by: User.following?(target, user), -      blocking: User.blocks?(user, target), -      muting: false, -      muting_notifications: false, -      requested: requested, -      domain_blocking: false, -      showing_reblogs: false, -      endorsed: false -    } -  end - -  def render("relationships.json", %{user: user, targets: targets}) do -    render_many(targets, AccountView, "relationship.json", user: user, as: :target) -  end -    defp username_from_nickname(string) when is_binary(string) do      hd(String.split(string, "@"))    end diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex index 1265d81c5..a992f75f6 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex @@ -138,7 +138,8 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do          },          accountActivationRequired: Keyword.get(instance, :account_activation_required, false),          invitesEnabled: Keyword.get(instance, :invites_enabled, false), -        features: features +        features: features, +        restrictedNicknames: Pleroma.Config.get([Pleroma.User, :restricted_nicknames])        }      } diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 7ec0cabb3..33c573d46 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -137,6 +137,7 @@ defmodule Pleroma.Web.Router do    scope "/api/pleroma", Pleroma.Web.TwitterAPI do      pipe_through(:authenticated_api) +    post("/blocks_import", UtilController, :blocks_import)      post("/follow_import", UtilController, :follow_import)      post("/change_password", UtilController, :change_password)      post("/delete_account", UtilController, :delete_account) @@ -281,6 +282,7 @@ defmodule Pleroma.Web.Router do      get("/statuses/followers", TwitterAPI.Controller, :followers)      get("/statuses/friends", TwitterAPI.Controller, :friends) +    get("/statuses/blocks", TwitterAPI.Controller, :blocks)      get("/statuses/show/:id", TwitterAPI.Controller, :fetch_status)      get("/statusnet/conversation/:id", TwitterAPI.Controller, :fetch_conversation) @@ -410,6 +412,27 @@ defmodule Pleroma.Web.Router do      get("/users/:nickname/outbox", ActivityPubController, :outbox)    end +  pipeline :activitypub_client do +    plug(:accepts, ["activity+json"]) +    plug(:fetch_session) +    plug(Pleroma.Plugs.OAuthPlug) +    plug(Pleroma.Plugs.BasicAuthDecoderPlug) +    plug(Pleroma.Plugs.UserFetcherPlug) +    plug(Pleroma.Plugs.SessionAuthenticationPlug) +    plug(Pleroma.Plugs.LegacyAuthenticationPlug) +    plug(Pleroma.Plugs.AuthenticationPlug) +    plug(Pleroma.Plugs.UserEnabledPlug) +    plug(Pleroma.Plugs.SetUserSessionIdPlug) +    plug(Pleroma.Plugs.EnsureUserKeyPlug) +  end + +  scope "/", Pleroma.Web.ActivityPub do +    pipe_through([:activitypub_client]) + +    get("/users/:nickname/inbox", ActivityPubController, :read_inbox) +    post("/users/:nickname/outbox", ActivityPubController, :update_outbox) +  end +    scope "/relay", Pleroma.Web.ActivityPub do      pipe_through(:ap_relay)      get("/", ActivityPubController, :relay) diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex index 1dc514976..f7d2257eb 100644 --- a/lib/pleroma/web/salmon/salmon.ex +++ b/lib/pleroma/web/salmon/salmon.ex @@ -161,16 +161,21 @@ defmodule Pleroma.Web.Salmon do      |> Enum.filter(fn user -> user && !user.local end)    end -  defp send_to_user(%{info: %{salmon: salmon}}, feed, poster) do +  # push an activity to remote accounts +  # +  defp send_to_user(%{info: %{salmon: salmon}}, feed, poster), +    do: send_to_user(salmon, feed, poster) + +  defp send_to_user(url, feed, poster) when is_binary(url) do      with {:ok, %{status: code}} <-             poster.( -             salmon, +             url,               feed,               [{"Content-Type", "application/magic-envelope+xml"}]             ) do -      Logger.debug(fn -> "Pushed to #{salmon}, code #{code}" end) +      Logger.debug(fn -> "Pushed to #{url}, code #{code}" end)      else -      e -> Logger.debug(fn -> "Pushing Salmon to #{salmon} failed, #{inspect(e)}" end) +      e -> Logger.debug(fn -> "Pushing Salmon to #{url} failed, #{inspect(e)}" end)      end    end @@ -184,6 +189,11 @@ defmodule Pleroma.Web.Salmon do      "Undo",      "Delete"    ] + +  @doc """ +  Publishes an activity to remote accounts +  """ +  @spec publish(User.t(), Pleroma.Activity.t(), Pleroma.HTTP.t()) :: none    def publish(user, activity, poster \\ &@httpoison.post/3)    def publish(%{info: %{keys: keys}} = user, %{data: %{"type" => type}} = activity, poster) diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index c872aec2b..87b8b71ba 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -240,21 +240,22 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do      follow_import(conn, %{"list" => File.read!(listfile.path)})    end -  def follow_import(%{assigns: %{user: user}} = conn, %{"list" => list}) do -    Task.start(fn -> -      String.split(list) -      |> Enum.map(fn account -> -        with %User{} = follower <- User.get_cached_by_ap_id(user.ap_id), -             %User{} = followed <- User.get_or_fetch(account), -             {:ok, follower} <- User.maybe_direct_follow(follower, followed) do -          ActivityPub.follow(follower, followed) -        else -          err -> Logger.debug("follow_import: following #{account} failed with #{inspect(err)}") -        end -      end) -    end) +  def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do +    with followed_identifiers <- String.split(list), +         {:ok, _} = Task.start(fn -> User.follow_import(follower, followed_identifiers) end) do +      json(conn, "job started") +    end +  end -    json(conn, "job started") +  def blocks_import(conn, %{"list" => %Plug.Upload{} = listfile}) do +    blocks_import(conn, %{"list" => File.read!(listfile.path)}) +  end + +  def blocks_import(%{assigns: %{user: blocker}} = conn, %{"list" => list}) do +    with blocked_identifiers <- String.split(list), +         {:ok, _} = Task.start(fn -> User.blocks_import(blocker, blocked_identifiers) end) do +      json(conn, "job started") +    end    end    def change_password(%{assigns: %{user: user}} = conn, params) do diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index c25cb0876..aebc3bff4 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -130,6 +130,15 @@ defmodule Pleroma.Web.TwitterAPI.Controller do    def user_timeline(%{assigns: %{user: user}} = conn, params) do      case TwitterAPI.get_user(user, params) do        {:ok, target_user} -> +        # Twitter and ActivityPub use a different name and sense for this parameter. +        {include_rts, params} = Map.pop(params, "include_rts") + +        params = +          case include_rts do +            x when x == "false" or x == "0" -> Map.put(params, "exclude_reblogs", "true") +            _ -> params +          end +          activities = ActivityPub.fetch_user_activities(target_user, user, params)          conn @@ -498,6 +507,14 @@ defmodule Pleroma.Web.TwitterAPI.Controller do      end    end +  def blocks(%{assigns: %{user: user}} = conn, _params) do +    with blocked_users <- User.blocked_users(user) do +      conn +      |> put_view(UserView) +      |> render("index.json", %{users: blocked_users, for: user}) +    end +  end +    def friend_requests(conn, params) do      with {:ok, user} <- TwitterAPI.get_user(conn.assigns[:user], params),           {:ok, friend_requests} <- User.get_follow_requests(user) do @@ -653,7 +670,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do      json_reply(conn, 403, json)    end -  def only_if_public_instance(conn = %{conn: %{assigns: %{user: _user}}}, _), do: conn +  def only_if_public_instance(%{assigns: %{user: %User{}}} = conn, _), do: conn    def only_if_public_instance(conn, _) do      if Keyword.get(Application.get_env(:pleroma, :instance), :public) do diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex index 6e489624f..ede3c0d25 100644 --- a/lib/pleroma/web/twitter_api/views/user_view.ex +++ b/lib/pleroma/web/twitter_api/views/user_view.ex @@ -15,18 +15,44 @@ defmodule Pleroma.Web.TwitterAPI.UserView do    end    def render("index.json", %{users: users, for: user}) do -    render_many(users, Pleroma.Web.TwitterAPI.UserView, "user.json", for: user) +    users +    |> render_many(Pleroma.Web.TwitterAPI.UserView, "user.json", for: user) +    |> Enum.filter(&Enum.any?/1)    end    def render("user.json", %{user: user = %User{}} = assigns) do +    if User.visible_for?(user, assigns[:for]), +      do: do_render("user.json", assigns), +      else: %{} +  end + +  def render("short.json", %{ +        user: %User{ +          nickname: nickname, +          id: id, +          ap_id: ap_id, +          name: name +        } +      }) do +    %{ +      "fullname" => name, +      "id" => id, +      "ostatus_uri" => ap_id, +      "profile_url" => ap_id, +      "screen_name" => nickname +    } +  end + +  defp do_render("user.json", %{user: user = %User{}} = assigns) do +    for_user = assigns[:for]      image = User.avatar_url(user) |> MediaProxy.url()      {following, follows_you, statusnet_blocking} = -      if assigns[:for] do +      if for_user do          { -          User.following?(assigns[:for], user), -          User.following?(user, assigns[:for]), -          User.blocks?(assigns[:for], user) +          User.following?(for_user, user), +          User.following?(user, for_user), +          User.blocks?(for_user, user)          }        else          {false, false, false} @@ -51,7 +77,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do      data = %{        "created_at" => user.inserted_at |> Utils.format_naive_asctime(),        "description" => HTML.strip_tags((user.bio || "") |> String.replace("<br>", "\n")), -      "description_html" => HTML.filter_tags(user.bio, User.html_filter_policy(assigns[:for])), +      "description_html" => HTML.filter_tags(user.bio, User.html_filter_policy(for_user)),        "favourites_count" => 0,        "followers_count" => user_info[:follower_count],        "following" => following, @@ -97,23 +123,6 @@ defmodule Pleroma.Web.TwitterAPI.UserView do      end    end -  def render("short.json", %{ -        user: %User{ -          nickname: nickname, -          id: id, -          ap_id: ap_id, -          name: name -        } -      }) do -    %{ -      "fullname" => name, -      "id" => id, -      "ostatus_uri" => ap_id, -      "profile_url" => ap_id, -      "screen_name" => nickname -    } -  end -    defp image_url(%{"url" => [%{"href" => href} | _]}), do: href    defp image_url(_), do: nil | 
