From 61a4bc50952b11a59dce7f655c883de59306adcd Mon Sep 17 00:00:00 2001
From: Maxim Filippov <colixer@gmail.com>
Date: Sun, 10 Feb 2019 22:41:06 +0300
Subject: [PATCH 1/5] Add OAuth tokens endpoint

---
 lib/pleroma/web/oauth/token.ex                |  8 +++++++
 lib/pleroma/web/router.ex                     |  2 ++
 .../web/twitter_api/twitter_api_controller.ex | 12 ++++++++++
 .../web/twitter_api/views/token_view.ex       | 22 +++++++++++++++++++
 test/support/factory.ex                       | 13 +++++++++++
 .../twitter_api_controller_test.exs           | 18 +++++++++++++++
 6 files changed, 75 insertions(+)
 create mode 100644 lib/pleroma/web/twitter_api/views/token_view.ex

diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex
index b0bbeeb69..40bf0ac6b 100644
--- a/lib/pleroma/web/oauth/token.ex
+++ b/lib/pleroma/web/oauth/token.ex
@@ -52,4 +52,12 @@ defmodule Pleroma.Web.OAuth.Token do
     )
     |> Repo.delete_all()
   end
+
+  def get_user_tokens(%User{id: user_id}) do
+    from(
+      t in Pleroma.Web.OAuth.Token,
+      where: t.user_id == ^user_id
+    )
+    |> Repo.all()
+  end
 end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 5b5627ce8..a394900b2 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -389,6 +389,8 @@ defmodule Pleroma.Web.Router do
     get("/qvitter/mutes", TwitterAPI.Controller, :raw_empty_array)
 
     get("/externalprofile/show", TwitterAPI.Controller, :external_profile)
+
+    get("/oauth_tokens", TwitterAPI.Controller, :oauth_tokens)
   end
 
   pipeline :ap_relay do
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index c2f0dc2a9..1a43e9a60 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -8,6 +8,10 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
   import Pleroma.Web.ControllerHelper, only: [json_response: 3]
 
   alias Ecto.Changeset
+  alias Pleroma.Web.TwitterAPI.{TwitterAPI, UserView, ActivityView, NotificationView, TokenView}
+  alias Pleroma.Web.CommonAPI
+  alias Pleroma.{Repo, Activity, Object, User, Notification}
+  alias Pleroma.Web.OAuth.Token
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.Web.ActivityPub.Utils
   alias Pleroma.Web.CommonAPI
@@ -542,6 +546,14 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
     end
   end
 
+  def oauth_tokens(%{assigns: %{user: user}} = conn, _params) do
+    with oauth_tokens <- Token.get_user_tokens(user) do
+      conn
+      |> put_view(TokenView)
+      |> render("index.json", %{tokens: oauth_tokens})
+    end
+  end
+
   def blocks(%{assigns: %{user: user}} = conn, _params) do
     with blocked_users <- User.blocked_users(user) do
       conn
diff --git a/lib/pleroma/web/twitter_api/views/token_view.ex b/lib/pleroma/web/twitter_api/views/token_view.ex
new file mode 100644
index 000000000..96b8526a4
--- /dev/null
+++ b/lib/pleroma/web/twitter_api/views/token_view.ex
@@ -0,0 +1,22 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.TwitterAPI.TokenView do
+  use Pleroma.Web, :view
+
+  def render("index.json", %{tokens: tokens}) do
+    tokens
+    |> render_many(Pleroma.Web.TwitterAPI.TokenView, "show.json")
+    |> Enum.filter(&Enum.any?/1)
+  end
+
+  def render("show.json", %{token: token_entry}) do
+    %{
+      id: token_entry.id,
+      token: token_entry.token,
+      refresh_token: token_entry.refresh_token,
+      valid_until: token_entry.valid_until
+    }
+  end
+end
diff --git a/test/support/factory.ex b/test/support/factory.ex
index 0c21093ce..7a91549f5 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -227,4 +227,17 @@ defmodule Pleroma.Factory do
       unreachable_since: nil
     }
   end
