diff --git a/CHANGELOG.md b/CHANGELOG.md
index e677a135ee..7d485ab892 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
### Features
+- [#7416](https://github.com/blockscout/blockscout/pull/7416) - Add option to disable reCAPTCHA
- [#6694](https://github.com/blockscout/blockscout/pull/6694) - Add withdrawals support (EIP-4895)
- [#7355](https://github.com/blockscout/blockscout/pull/7355) - Add endpoint for token info import
- [#7393](https://github.com/blockscout/blockscout/pull/7393) - Realtime fetcher max gap
diff --git a/apps/block_scout_web/assets/js/lib/csv_download.js b/apps/block_scout_web/assets/js/lib/csv_download.js
index 5163ce88ec..07f44ca30f 100644
--- a/apps/block_scout_web/assets/js/lib/csv_download.js
+++ b/apps/block_scout_web/assets/js/lib/csv_download.js
@@ -31,10 +31,17 @@ $button.on('click', () => {
// @ts-ignore
// eslint-disable-next-line
const reCaptchaV3ClientKey = document.getElementById('js-re-captcha-v3-client-key').value
+ // @ts-ignore
+ // eslint-disable-next-line
+ const reCaptchaDisabled = document.getElementById('js-re-captcha-disabled').value
const addressHash = $button.data('address-hash')
const from = $('.js-datepicker-from').val()
const to = $('.js-datepicker-to').val()
- if (reCaptchaV3ClientKey) {
+ if (reCaptchaDisabled) {
+ const url = `${$button.data('link')}?address_id=${addressHash}&from_period=${from}&to_period=${to}`
+
+ download(url)
+ } else if (reCaptchaV3ClientKey) {
disableBtnWithSpinner()
// @ts-ignore
// eslint-disable-next-line
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex
index e60dbc673b..a1ba52d659 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex
@@ -180,6 +180,42 @@ defmodule BlockScoutWeb.AddressTransactionController do
|> send_chunked(200)
end
+ defp items_csv(
+ conn,
+ %{
+ "address_id" => address_hash_string,
+ "from_period" => from_period,
+ "to_period" => to_period
+ },
+ csv_export_module
+ )
+ when is_binary(address_hash_string) do
+ with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
+ {:ok, address} <- Chain.hash_to_address(address_hash),
+ true <- Application.get_env(:block_scout_web, :recaptcha)[:is_disabled] do
+ address
+ |> csv_export_module.export(from_period, to_period)
+ |> Enum.reduce_while(put_resp_params(conn), fn chunk, conn ->
+ case Conn.chunk(conn, chunk) do
+ {:ok, conn} ->
+ {:cont, conn}
+
+ {:error, :closed} ->
+ {:halt, conn}
+ end
+ end)
+ else
+ :error ->
+ unprocessable_entity(conn)
+
+ {:error, :not_found} ->
+ not_found(conn)
+
+ {:recaptcha, false} ->
+ not_found(conn)
+ end
+ end
+
defp items_csv(
conn,
%{
@@ -232,6 +268,22 @@ defmodule BlockScoutWeb.AddressTransactionController do
)
end
+ def transactions_csv(conn, %{
+ "address_id" => address_hash_string,
+ "from_period" => from_period,
+ "to_period" => to_period
+ }) do
+ items_csv(
+ conn,
+ %{
+ "address_id" => address_hash_string,
+ "from_period" => from_period,
+ "to_period" => to_period
+ },
+ AddressTransactionCsvExporter
+ )
+ end
+
def transactions_csv(conn, %{
"address_id" => address_hash_string,
"from_period" => from_period,
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/csv_export/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/csv_export/index.html.eex
index cd98994651..9b9f6a8893 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/csv_export/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/csv_export/index.html.eex
@@ -41,4 +41,4 @@
<% true -> %>
<% end %>
-
\ No newline at end of file
+
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex
index 81725695df..8f2310b37c 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex
@@ -66,6 +66,7 @@
+
<% show_maintenance_alert = Application.get_env(:block_scout_web, BlockScoutWeb.Chain)[:show_maintenance_alert] %>
diff --git a/config/runtime.exs b/config/runtime.exs
index 7e6c891cd3..216e45857f 100644
--- a/config/runtime.exs
+++ b/config/runtime.exs
@@ -38,7 +38,8 @@ config :block_scout_web, :recaptcha,
v2_client_key: System.get_env("RE_CAPTCHA_CLIENT_KEY"),
v2_secret_key: System.get_env("RE_CAPTCHA_SECRET_KEY"),
v3_client_key: System.get_env("RE_CAPTCHA_V3_CLIENT_KEY"),
- v3_secret_key: System.get_env("RE_CAPTCHA_V3_SECRET_KEY")
+ v3_secret_key: System.get_env("RE_CAPTCHA_V3_SECRET_KEY"),
+ is_disabled: ConfigHelper.parse_bool_env_var("RE_CAPTCHA_DISABLED")
network_path =
"NETWORK_PATH"
diff --git a/docker-compose/envs/common-blockscout.env b/docker-compose/envs/common-blockscout.env
index 0f69031e74..bd23653152 100644
--- a/docker-compose/envs/common-blockscout.env
+++ b/docker-compose/envs/common-blockscout.env
@@ -156,6 +156,7 @@ RE_CAPTCHA_SECRET_KEY=
RE_CAPTCHA_CLIENT_KEY=
RE_CAPTCHA_V3_SECRET_KEY=
RE_CAPTCHA_V3_CLIENT_KEY=
+RE_CAPTCHA_DISABLED=false
JSON_RPC=
#API_RATE_LIMIT_DISABLED=true
API_RATE_LIMIT_TIME_INTERVAL=1s
@@ -199,4 +200,4 @@ ACCOUNT_REDIS_URL=redis://redis_db:6379
# AMPLITUDE_API_KEY=
# AMPLITUDE_URL=
EIP_1559_ELASTICITY_MULTIPLIER=2
-# API_SENSITIVE_ENDPOINTS_KEY=
\ No newline at end of file
+# API_SENSITIVE_ENDPOINTS_KEY=
diff --git a/docker/Makefile b/docker/Makefile
index 495e4dcef9..c98d09a9d3 100644
--- a/docker/Makefile
+++ b/docker/Makefile
@@ -369,6 +369,9 @@ endif
ifdef RE_CAPTCHA_V3_CLIENT_KEY
BLOCKSCOUT_CONTAINER_PARAMS += -e 'RE_CAPTCHA_V3_CLIENT_KEY=$(RE_CAPTCHA_V3_CLIENT_KEY)'
endif
+ifdef RE_CAPTCHA_IS_ENTERPRISE
+ BLOCKSCOUT_CONTAINER_PARAMS += -e 'RE_CAPTCHA_IS_ENTERPRISE=$(RE_CAPTCHA_IS_ENTERPRISE)'
+endif
ifdef CACHE_ADDRESS_TOKEN_TRANSFERS_COUNTER_PERIOD
BLOCKSCOUT_CONTAINER_PARAMS += -e 'CACHE_ADDRESS_TOKEN_TRANSFERS_COUNTER_PERIOD=$(CACHE_ADDRESS_TOKEN_TRANSFERS_COUNTER_PERIOD)'
endif