diff --git a/src/invidious.cr b/src/invidious.cr index d7c5b80b..bb06c3ec 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -217,6 +217,7 @@ end Kemal.config.powered_by_header = false add_handler FilteredCompressHandler.new add_handler APIHandler.new +add_handler DisableAPIHandler.new add_handler AuthHandler.new add_handler DenyFrame.new diff --git a/src/invidious/config.cr b/src/invidious/config.cr index 7853d9a3..e4763679 100644 --- a/src/invidious/config.cr +++ b/src/invidious/config.cr @@ -127,6 +127,10 @@ class Config property login_enabled : Bool = true property registration_enabled : Bool = true property statistics_enabled : Bool = false + # When set to false, disables the unauthenticated API endpoints + # (videos, channels, search, etc.) that can be abused by bots. + # Authenticated API endpoints (/api/v1/auth/*) are unaffected. + property enable_api : Bool = true property admins : Array(String) = [] of String property external_port : Int32? = nil property default_user_preferences : ConfigPreferences = ConfigPreferences.from_yaml("") diff --git a/src/invidious/helpers/handlers.cr b/src/invidious/helpers/handlers.cr index 7c5ef118..a7ee75c1 100644 --- a/src/invidious/helpers/handlers.cr +++ b/src/invidious/helpers/handlers.cr @@ -133,6 +133,29 @@ class APIHandler < Kemal::Handler end end +class DisableAPIHandler < Kemal::Handler + # Blocks unauthenticated API endpoints when `enable_api` is false. + # Authenticated endpoints (/api/v1/auth/*) and stats are excluded. + {% for method in %w(GET POST PUT HEAD DELETE PATCH OPTIONS) %} + only ["/api/v1/*"], {{method}} + {% end %} + exclude ["/api/v1/auth/*"], "GET" + exclude ["/api/v1/auth/*"], "POST" + exclude ["/api/v1/auth/*"], "DELETE" + exclude ["/api/v1/auth/*"], "PATCH" + exclude ["/api/v1/auth/*"], "PUT" + exclude ["/api/v1/stats"], "GET" + + def call(env) + if only_match?(env) && !exclude_match?(env) && !CONFIG.enable_api + env.response.content_type = "application/json" + env.response.status_code = 403 + return {"error" => "The API has been disabled by the administrator."}.to_json + end + call_next env + end +end + class DenyFrame < Kemal::Handler exclude ["/embed/*"]