From ad3f0357e6bd5c1ded0236c500dad8ac28ac9dcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toni=20F=C3=B6rster?= Date: Mon, 13 Nov 2023 11:53:58 +0100 Subject: [PATCH] support for private instances This is a modification of PR #3728. And addresses #446 Server admins can set the instance to be private. Which means it is only accessible with a registered user account. The endpoints `/api/v1/popular` and `/api/v1/trending` are whitelisted because some clients expect them to be open. --- config/config.example.yml | 30 ++++++++++++++++-- src/invidious/config.cr | 4 +++ src/invidious/routes/before_all.cr | 49 ++++++++++++++++++++++-------- 3 files changed, 69 insertions(+), 14 deletions(-) diff --git a/config/config.example.yml b/config/config.example.yml index b44fcc0e..1e9b1264 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -236,6 +236,32 @@ https_only: false # Users and accounts # ----------------------------- +## +## Allow/Forbid the usage of the Invidious Instance without an account. +## Only /login and /privacy are accessible on such instances for unregistered +## users on the web interface. Moreover, certain API endpoints are accessible, +## to allow third-party clients to add the instance and login to an existing +## account. +## +## To avoid any data leakage it is recommended to set popular_enabled and +## statistics_enabled to 'false'. Furthermore, registration_enabled should be +## set to 'false' to only allow existing users to access the instance. +## +## Accepted values: true, false +## Default: false +## +#private_instance: false + +## +## Redirect request to the login page on private instances. Also requires +## login_enabled to be 'true', otherwise the server sends status code 401 +## and closes the connection. +## +## Accepted values: true, false +## Default: false +## +#redirect_login: false + ## ## Allow/Forbid Invidious (local) account creation. Invidious ## accounts allow users to subscribe to channels and to create @@ -777,7 +803,7 @@ default_user_preferences: ## ## Default dash video quality. ## - ## Note: this setting only takes effet if the + ## Note: this setting only takes effect if the ## 'quality' parameter is set to "dash". ## ## Accepted values: @@ -812,7 +838,7 @@ default_user_preferences: ## Default: true ## #vr_mode: true - + ## ## Save the playback position ## Allow to continue watching at the previous position when diff --git a/src/invidious/config.cr b/src/invidious/config.cr index 429d9246..3d907020 100644 --- a/src/invidious/config.cr +++ b/src/invidious/config.cr @@ -92,6 +92,10 @@ class Config property use_pubsub_feeds : Bool | Int32 = false property popular_enabled : Bool = true property captcha_enabled : Bool = true + # Only allow usage of the Invidious instance with an existing account + property private_instance : Bool = false + # Redirected requests to the login page on a private instance. Requires login_enabled: true + property redirect_login : Bool = false property login_enabled : Bool = true property registration_enabled : Bool = true property statistics_enabled : Bool = false diff --git a/src/invidious/routes/before_all.cr b/src/invidious/routes/before_all.cr index 396840a4..ad547875 100644 --- a/src/invidious/routes/before_all.cr +++ b/src/invidious/routes/before_all.cr @@ -61,18 +61,6 @@ module Invidious::Routes::BeforeAll env.response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains; preload" end - return if { - "/sb/", - "/vi/", - "/s_p/", - "/yts/", - "/ggpht/", - "/api/manifest/", - "/videoplayback", - "/latest_version", - "/download", - }.any? { |r| env.request.resource.starts_with? r } - if env.request.cookies.has_key? "SID" sid = env.request.cookies["SID"].value @@ -100,6 +88,43 @@ module Invidious::Routes::BeforeAll end end + unregistered_path_whitelist = { + "/login", + "/privacy" + "/api/v1/stats", + # TODO: popular and trending are here for clients that require these endpoints to be accessible e.g. Clipious + # can be removed as soon as those clients can handele these request on private instances + "/api/v1/popular", + "/api/v1/trending", + "/feed/webhook/v1:", + "/api/v1/videos/dQw4w9WgXcQ", + "/api/v1/comments/jNQXAC9IVRw", + } + + if CONFIG.private_instance && !env.get?("user") && !unregistered_path_whitelist.any? { |r| env.request.path.starts_with? r } + if CONFIG.redirect_login && CONFIG.login_enabled + env.response.headers["Location"] = "/login" + haltf env, status_code: 302 + else + env.response.status_code = 401 + env.response.close + end + end + + return if { + "/sb/", + "/vi/", + "/s_p/", + "/yts/", + "/ggpht/", + "/download", + "/licenses", + "/api/manifest/", + "/videoplayback", + "/latest_version", + "/opensearch.xml", + }.any? { |r| env.request.resource.starts_with? r } + dark_mode = convert_theme(env.params.query["dark_mode"]?) || preferences.dark_mode.to_s thin_mode = env.params.query["thin_mode"]? || preferences.thin_mode.to_s thin_mode = thin_mode == "true"