From 3920244be5be000e33c470beb897a031ecef3ac8 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov <ivantashkinov@gmail.com>
Date: Wed, 11 Dec 2019 11:42:02 +0300
Subject: [PATCH] [#1427] Fixed `:admin` option handling in OAuthScopesPlug,
 added tests.

---
 lib/pleroma/config.ex                  | 11 ++++++--
 lib/pleroma/plugs/oauth_scopes_plug.ex | 17 +++++++-----
 test/plugs/oauth_scopes_plug_test.exs  | 38 ++++++++++++++++++++++++++
 3 files changed, 56 insertions(+), 10 deletions(-)

diff --git a/lib/pleroma/config.ex b/lib/pleroma/config.ex
index cadab2f15..bad6d505c 100644
--- a/lib/pleroma/config.ex
+++ b/lib/pleroma/config.ex
@@ -68,8 +68,13 @@ defmodule Pleroma.Config do
 
   def enforce_oauth_admin_scope_usage?, do: !!get([:auth, :enforce_oauth_admin_scope_usage])
 
-  def oauth_admin_scopes(scope) do
-    ["admin:#{scope}"] ++
-      if enforce_oauth_admin_scope_usage?(), do: [], else: [scope]
+  def oauth_admin_scopes(scopes) when is_list(scopes) do
+    Enum.flat_map(
+      scopes,
+      fn scope ->
+        ["admin:#{scope}"] ++
+          if enforce_oauth_admin_scope_usage?(), do: [], else: [scope]
+      end
+    )
   end
 end
diff --git a/lib/pleroma/plugs/oauth_scopes_plug.ex b/lib/pleroma/plugs/oauth_scopes_plug.ex
index 3201fb399..174a8389c 100644
--- a/lib/pleroma/plugs/oauth_scopes_plug.ex
+++ b/lib/pleroma/plugs/oauth_scopes_plug.ex
@@ -17,13 +17,7 @@ defmodule Pleroma.Plugs.OAuthScopesPlug do
     op = options[:op] || :|
     token = assigns[:token]
 
-    scopes =
-      if options[:admin] do
-        Config.oauth_admin_scopes(scopes)
-      else
-        scopes
-      end
-
+    scopes = transform_scopes(scopes, options)
     matched_scopes = token && filter_descendants(scopes, token.scopes)
 
     cond do
@@ -69,6 +63,15 @@ defmodule Pleroma.Plugs.OAuthScopesPlug do
     )
   end
 
+  @doc "Transforms scopes by applying supported options (e.g. :admin)"
+  def transform_scopes(scopes, options) do
+    if options[:admin] do
+      Config.oauth_admin_scopes(scopes)
+    else
+      scopes
+    end
+  end
+
   defp maybe_perform_instance_privacy_check(%Plug.Conn{} = conn, options) do
     if options[:skip_instance_privacy_check] do
       conn
diff --git a/test/plugs/oauth_scopes_plug_test.exs b/test/plugs/oauth_scopes_plug_test.exs
index be6d1340b..89f32f43a 100644
--- a/test/plugs/oauth_scopes_plug_test.exs
+++ b/test/plugs/oauth_scopes_plug_test.exs
@@ -224,4 +224,42 @@ defmodule Pleroma.Plugs.OAuthScopesPlugTest do
       assert f.(["admin:read"], ["write", "admin"]) == ["admin:read"]
     end
   end
+
+  describe "transform_scopes/2" do
+    clear_config([:auth, :enforce_oauth_admin_scope_usage])
+
+    setup do
+      {:ok, %{f: &OAuthScopesPlug.transform_scopes/2}}
+    end
+
+    test "with :admin option, prefixes all requested scopes with `admin:` " <>
+           "and [optionally] keeps only prefixed scopes, " <>
+           "depending on `[:auth, :enforce_oauth_admin_scope_usage]` setting",
+         %{f: f} do
+      Pleroma.Config.put([:auth, :enforce_oauth_admin_scope_usage], false)
+
+      assert f.(["read"], %{admin: true}) == ["admin:read", "read"]
+
+      assert f.(["read", "write"], %{admin: true}) == [
+               "admin:read",
+               "read",
+               "admin:write",
+               "write"
+             ]
+
+      Pleroma.Config.put([:auth, :enforce_oauth_admin_scope_usage], true)
+
+      assert f.(["read:accounts"], %{admin: true}) == ["admin:read:accounts"]
+
+      assert f.(["read", "write:reports"], %{admin: true}) == [
+               "admin:read",
+               "admin:write:reports"
+             ]
+    end
+
+    test "with no supported options, returns unmodified scopes", %{f: f} do
+      assert f.(["read"], %{}) == ["read"]
+      assert f.(["read", "write"], %{}) == ["read", "write"]
+    end
+  end
 end