diff options
29 files changed, 645 insertions, 9 deletions
| diff --git a/config/config.exs b/config/config.exs index 2b041b10f..18a2490a4 100644 --- a/config/config.exs +++ b/config/config.exs @@ -26,6 +26,10 @@ config :logger, :console,    format: "$time $metadata[$level] $message\n",    metadata: [:request_id] +config :mime, :types, %{ +  "application/xrd+xml" => ["xrd+xml"] +} +  # Import environment specific config. This must remain at the bottom  # of this file so it overrides the configuration defined above.  import_config "#{Mix.env}.exs" diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 3a4dd5d08..3ce07d510 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -19,6 +19,13 @@ defmodule Pleroma.User do      timestamps()    end +  def avatar_url(user) do +    case user.avatar do +      %{"url" => [%{"href" => href} | _]} -> href +      _ -> "https://placehold.it/48x48" +    end +  end +    def ap_id(%User{nickname: nickname}) do      "#{Pleroma.Web.base_url}/users/#{nickname}"    end diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index 6af42a685..45a3a345d 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -9,6 +9,9 @@ defmodule Pleroma.Web.Endpoint do    # when deploying your static files in production.    plug Plug.Static,      at: "/media", from: "uploads", gzip: false +  plug Plug.Static, +    at: "/", from: :pleroma, +    only: ~w(index.html static)    # Code reloading can be explicitly enabled under the    # :code_reloader configuration of your endpoint. diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex new file mode 100644 index 000000000..6f101109c --- /dev/null +++ b/lib/pleroma/web/ostatus/activity_representer.ex @@ -0,0 +1,20 @@ +defmodule Pleroma.Web.OStatus.ActivityRepresenter do +  def to_simple_form(%{data: %{"object" => %{"type" => "Note"}}} = activity, user) do +    h = fn(str) -> [to_charlist(str)] end + +    updated_at = activity.updated_at +    |> NaiveDateTime.to_iso8601 +    inserted_at = activity.inserted_at +    |> NaiveDateTime.to_iso8601 + +    [ +      {:"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"])}, +      {:title, ['New note by #{user.nickname}']}, +      {:content, [type: 'html'], h.(activity.data["object"]["content"])}, +      {:published, h.(inserted_at)}, +      {:updated, h.(updated_at)} +    ] +  end +end diff --git a/lib/pleroma/web/ostatus/feed_representer.ex b/lib/pleroma/web/ostatus/feed_representer.ex new file mode 100644 index 000000000..1576b4710 --- /dev/null +++ b/lib/pleroma/web/ostatus/feed_representer.ex @@ -0,0 +1,28 @@ +defmodule Pleroma.Web.OStatus.FeedRepresenter do +  alias Pleroma.Web.OStatus +  alias Pleroma.Web.OStatus.{UserRepresenter, ActivityRepresenter} + +  def to_simple_form(user, activities, users) do +    most_recent_update = List.first(activities).updated_at +    |> NaiveDateTime.to_iso8601 + +    h = fn(str) -> [to_charlist(str)] end + +    entries = Enum.map(activities, fn(activity) -> +      {:entry, ActivityRepresenter.to_simple_form(activity, user)} +    end) + +    [{ +      :feed, [ +        xmlns: 'http://www.w3.org/2005/Atom', +        "xmlns:activity": 'http://activitystrea.ms/spec/1.0/' +      ], [ +        {:id, h.(OStatus.feed_path(user))}, +        {:title, ['#{user.nickname}\'s timeline']}, +        {:updated, h.(most_recent_update)}, +        {:link, [rel: 'hub', href: h.(OStatus.pubsub_path(user))], []}, +        {:author, UserRepresenter.to_simple_form(user)} +      ] ++ entries +    }] +  end +end diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex new file mode 100644 index 000000000..d21b9078f --- /dev/null +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -0,0 +1,14 @@ +defmodule Pleroma.Web.OStatus do +  alias Pleroma.Web + +  def feed_path(user) do +    "#{user.ap_id}/feed.atom" +  end + +  def pubsub_path(user) do +    "#{Web.base_url}/push/hub/#{user.nickname}" +  end + +  def user_path(user) do +  end +end diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex new file mode 100644 index 000000000..4db4a55e6 --- /dev/null +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -0,0 +1,30 @@ +defmodule Pleroma.Web.OStatus.OStatusController do +  use Pleroma.Web, :controller + +  alias Pleroma.{User, Activity} +  alias Pleroma.Web.OStatus.FeedRepresenter +  alias Pleroma.Repo +  import Ecto.Query + +  def feed(conn, %{"nickname" => nickname}) do +    user = User.get_cached_by_nickname(nickname) +    query = from activity in Activity, +      where: fragment("? @> ?", activity.data, ^%{actor: user.ap_id}), +      limit: 20, +      order_by: [desc: :inserted_at] + +    activities = query +    |> Repo.all + +    response = FeedRepresenter.to_simple_form(user, activities, [user]) +    |> :xmerl.export_simple(:xmerl_xml) + +    conn +    |> put_resp_content_type("application/atom+xml") +    |> send_resp(200, response) +  end + +  def temp(conn, params) do +    IO.inspect(params) +  end +end diff --git a/lib/pleroma/web/ostatus/user_representer.ex b/lib/pleroma/web/ostatus/user_representer.ex new file mode 100644 index 000000000..e7ee4cfeb --- /dev/null +++ b/lib/pleroma/web/ostatus/user_representer.ex @@ -0,0 +1,15 @@ +defmodule Pleroma.Web.OStatus.UserRepresenter do +  alias Pleroma.User +  def to_simple_form(user) do +    ap_id = to_charlist(user.ap_id) +    nickname = to_charlist(user.nickname) +    avatar_url = to_charlist(User.avatar_url(user)) +    [ +      { :id, [ap_id] }, +      { :"activity:object", ['http://activitystrea.ms/schema/1.0/person'] }, +      { :uri, [ap_id] }, +      { :name, [nickname] }, +      { :link, [rel: 'avatar', href: avatar_url], []} +    ] +  end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 6a2b37aec..a4f13c879 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -19,6 +19,10 @@ defmodule Pleroma.Web.Router do      plug Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Pleroma.Web.Router.user_fetcher/1}    end +  pipeline :well_known do +    plug :accepts, ["xml", "xrd+xml"] +  end +    scope "/api", Pleroma.Web do      pipe_through :api @@ -61,4 +65,32 @@ defmodule Pleroma.Web.Router do      post "/qvitter/update_avatar", TwitterAPI.Controller, :update_avatar    end + +  pipeline :ostatus do +    plug :accepts, ["xml", "atom"] +  end + +  scope "/", Pleroma.Web do +    pipe_through :ostatus + +    get "/users/:nickname/feed", OStatus.OStatusController, :feed +    post "/push/hub/:nickname", Websub.WebsubController, :websub_subscription_request +  end + +  scope "/.well-known", Pleroma.Web do +    pipe_through :well_known + +    get "/host-meta", WebFinger.WebFingerController, :host_meta +    get "/webfinger", WebFinger.WebFingerController, :webfinger +  end + +  scope "/", Fallback do +    get "/*path", RedirectController, :redirector +  end + +end + +defmodule Fallback.RedirectController do +  use Pleroma.Web, :controller +  def redirector(conn, _params), do: send_file(conn, 200, "priv/static/index.html")  end diff --git a/lib/pleroma/web/twitter_api/representers/user_representer.ex b/lib/pleroma/web/twitter_api/representers/user_representer.ex index f358baf3c..ab7d6d353 100644 --- a/lib/pleroma/web/twitter_api/representers/user_representer.ex +++ b/lib/pleroma/web/twitter_api/representers/user_representer.ex @@ -4,11 +4,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.UserRepresenter do    alias Pleroma.User    def to_map(user, opts) do -    image = case user.avatar do -      %{"url" => [%{"href" => href} | _]} -> href -      _ -> "https://placehold.it/48x48" -    end - +    image = User.avatar_url(user)      following = if opts[:for] do        User.following?(opts[:for], user)      else diff --git a/lib/pleroma/web/web.ex b/lib/pleroma/web/web.ex index d03db2231..a81e3e6e1 100644 --- a/lib/pleroma/web/web.ex +++ b/lib/pleroma/web/web.ex @@ -61,12 +61,17 @@ 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 = -      settings -      |> Keyword.fetch!(:url) -      |> Keyword.fetch!(:host) + +    host = host()      protocol = settings |> Keyword.fetch!(:protocol) diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex new file mode 100644 index 000000000..eb540e92a --- /dev/null +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -0,0 +1,39 @@ +defmodule Pleroma.Web.WebFinger do +  alias Pleroma.XmlBuilder +  alias Pleroma.User +  alias Pleroma.Web.OStatus + +  def host_meta() do +    base_url  = Pleroma.Web.base_url +    { +      :XRD, %{ xmlns: "http://docs.oasis-open.org/ns/xri/xrd-1.0" }, +      { +        :Link, %{ rel: "lrdd", type: "application/xrd+xml", template: "#{base_url}/.well-known/webfinger?resource={uri}"  } +      } +    } +    |> XmlBuilder.to_doc +  end + +  def webfinger(resource) do +    host = Pleroma.Web.host +    regex = ~r/acct:(?<username>\w+)@#{host}/ +    case Regex.named_captures(regex, resource) do +      %{"username" => username} -> +        user = User.get_cached_by_nickname(username) +        {:ok, represent_user(user)} +      _ -> nil +    end +  end + +  def represent_user(user) do +    { +      :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)}} +      ] +    } +    |> XmlBuilder.to_doc +  end +end diff --git a/lib/pleroma/web/web_finger/web_finger_controller.ex b/lib/pleroma/web/web_finger/web_finger_controller.ex new file mode 100644 index 000000000..7c0fd3142 --- /dev/null +++ b/lib/pleroma/web/web_finger/web_finger_controller.ex @@ -0,0 +1,21 @@ +defmodule Pleroma.Web.WebFinger.WebFingerController do +  use Pleroma.Web, :controller + +  alias Pleroma.Web.WebFinger + +  def host_meta(conn, _params) do +    xml = WebFinger.host_meta + +    conn +    |> put_resp_content_type("application/xrd+xml") +    |> send_resp(200, xml) +  end + +  def webfinger(conn, %{"resource" => resource}) do +    {:ok, response} = Pleroma.Web.WebFinger.webfinger(resource) + +    conn +    |> put_resp_content_type("application/xrd+xml") +    |> send_resp(200, response) +  end +end diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex new file mode 100644 index 000000000..c7752487c --- /dev/null +++ b/lib/pleroma/web/websub/websub.ex @@ -0,0 +1,23 @@ +defmodule Pleroma.Web.Websub do +  alias Pleroma.Repo + +  def verify(subscription, getter \\ &HTTPoison.get/3 ) do +    challenge = Base.encode16(:crypto.strong_rand_bytes(8)) +    lease_seconds = NaiveDateTime.diff(subscription.inserted_at, subscription.valid_until) +    with {:ok, response} <- getter.(subscription.callback, [], [params: %{ +                                                              "hub.challenge": challenge, +                                                              "hub.lease_seconds": lease_seconds, +                                                              "hub.topic": subscription.topic, +                                                              "hub.mode": "subscribe" +                                                                }]), +         ^challenge <- response.body +    do +      changeset = Ecto.Changeset.change(subscription, %{state: "active"}) +      Repo.update(changeset) +    else _e -> +      changeset = Ecto.Changeset.change(subscription, %{state: "rejected"}) +      {:ok, subscription } = Repo.update(changeset) +      {:error, subscription} +    end +  end +end diff --git a/lib/pleroma/web/websub/websub_controller.ex b/lib/pleroma/web/websub/websub_controller.ex new file mode 100644 index 000000000..09305c337 --- /dev/null +++ b/lib/pleroma/web/websub/websub_controller.ex @@ -0,0 +1,48 @@ +defmodule Pleroma.Web.Websub.WebsubController do +  use Pleroma.Web, :controller +  alias Pleroma.Web.Websub.WebsubServerSubscription +  alias Pleroma.{Repo, User} +  alias Pleroma.Web.OStatus +  def websub_subscription_request(conn, %{"nickname" => nickname} = params) do +    user = User.get_cached_by_nickname(nickname) + +    with {:ok, topic} <- valid_topic(params, user), +         {:ok, lease_time} <- lease_time(params), +         secret <- params["hub.secret"] +    do +      data = %{ +        state: "requested", +        topic: topic, +        secret: secret +      } + +      change = Ecto.Changeset.change(%WebsubServerSubscription{}, data) +      websub = Repo.insert!(change) + +      change = Ecto.Changeset.change(websub, %{valid_until: NaiveDateTime.add(websub.inserted_at, lease_time)}) +      websub = Repo.update!(change) + +      conn +      |> send_resp(202, "Accepted") +    else {:error, reason} -> +      conn +      |> send_resp(500, reason) +    end +  end + +  defp lease_time(%{"hub.lease_seconds" => lease_seconds}) do +    {:ok, lease_seconds} +  end + +  defp lease_time(_) do +    {:ok, 60 * 60 * 24 * 3} # three days +  end + +  defp valid_topic(%{"hub.topic" => topic}, user) do +    if topic == OStatus.feed_path(user) do +      {:ok, topic} +    else +      {:error, "Wrong topic requested, expected #{OStatus.feed_path(user)}, got #{topic}"} +    end +  end +end diff --git a/lib/pleroma/web/websub/websub_server_subscription.ex b/lib/pleroma/web/websub/websub_server_subscription.ex new file mode 100644 index 000000000..a29dd5860 --- /dev/null +++ b/lib/pleroma/web/websub/websub_server_subscription.ex @@ -0,0 +1,13 @@ +defmodule Pleroma.Web.Websub.WebsubServerSubscription do +  use Ecto.Schema + +  schema "websub_server_subscriptions" do +    field :topic, :string +    field :callback, :string +    field :secret, :string +    field :valid_until, :naive_datetime +    field :state, :string + +    timestamps() +  end +end diff --git a/lib/xml_builder.ex b/lib/xml_builder.ex new file mode 100644 index 000000000..ac1ac8a74 --- /dev/null +++ b/lib/xml_builder.ex @@ -0,0 +1,42 @@ +defmodule Pleroma.XmlBuilder do +  def to_xml({tag, attributes, content}) do +    open_tag = make_open_tag(tag, attributes) + +    content_xml = to_xml(content) + +    "<#{open_tag}>#{content_xml}</#{tag}>" +  end + +  def to_xml({tag, %{} = attributes}) do +    open_tag = make_open_tag(tag, attributes) + +    "<#{open_tag} />" +  end + +  def to_xml({tag, content}), do: to_xml({tag, %{}, content}) + +  def to_xml(content) when is_binary(content) do +    to_string(content) +  end + +  def to_xml(content) when is_list(content) do +    for element <- content do +      to_xml(element) +    end +    |> Enum.join +  end + +  def to_xml(%NaiveDateTime{} = time) do +    NaiveDateTime.to_iso8601(time) +  end + +  def to_doc(content), do: "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" <> to_xml(content) + +  defp make_open_tag(tag, attributes) do +    attributes_string = for {attribute, value} <- attributes do +      "#{attribute}=\"#{value}\"" +    end |> Enum.join(" ") + +    Enum.join([tag, attributes_string], " ") |> String.strip +  end +end @@ -39,6 +39,7 @@ defmodule Pleroma.Mixfile do       {:html_sanitize_ex, "~> 1.0.0"},       {:calendar, "~> 0.16.1"},       {:cachex, "~> 2.1"}, +     {:httpoison, "~> 0.11.1"},       {:ex_machina, "~> 2.0", only: :test},       {:mix_test_watch, "~> 0.2", only: :dev}]    end @@ -18,6 +18,7 @@    "gettext": {:hex, :gettext, "0.13.1", "5e0daf4e7636d771c4c71ad5f3f53ba09a9ae5c250e1ab9c42ba9edccc476263", [:mix], []},    "hackney": {:hex, :hackney, "1.7.1", "e238c52c5df3c3b16ce613d3a51c7220a784d734879b1e231c9babd433ac1cb4", [:rebar3], [{:certifi, "1.0.0", [hex: :certifi, optional: false]}, {:idna, "4.0.0", [hex: :idna, optional: false]}, {:metrics, "1.0.1", [hex: :metrics, optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, optional: false]}]},    "html_sanitize_ex": {:hex, :html_sanitize_ex, "1.0.1", "2572e7122c78ab7e57b613e7c7f5e42bf9b3c25e430e32f23f1413d86db8a0af", [:mix], [{:mochiweb, "~> 2.12.2", [hex: :mochiweb, optional: false]}]}, +  "httpoison": {:hex, :httpoison, "0.11.1", "d06c571274c0e77b6cc50e548db3fd7779f611fbed6681fd60a331f66c143a0b", [:mix], [{:hackney, "~> 1.7.0", [hex: :hackney, optional: false]}]},    "idna": {:hex, :idna, "4.0.0", "10aaa9f79d0b12cf0def53038547855b91144f1bfcc0ec73494f38bb7b9c4961", [:rebar3], []},    "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], []},    "mime": {:hex, :mime, "1.1.0", "01c1d6f4083d8aa5c7b8c246ade95139620ef8effb009edde934e0ec3b28090a", [:mix], []}, diff --git a/priv/repo/migrations/20170418200143_create_webssub_server_subscription.exs b/priv/repo/migrations/20170418200143_create_webssub_server_subscription.exs new file mode 100644 index 000000000..fe2fa2304 --- /dev/null +++ b/priv/repo/migrations/20170418200143_create_webssub_server_subscription.exs @@ -0,0 +1,15 @@ +defmodule Pleroma.Repo.Migrations.CreateWebsubServerSubscription do +  use Ecto.Migration + +  def change do +    create table(:websub_server_subscriptions) do +      add :topic, :string +      add :callback, :string +      add :secret, :string +      add :valid_until, :naive_datetime +      add :state, :string + +      timestamps() +    end +  end +end diff --git a/test/support/factory.ex b/test/support/factory.ex index 3fc9cf710..401fdfda3 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -64,4 +64,14 @@ defmodule Pleroma.Factory do        data: data      }    end + +  def websub_subscription_factory do +    %Pleroma.Web.Websub.WebsubServerSubscription{ +      topic: "http://example.org", +      callback: "http://example/org/callback", +      secret: "here's a secret", +      valid_until: NaiveDateTime.add(NaiveDateTime.utc_now, 100), +      state: "requested" +    } +  end  end diff --git a/test/web/ostatus/activity_representer_test.exs b/test/web/ostatus/activity_representer_test.exs new file mode 100644 index 000000000..de79717b1 --- /dev/null +++ b/test/web/ostatus/activity_representer_test.exs @@ -0,0 +1,38 @@ +defmodule Pleroma.Web.OStatus.ActivityRepresenterTest do +  use Pleroma.DataCase + +  alias Pleroma.Web.OStatus.ActivityRepresenter +  alias Pleroma.User + +  import Pleroma.Factory + +  test "a note activity" do +    note_activity = insert(:note_activity) +    updated_at = note_activity.updated_at +    |> NaiveDateTime.to_iso8601 +    inserted_at = note_activity.inserted_at +    |> NaiveDateTime.to_iso8601 + +    user = User.get_cached_by_ap_id(note_activity.data["actor"]) + +    expected = """ +    <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> +    <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> +    <id>#{note_activity.data["object"]["id"]}</id> +    <title>New note by #{user.nickname}</title> +    <content type="html">#{note_activity.data["object"]["content"]}</content> +    <published>#{inserted_at}</published> +    <updated>#{updated_at}</updated> +    """ + +    tuple = ActivityRepresenter.to_simple_form(note_activity, user) + +    res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary + +    assert clean(res) == clean(expected) +  end + +  defp clean(string) do +    String.replace(string, ~r/\s/, "") +  end +end diff --git a/test/web/ostatus/feed_representer_test.exs b/test/web/ostatus/feed_representer_test.exs new file mode 100644 index 000000000..3d8eaac6e --- /dev/null +++ b/test/web/ostatus/feed_representer_test.exs @@ -0,0 +1,44 @@ +defmodule Pleroma.Web.OStatus.FeedRepresenterTest do +  use Pleroma.DataCase +  import Pleroma.Factory +  alias Pleroma.User +  alias Pleroma.Web.OStatus.{FeedRepresenter, UserRepresenter, ActivityRepresenter} +  alias Pleroma.Web.OStatus + +  test "returns a feed of the last 20 items of the user" do +    note_activity = insert(:note_activity) +    user = User.get_cached_by_ap_id(note_activity.data["actor"]) + +    tuple = FeedRepresenter.to_simple_form(user, [note_activity], [user]) + +    most_recent_update = note_activity.updated_at +    |> NaiveDateTime.to_iso8601 + +    res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary +    user_xml = UserRepresenter.to_simple_form(user) +    |> :xmerl.export_simple_content(:xmerl_xml) + +    entry_xml = ActivityRepresenter.to_simple_form(note_activity, user) +    |> :xmerl.export_simple_content(:xmerl_xml) + +    expected = """ +    <feed xmlns="http://www.w3.org/2005/Atom" xmlns:activity="http://activitystrea.ms/spec/1.0/"> +      <id>#{OStatus.feed_path(user)}</id> +      <title>#{user.nickname}'s timeline</title> +      <updated>#{most_recent_update}</updated> +      <link rel="hub" href="#{OStatus.pubsub_path(user)}" /> +      <author> +        #{user_xml} +      </author> +      <entry> +        #{entry_xml} +      </entry> +    </feed> +    """ +    assert clean(res) == clean(expected) +  end + +  defp clean(string) do +    String.replace(string, ~r/\s/, "") +  end +end diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs new file mode 100644 index 000000000..229cd9b1e --- /dev/null +++ b/test/web/ostatus/ostatus_controller_test.exs @@ -0,0 +1,15 @@ +defmodule Pleroma.Web.OStatus.OStatusControllerTest do +  use Pleroma.Web.ConnCase +  import Pleroma.Factory +  alias Pleroma.User + +  test "gets a feed", %{conn: conn} do +    note_activity = insert(:note_activity) +    user = User.get_cached_by_ap_id(note_activity.data["actor"]) + +    conn = conn +    |> get("/users/#{user.nickname}/feed.atom") + +    assert response(conn, 200) +  end +end diff --git a/test/web/ostatus/user_representer_test.exs b/test/web/ostatus/user_representer_test.exs new file mode 100644 index 000000000..a401a56da --- /dev/null +++ b/test/web/ostatus/user_representer_test.exs @@ -0,0 +1,28 @@ +defmodule Pleroma.Web.OStatus.UserRepresenterTest do +  use Pleroma.DataCase +  alias Pleroma.Web.OStatus.UserRepresenter + +  import Pleroma.Factory +  alias Pleroma.User + +  test "returns a user with id, uri, name and link" do +    user = build(:user) +    tuple = UserRepresenter.to_simple_form(user) + +    res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary + +    expected = """ +    <id>#{user.ap_id}</id> +    <activity:object>http://activitystrea.ms/schema/1.0/person</activity:object> +    <uri>#{user.ap_id}</uri> +    <name>#{user.nickname}</name> +    <link rel="avatar" href="#{User.avatar_url(user)}" /> +    """ + +    assert clean(res) == clean(expected) +  end + +  defp clean(string) do +    String.replace(string, ~r/\s/, "") +  end +end diff --git a/test/web/web_finger/web_finger_test.exs b/test/web/web_finger/web_finger_test.exs new file mode 100644 index 000000000..8a3007ff9 --- /dev/null +++ b/test/web/web_finger/web_finger_test.exs @@ -0,0 +1,11 @@ +defmodule Pleroma.Web.WebFingerTest do +  use Pleroma.DataCase + +  describe "host meta" do +    test "returns a link to the xml lrdd" do +      host_info = Pleroma.Web.WebFinger.host_meta + +      assert String.contains?(host_info, Pleroma.Web.base_url) +    end +  end +end diff --git a/test/web/websub/websub_controller_test.exs b/test/web/websub/websub_controller_test.exs new file mode 100644 index 000000000..4eff598d6 --- /dev/null +++ b/test/web/websub/websub_controller_test.exs @@ -0,0 +1,30 @@ +defmodule Pleroma.Web.Websub.WebsubControllerTest do +  use Pleroma.Web.ConnCase +  import Pleroma.Factory +  alias Pleroma.Repo +  alias Pleroma.Web.Websub.WebsubServerSubscription + +  test "websub subscription request", %{conn: conn} do +    user = insert(:user) + +    path = Pleroma.Web.OStatus.pubsub_path(user) + +    data = %{ +      "hub.callback": "http://example.org/sub", +      "hub.mode": "subscription", +      "hub.topic": Pleroma.Web.OStatus.feed_path(user), +      "hub.secret": "a random secret", +      "hub.lease_seconds": 100 +    } + +    conn = conn +    |> post(path, data) + +    assert response(conn, 202) == "Accepted" +    subscription = Repo.one!(WebsubServerSubscription) +    assert subscription.topic == Pleroma.Web.OStatus.feed_path(user) +    assert subscription.state == "requested" +    assert subscription.secret == "a random secret" +    assert subscription.valid_until == NaiveDateTime.add(subscription.inserted_at, 100) +  end +end diff --git a/test/web/websub/websub_test.exs b/test/web/websub/websub_test.exs new file mode 100644 index 000000000..93a44fe46 --- /dev/null +++ b/test/web/websub/websub_test.exs @@ -0,0 +1,44 @@ +defmodule Pleroma.Web.WebsubTest do +  use Pleroma.DataCase +  alias Pleroma.Web.Websub +  import Pleroma.Factory + +  test "a verification of a request that is accepted" do +    sub = insert(:websub_subscription) +    topic = sub.topic + +    getter = fn (_path, _headers, options) -> +      %{ +        "hub.challenge": challenge, +        "hub.lease_seconds": seconds, +        "hub.topic": ^topic, +        "hub.mode": "subscribe" +      } = Keyword.get(options, :params) + +      assert is_number(seconds) + +      {:ok, %HTTPoison.Response{ +        status_code: 200, +        body: challenge +      }} +    end + +    {:ok, sub} = Websub.verify(sub, getter) +    assert sub.state == "active" +  end + +  test "a verification of a request that doesn't return 200" do +    sub = insert(:websub_subscription) +    topic = sub.topic + +    getter = fn (_path, _headers, _options) -> +      {:ok, %HTTPoison.Response{ +        status_code: 500, +        body: "" +      }} +    end + +    {:error, sub} = Websub.verify(sub, getter) +    assert sub.state == "rejected" +  end +end diff --git a/test/xml_builder_test.exs b/test/xml_builder_test.exs new file mode 100644 index 000000000..f502a0f0e --- /dev/null +++ b/test/xml_builder_test.exs @@ -0,0 +1,59 @@ +defmodule Pleroma.XmlBuilderTest do +  use Pleroma.DataCase +  alias Pleroma.XmlBuilder + +  test "Build a basic xml string from a tuple" do +    data = { :feed, %{ xmlns: "http://www.w3.org/2005/Atom"}, "Some content" } + +    expected_xml = "<feed xmlns=\"http://www.w3.org/2005/Atom\">Some content</feed>" + +    assert XmlBuilder.to_xml(data) == expected_xml +  end + +  test "returns a complete document" do +    data = { :feed, %{ xmlns: "http://www.w3.org/2005/Atom"}, "Some content" } + +    expected_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><feed xmlns=\"http://www.w3.org/2005/Atom\">Some content</feed>" + +    assert XmlBuilder.to_doc(data) == expected_xml +  end + +  test "Works without attributes" do +    data = { +      :feed, +      "Some content" +    } + +    expected_xml = "<feed>Some content</feed>" + +    assert XmlBuilder.to_xml(data) == expected_xml +  end + +  test "It works with nested tuples" do +    data = { +      :feed, +      [ +        {:guy, "brush"}, +        {:lament, %{ configuration: "puzzle" }, "pinhead" } +      ] +    } + +    expected_xml = ~s[<feed><guy>brush</guy><lament configuration="puzzle">pinhead</lament></feed>] + +    assert XmlBuilder.to_xml(data) == expected_xml +  end + +  test "Represents NaiveDateTime as iso8601" do +    assert XmlBuilder.to_xml(~N[2000-01-01 13:13:33]) == "2000-01-01T13:13:33" +  end + +  test "Uses self-closing tags when no content is giving" do +    data = { +      :link, +      %{ rel: "self" } +    } + +    expected_xml = ~s[<link rel="self" />] +    assert XmlBuilder.to_xml(data) == expected_xml +  end +end | 
