Skip to content

Commit a553c46

Browse files
committed
feat: add Plug to block requests by Ip
1 parent c415dba commit a553c46

File tree

4 files changed

+47
-3
lines changed

4 files changed

+47
-3
lines changed

apps/block_scout_web/lib/block_scout_web/api_router.ex

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ defmodule BlockScoutWeb.ApiRouter do
1414
"""
1515
use BlockScoutWeb, :router
1616
alias BlockScoutWeb.{AddressTransactionController, APIKeyV2Router, SmartContractsApiV2Router, UtilsApiV2Router}
17-
alias BlockScoutWeb.Plug.{CheckAccountAPI, CheckApiV2, RateLimit}
17+
alias BlockScoutWeb.Plug.{CheckAccountAPI, CheckApiV2, RateLimit, BlockedIpList}
1818

1919
forward("/v2/smart-contracts", SmartContractsApiV2Router)
2020
forward("/v2/key", APIKeyV2Router)
@@ -37,13 +37,15 @@ defmodule BlockScoutWeb.ApiRouter do
3737
plug(CheckApiV2)
3838
plug(:fetch_session)
3939
plug(:protect_from_forgery)
40+
plug(BlockedIpList)
4041
plug(RateLimit)
4142
end
4243

4344
pipeline :api_v2_no_session do
4445
plug(BlockScoutWeb.Plug.Logger, application: :api_v2)
4546
plug(:accepts, ["json"])
4647
plug(CheckApiV2)
48+
plug(BlockedIpList)
4749
plug(RateLimit)
4850
end
4951

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
defmodule BlockScoutWeb.Plug.BlockedIpList do
2+
@moduledoc """
3+
Block requests by IP
4+
"""
5+
alias BlockScoutWeb.AccessHelper
6+
7+
def init(opts), do: opts
8+
9+
def call(conn, _opts) do
10+
if AccessHelper.blocked_access?(conn) do
11+
AccessHelper.handle_blocked_access(conn, true)
12+
else
13+
conn
14+
end
15+
end
16+
end

apps/block_scout_web/lib/block_scout_web/views/access_helper.ex

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,32 @@ defmodule BlockScoutWeb.AccessHelper do
6363
end
6464
end
6565

66+
def blocked_access?(conn) do
67+
case Application.get_env(:block_scout_web, :blocked_ips) do
68+
nil ->
69+
false
70+
71+
blocked_ips ->
72+
blocked_ips
73+
|> String.replace(" ", "")
74+
|> String.split(",")
75+
|> Enum.member?(conn_to_ip_string(conn))
76+
end
77+
end
78+
79+
def handle_blocked_access(conn, api_v2? \\ false) do
80+
APILogger.message("unauthorized request")
81+
82+
view = if api_v2?, do: ApiView, else: RPCView
83+
tag = if api_v2?, do: :message, else: :error
84+
85+
conn
86+
|> Conn.put_status(401)
87+
|> put_view(view)
88+
|> render(tag, %{tag => "unauthorized"})
89+
|> Conn.halt()
90+
end
91+
6692
# credo:disable-for-next-line /Complexity/
6793
defp check_rate_limit_inner(conn, rate_limit_config) do
6894
global_limit = rate_limit_config[:global_limit]
@@ -81,8 +107,6 @@ defmodule BlockScoutWeb.AccessHelper do
81107

82108
user_agent = get_user_agent(conn)
83109

84-
Logger.info("request ip: #{inspect(ip_string)}")
85-
86110
cond do
87111
check_api_key(conn) && get_api_key(conn) == static_api_key ->
88112
rate_limit(static_api_key, limit_by_key, time_interval_limit)

config/runtime.exs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ config :block_scout_web, BlockScoutWeb.MicroserviceInterfaces.TransactionInterpr
136136
service_url: System.get_env("MICROSERVICE_TRANSACTION_INTERPRETATION_URL"),
137137
enabled: ConfigHelper.parse_bool_env_var("MICROSERVICE_TRANSACTION_INTERPRETATION_ENABLED")
138138

139+
config :block_scout_web, blocked_ips: System.get_env("API_BLOCKED_IPS")
140+
139141
# Configures Ueberauth's Auth0 auth provider
140142
config :ueberauth, Ueberauth.Strategy.Auth0.OAuth,
141143
domain: System.get_env("ACCOUNT_AUTH0_DOMAIN"),

0 commit comments

Comments
 (0)