diff --git a/apps/block_scout_web/lib/block_scout_web/api_router.ex b/apps/block_scout_web/lib/block_scout_web/api_router.ex index bd93d25b67..944ea56fa4 100644 --- a/apps/block_scout_web/lib/block_scout_web/api_router.ex +++ b/apps/block_scout_web/lib/block_scout_web/api_router.ex @@ -18,42 +18,56 @@ defmodule BlockScoutWeb.ApiRouter do plug(:accepts, ["json"]) end - scope "/v1", as: :api_v1 do + scope "/v1", BlockScoutWeb.API.V1, as: :api_v1 do pipe_through(:api) + get("/health", HealthController, :health) + if Application.get_env(:block_scout_web, __MODULE__)[:writing_enabled] do + post("/decompiled_smart_contract", DecompiledSmartContractController, :create) + post("/verified_smart_contracts", VerifiedSmartContractController, :create) + end + end + + if Application.get_env(:block_scout_web, __MODULE__)[:reading_enabled] do scope "/" do alias BlockScoutWeb.API.{RPC, V1} - get("/supply", V1.SupplyController, :supply) + pipe_through(:api) - post("/eth_rpc", RPC.EthController, :eth_request) + scope "/v1", as: :api_v1 do + get("/supply", V1.SupplyController, :supply) + post("/eth_rpc", RPC.EthController, :eth_request) + end - forward("/", RPC.RPCTranslator, %{ - "block" => RPC.BlockController, - "account" => RPC.AddressController, - "logs" => RPC.LogsController, - "token" => RPC.TokenController, - "stats" => RPC.StatsController, - "contract" => RPC.ContractController, - "transaction" => RPC.TransactionController - }) + # For backward compatibility. Should be removed + post("/eth_rpc", RPC.EthController, :eth_request) end end - # For backward compatibility. Should be removed scope "/" do - alias BlockScoutWeb.API.RPC pipe_through(:api) + alias BlockScoutWeb.API.RPC - post("/eth_rpc", RPC.EthController, :eth_request) + scope "/v1", as: :api_v1 do + forward("/", RPC.RPCTranslator, %{ + "block" => {RPC.BlockController, []}, + "account" => {RPC.AddressController, []}, + "logs" => {RPC.LogsController, []}, + "token" => {RPC.TokenController, []}, + "stats" => {RPC.StatsController, []}, + "contract" => {RPC.ContractController, [:verify]}, + "transaction" => {RPC.TransactionController, []} + }) + end + # For backward compatibility. Should be removed forward("/", RPCTranslatorForwarder, %{ - "block" => RPC.BlockController, - "account" => RPC.AddressController, - "logs" => RPC.LogsController, - "token" => RPC.TokenController, - "stats" => RPC.StatsController, - "contract" => RPC.ContractController, - "transaction" => RPC.TransactionController + "block" => {RPC.BlockController, []}, + "account" => {RPC.AddressController, []}, + "logs" => {RPC.LogsController, []}, + "token" => {RPC.TokenController, []}, + "stats" => {RPC.StatsController, []}, + "contract" => {RPC.ContractController, [:verify]}, + "transaction" => {RPC.TransactionController, []} }) end end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/rpc_translator.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/rpc_translator.ex index a5a4959e8d..b6380fc975 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/rpc_translator.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/rpc_translator.ex @@ -25,8 +25,9 @@ defmodule BlockScoutWeb.API.RPC.RPCTranslator do def init(opts), do: opts def call(%Conn{params: %{"module" => module, "action" => action}} = conn, translations) do - with {:ok, controller} <- translate_module(translations, module), + with {:ok, {controller, write_actions}} <- translate_module(translations, module), {:ok, action} <- translate_action(action), + true <- action_accessed?(action, write_actions), {:ok, conn} <- call_controller(conn, controller, action) do conn else @@ -64,7 +65,7 @@ defmodule BlockScoutWeb.API.RPC.RPCTranslator do end @doc false - @spec translate_module(map(), String.t()) :: {:ok, module()} | {:error, :no_action} + @spec translate_module(map(), String.t()) :: {:ok, {module(), list(atom())}} | {:error, :no_action} defp translate_module(translations, module) do module_lowercase = String.downcase(module) @@ -83,6 +84,16 @@ defmodule BlockScoutWeb.API.RPC.RPCTranslator do ArgumentError -> {:error, :no_action} end + defp action_accessed?(action, write_actions) do + conf = Application.get_env(:block_scout_web, BlockScoutWeb.ApiRouter) + + if action in write_actions do + conf[:writing_enabled] || {:error, :no_action} + else + conf[:reading_enabled] || {:error, :no_action} + end + end + @doc false @spec call_controller(Conn.t(), module(), atom()) :: {:ok, Conn.t()} | {:error, :no_action} | {:error, Exception.t()} defp call_controller(conn, controller, action) do diff --git a/apps/block_scout_web/lib/block_scout_web/router.ex b/apps/block_scout_web/lib/block_scout_web/router.ex index 7d2af1ffc8..e654e1729c 100644 --- a/apps/block_scout_web/lib/block_scout_web/router.ex +++ b/apps/block_scout_web/lib/block_scout_web/router.ex @@ -19,19 +19,9 @@ defmodule BlockScoutWeb.Router do plug(:accepts, ["json"]) end - scope "/api/v1", BlockScoutWeb.API.V1, as: :api_v1 do - pipe_through(:api) - get("/health", HealthController, :health) - - if Application.get_env(:block_scout_web, ApiRouter)[:writing_enabled] do - post("/decompiled_smart_contract", DecompiledSmartContractController, :create) - post("/verified_smart_contracts", VerifiedSmartContractController, :create) - end - end + forward("/api", ApiRouter) if Application.get_env(:block_scout_web, ApiRouter)[:reading_enabled] do - forward("/api", ApiRouter) - # Needs to be 200 to support the schema introspection for graphiql @max_complexity 200