+
+  def oauth_token_factory do
+    user = insert(:user)
+    oauth_app = insert(:oauth_app)
+
+    %Pleroma.Web.OAuth.Token{
+      token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(),
+      refresh_token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(),
+      user_id: user.id,
+      app_id: oauth_app.id,
+      valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), 60 * 10)
+    }
+  end
 end
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index 855ae1526..c50d82def 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -1876,4 +1876,22 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
                ActivityRepresenter.to_map(activity, %{user: user, for: user})
     end
   end
+
+  describe "GET /api/oauth_tokens" do
+    test "renders list" do
+      token = insert(:oauth_token)
+
+      response =
+        build_conn()
+        |> assign(:user, Repo.get(User, token.user_id))
+        |> get("/api/oauth_tokens")
+
+      keys =
+        json_response(response, 200)
+        |> hd()
+        |> Map.keys()
+
+      assert keys -- ["id", "refresh_token", "token", "valid_until"] == []
+    end
+  end
 end

From 62a45bdc11bc98ca4c24b0b8aa54c9d2958f81a1 Mon Sep 17 00:00:00 2001
From: Maxim Filippov <colixer@gmail.com>
Date: Mon, 11 Feb 2019 00:49:56 +0300
Subject: [PATCH 2/5] Add revoke token

---
 lib/pleroma/web/oauth/token.ex                | 11 ++++++++-
 lib/pleroma/web/router.ex                     |  1 +
 .../web/twitter_api/twitter_api_controller.ex |  6 +++++
 .../twitter_api_controller_test.exs           | 23 ++++++++++++++++---
 4 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex
index 40bf0ac6b..380a39360 100644
--- a/lib/pleroma/web/oauth/token.ex
+++ b/lib/pleroma/web/oauth/token.ex
@@ -53,9 +53,18 @@ defmodule Pleroma.Web.OAuth.Token do
     |> Repo.delete_all()
   end
 
-  def get_user_tokens(%User{id: user_id}) do
+  def delete_user_token(%User{id: user_id}, token_id) do
     from(
       t in Pleroma.Web.OAuth.Token,
+      where: t.user_id == ^user_id,
+      where: t.id == ^token_id
+    )
+    |> Repo.delete_all()
+  end
+
+  def get_user_tokens(%User{id: user_id}) do
+    from(
+      t in Token,
       where: t.user_id == ^user_id
     )
     |> Repo.all()
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index a394900b2..d45fa526e 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -391,6 +391,7 @@ defmodule Pleroma.Web.Router do
     get("/externalprofile/show", TwitterAPI.Controller, :external_profile)
 
     get("/oauth_tokens", TwitterAPI.Controller, :oauth_tokens)
+    delete("/oauth_tokens/:id", TwitterAPI.Controller, :revoke_token)
   end
 
   pipeline :ap_relay do
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index 1a43e9a60..fac05f288 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -554,6 +554,12 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
     end
   end
 
