Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for using Invidious through a HTTP Proxy #4270

Merged
merged 4 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions config/config.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,17 @@ https_only: false
##
#force_resolve:

##
## Configuration for using a HTTP proxy
##
## If unset, then no HTTP proxy will be used.
##
http_proxy:
user:
password:
host:
port:


##
## Use Innertube's transcripts API instead of timedtext for closed captions
Expand Down
8 changes: 6 additions & 2 deletions shard.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ shards:

backtracer:
git: https://github.com/sija/backtracer.cr.git
version: 1.2.1
version: 1.2.2

db:
git: https://github.com/crystal-lang/crystal-db.git
Expand All @@ -20,6 +20,10 @@ shards:
git: https://github.com/crystal-loot/exception_page.git
version: 0.2.2

http_proxy:
git: https://github.com/mamantoha/http_proxy.git
version: 0.10.3

kemal:
git: https://github.com/kemalcr/kemal.git
version: 1.1.2
Expand All @@ -42,7 +46,7 @@ shards:

spectator:
git: https://github.com/icy-arctic-fox/spectator.git
version: 0.10.4
version: 0.10.6

sqlite3:
git: https://github.com/crystal-lang/crystal-sqlite3.git
Expand Down
3 changes: 3 additions & 0 deletions shard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ dependencies:
athena-negotiation:
github: athena-framework/negotiation
version: ~> 0.1.1
http_proxy:
github: mamantoha/http_proxy
version: ~> 0.10.3

development_dependencies:
spectator:
Expand Down
1 change: 1 addition & 0 deletions src/invidious.cr
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ require "kilt"
require "./ext/kemal_content_for.cr"
require "./ext/kemal_static_file_handler.cr"

require "http_proxy"
require "athena-negotiation"
require "openssl/hmac"
require "option_parser"
Expand Down
11 changes: 11 additions & 0 deletions src/invidious/config.cr
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ struct ConfigPreferences
end
end

struct HTTPProxyConfig
include YAML::Serializable

property user : String
property password : String
property host : String
property port : Int32
end

class Config
include YAML::Serializable

Expand Down Expand Up @@ -126,6 +135,8 @@ class Config
property host_binding : String = "0.0.0.0"
# Pool size for HTTP requests to youtube.com and ytimg.com (each domain has a separate pool of `pool_size`)
property pool_size : Int32 = 100
# HTTP Proxy configuration
property http_proxy : HTTPProxyConfig? = nil

# Use Innertube's transcripts API instead of timedtext for closed captions
property use_innertube_for_captions : Bool = false
Expand Down
34 changes: 34 additions & 0 deletions src/invidious/helpers/crystal_class_overrides.cr
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,40 @@ end
class HTTP::Client
property family : Socket::Family = Socket::Family::UNSPEC

# Override stdlib to automatically initialize proxy if configured
syeopite marked this conversation as resolved.
Show resolved Hide resolved
#
# Accurate as of crystal 1.10.1
SamantazFox marked this conversation as resolved.
Show resolved Hide resolved

def initialize(@host : String, port = nil, tls : TLSContext = nil)
check_host_only(@host)

{% if flag?(:without_openssl) %}
if tls
raise "HTTP::Client TLS is disabled because `-D without_openssl` was passed at compile time"
end
@tls = nil
{% else %}
@tls = case tls
when true
OpenSSL::SSL::Context::Client.new
when OpenSSL::SSL::Context::Client
tls
when false, nil
nil
end
{% end %}

@port = (port || (@tls ? 443 : 80)).to_i

self.proxy = make_configured_http_proxy_client() if CONFIG.http_proxy
end

def initialize(@io : IO, @host = "", @port = 80)
@reconnect = false

self.proxy = make_configured_http_proxy_client() if CONFIG.http_proxy
end

private def io
io = @io
return io if io
Expand Down
19 changes: 18 additions & 1 deletion src/invidious/yt_backend/connection_pool.cr
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,16 @@ struct YoutubeConnectionPool

def client(&block)
conn = pool.checkout
# Proxy needs to be reinstated every time we get a client from the pool
conn.proxy = make_configured_http_proxy_client() if CONFIG.http_proxy

begin
response = yield conn
rescue ex
conn.close
conn = HTTP::Client.new(url)

conn = HTTP::Client.new(url)
conn.proxy = make_configured_http_proxy_client() if CONFIG.http_proxy
conn.family = CONFIG.force_resolve
conn.family = Socket::Family::INET if conn.family == Socket::Family::UNSPEC
conn.before_request { |r| add_yt_headers(r) } if url.host == "www.youtube.com"
Expand Down Expand Up @@ -77,3 +81,16 @@ def make_client(url : URI, region = nil, force_resolve : Bool = false, &block)
client.close
end
end

def make_configured_http_proxy_client
# This method is only called when configuration for an HTTP proxy are set
config_proxy = CONFIG.http_proxy.not_nil!

return HTTP::Proxy::Client.new(
config_proxy.host,
config_proxy.port,

username: config_proxy.user,
password: config_proxy.password,
)
end
Loading