Enforcement of OAuth scopes check for authenticated API endpoints, :skip_plug plug...
[akkoma] / lib / pleroma / web / web.ex
index bfb6c728784055ab925799f1ef7f84de7aa0ee76..1af29ce788bcdadffb18871f372e1e76c256c252 100644 (file)
@@ -1,5 +1,5 @@
 # Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web do
@@ -29,11 +29,34 @@ defmodule Pleroma.Web do
       import Pleroma.Web.Router.Helpers
       import Pleroma.Web.TranslationHelpers
 
+      alias Pleroma.Plugs.PlugHelper
+
       plug(:set_put_layout)
 
       defp set_put_layout(conn, _) do
         put_layout(conn, Pleroma.Config.get(:app_layout, "app.html"))
       end
+
+      # Marks a plug as intentionally skipped
+      #   (states that the plug is not called for a good reason, not by a mistake)
+      defp skip_plug(conn, plug_module) do
+        PlugHelper.append_to_skipped_plugs(conn, plug_module)
+      end
+
+      # Here we can apply before-action hooks (e.g. verify whether auth checks were preformed)
+      defp action(conn, params) do
+        if conn.private[:auth_expected] &&
+             not PlugHelper.plug_called_or_skipped?(conn, Pleroma.Plugs.OAuthScopesPlug) do
+          conn
+          |> render_error(
+            :forbidden,
+            "Security violation: OAuth scopes check was neither handled nor explicitly skipped."
+          )
+          |> halt()
+        else
+          super(conn, params)
+        end
+      end
     end
   end
 
@@ -66,23 +89,9 @@ defmodule Pleroma.Web do
       end
 
       @doc """
-      Same as `render_many/4` but wrapped in rescue block and parallelized (unless disabled by passing false as a fifth argument).
+      Same as `render_many/4` but wrapped in rescue block.
       """
-      def safe_render_many(collection, view, template, assigns \\ %{}, parallel \\ true)
-
-      def safe_render_many(collection, view, template, assigns, true) do
-        Enum.map(collection, fn resource ->
-          Task.async(fn ->
-            as = Map.get(assigns, :as) || view.__resource__
-            assigns = Map.put(assigns, as, resource)
-            safe_render(view, template, assigns)
-          end)
-        end)
-        |> Enum.map(&Task.await(&1, :infinity))
-        |> Enum.filter(& &1)
-      end
-
-      def safe_render_many(collection, view, template, assigns, false) do
+      def safe_render_many(collection, view, template, assigns \\ %{}) do
         Enum.map(collection, fn resource ->
           as = Map.get(assigns, :as) || view.__resource__
           assigns = Map.put(assigns, as, resource)