+  def revoke_token(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do
+    Token.delete_user_token(user, id)
+
+    json_reply(conn, 201, "")
+  end
+
   def blocks(%{assigns: %{user: user}} = conn, _params) do
     with blocked_users <- User.blocked_users(user) do
       conn
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index c50d82def..527a920fb 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -8,6 +8,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
   alias Pleroma.Builders.{ActivityBuilder, UserBuilder}
   alias Pleroma.{Repo, Activity, User, Object, Notification}
   alias Pleroma.Web.ActivityPub.ActivityPub
+  alias Pleroma.Web.OAuth.Token
   alias Pleroma.Web.TwitterAPI.UserView
   alias Pleroma.Web.TwitterAPI.NotificationView
   alias Pleroma.Web.CommonAPI
@@ -1878,12 +1879,16 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
   end
 
   describe "GET /api/oauth_tokens" do
-    test "renders list" do
-      token = insert(:oauth_token)
+    setup do
+      token = insert(:oauth_token) |> Repo.preload(:user)
 
+      %{token: token}
+    end
+
+    test "renders list", %{token: token} do
       response =
         build_conn()
-        |> assign(:user, Repo.get(User, token.user_id))
+        |> assign(:user, token.user)
         |> get("/api/oauth_tokens")
 
       keys =
@@ -1893,5 +1898,17 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
 
       assert keys -- ["id", "refresh_token", "token", "valid_until"] == []
     end
+
+    test "revoke token", %{token: token} do
+      response =
+        build_conn()
+        |> assign(:user, token.user)
+        |> delete("/api/oauth_tokens/#{token.id}")
+
+      tokens = Token.get_user_tokens(token.user)
+
+      assert tokens == []
+      assert response.status == 201
+    end
   end
 end

From 760fec4cb85c7ddf2ec4fa5578ab4a1ceafc1e84 Mon Sep 17 00:00:00 2001
From: Maxim Filippov <colixer@gmail.com>
Date: Mon, 11 Feb 2019 09:48:24 +0000
Subject: [PATCH 3/5] Update token.ex

---
 lib/pleroma/web/oauth/token.ex | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex
index 380a39360..f5594f834 100644
--- a/lib/pleroma/web/oauth/token.ex
+++ b/lib/pleroma/web/oauth/token.ex
@@ -47,7 +47,7 @@ defmodule Pleroma.Web.OAuth.Token do
 
   def delete_user_tokens(%User{id: user_id}) do
     from(
-      t in Pleroma.Web.OAuth.Token,
+      t in Token,
       where: t.user_id == ^user_id
     )
     |> Repo.delete_all()
@@ -55,7 +55,7 @@ defmodule Pleroma.Web.OAuth.Token do
 
   def delete_user_token(%User{id: user_id}, token_id) do
     from(
-      t in Pleroma.Web.OAuth.Token,
+      t in Token,
       where: t.user_id == ^user_id,
       where: t.id == ^token_id
     )

From 94708d63705f1e4e7f3aaebb6744634237b0cf21 Mon Sep 17 00:00:00 2001
From: Maxim Filippov <colixer@gmail.com>
Date: Sun, 17 Feb 2019 23:57:35 +0300
Subject: [PATCH 4/5] Render only "id", "valid_until" and "app_name" in
 TokenView

---
 lib/pleroma/web/oauth/token.ex                  | 1 +
 lib/pleroma/web/twitter_api/views/token_view.ex | 5 ++---
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex
index f5594f834..7fe58f6a2 100644
--- a/lib/pleroma/web/oauth/token.ex
+++ b/lib/pleroma/web/oauth/token.ex
@@ -68,5 +68,6 @@ defmodule Pleroma.Web.OAuth.Token do
       where: t.user_id == ^user_id
     )
     |> Repo.all()
+    |> Repo.preload(:app)
   end
 end
diff --git a/lib/pleroma/web/twitter_api/views/token_view.ex b/lib/pleroma/web/twitter_api/views/token_view.ex
index 96b8526a4..3ff314913 100644
--- a/lib/pleroma/web/twitter_api/views/token_view.ex
+++ b/lib/pleroma/web/twitter_api/views/token_view.ex
@@ -14,9 +14,8 @@ defmodule Pleroma.Web.TwitterAPI.TokenView do
   def render("show.json", %{token: token_entry}) do
     %{
       id: token_entry.id,
-      token: token_entry.token,
-      refresh_token: token_entry.refresh_token,
-      valid_until: token_entry.valid_until
+      valid_until: token_entry.valid_until,
+      app_name: token_entry.app.client_name
     }
   end
 end

From fd17a0cc9b78d1338e1fee51aa452858172639fe Mon Sep 17 00:00:00 2001
From: Maxim Filippov <colixer@gmail.com>
Date: Mon, 18 Feb 2019 00:10:48 +0300
Subject: [PATCH 5/5] Fix test

---
 test/web/twitter_api/twitter_api_controller_test.exs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index 527a920fb..3922b3c5e 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -1896,7 +1896,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
         |> hd()
         |> Map.keys()
 
-      assert keys -- ["id", "refresh_token", "token", "valid_until"] == []
+      assert keys -- ["id", "app_name", "valid_until"] == []
     end
 
     test "revoke token", %{token: token} do