mirror of
				https://github.com/iv-org/invidious.git
				synced 2025-10-31 12:42:09 +00:00 
			
		
		
		
	SigHelper: Make signature server optional and configurable
This commit is contained in:
		| @@ -153,6 +153,15 @@ Invidious::Database.check_integrity(CONFIG) | ||||
|   {% puts "\nDone checking player dependencies, now compiling Invidious...\n" %} | ||||
| {% end %} | ||||
|  | ||||
| # Misc | ||||
|  | ||||
| DECRYPT_FUNCTION = | ||||
|   if sig_helper_address = CONFIG.signature_server.presence | ||||
|     IV::DecryptFunction.new(sig_helper_address) | ||||
|   else | ||||
|     nil | ||||
|   end | ||||
|  | ||||
| # Start jobs | ||||
|  | ||||
| if CONFIG.channel_threads > 0 | ||||
|   | ||||
| @@ -118,6 +118,10 @@ class Config | ||||
|   # Connect to YouTube over 'ipv6', 'ipv4'. Will sometimes resolve fix issues with rate-limiting (see https://github.com/ytdl-org/youtube-dl/issues/21729) | ||||
|   @[YAML::Field(converter: Preferences::FamilyConverter)] | ||||
|   property force_resolve : Socket::Family = Socket::Family::UNSPEC | ||||
|  | ||||
|   # External signature solver server socket (either a path to a UNIX domain socket or "<IP>:<Port>") | ||||
|   property signature_server : String? = nil | ||||
|  | ||||
|   # Port to listen for connections (overridden by command line argument) | ||||
|   property port : Int32 = 3000 | ||||
|   # Host to bind (overridden by command line argument) | ||||
|   | ||||
| @@ -72,8 +72,12 @@ module Invidious::SigHelper | ||||
|   #  High-level functions | ||||
|   # ---------------------- | ||||
|  | ||||
|   module Client | ||||
|     extend self | ||||
|   class Client | ||||
|     @mux : Multiplexor | ||||
|  | ||||
|     def initialize(uri_or_path) | ||||
|       @mux = Multiplexor.new(uri_or_path) | ||||
|     end | ||||
|  | ||||
|     # Forces the server to re-fetch the YouTube player, and extract the necessary | ||||
|     # components from it (nsig function code, sig function code, signature timestamp). | ||||
| @@ -148,7 +152,7 @@ module Invidious::SigHelper | ||||
|     end | ||||
|  | ||||
|     private def send_request(request : Request, &) | ||||
|       channel = Multiplexor::INSTANCE.send(request) | ||||
|       channel = @mux.send(request) | ||||
|       slice = channel.receive | ||||
|       return yield slice | ||||
|     rescue ex | ||||
| @@ -172,10 +176,8 @@ module Invidious::SigHelper | ||||
|  | ||||
|     @conn : Connection | ||||
|  | ||||
|     INSTANCE = new("") | ||||
|  | ||||
|     def initialize(url : String) | ||||
|       @conn = Connection.new(url) | ||||
|     def initialize(uri_or_path) | ||||
|       @conn = Connection.new(uri_or_path) | ||||
|       listen | ||||
|     end | ||||
|  | ||||
| @@ -275,13 +277,14 @@ module Invidious::SigHelper | ||||
|     {% end %} | ||||
|  | ||||
|     def initialize(host_or_path : String) | ||||
|       if host_or_path.empty? | ||||
|         host_or_path = "/tmp/inv_sig_helper.sock" | ||||
|       end | ||||
|  | ||||
|       case host_or_path | ||||
|       when .starts_with?('/') | ||||
|         @socket = UNIXSocket.new(host_or_path) | ||||
|         # Make sure that the file exists | ||||
|         if File.exists?(host_or_path) | ||||
|           @socket = UNIXSocket.new(host_or_path) | ||||
|         else | ||||
|           raise Exception.new("SigHelper: '#{host_or_path}' no such file") | ||||
|         end | ||||
|       when .starts_with?("tcp://") | ||||
|         uri = URI.parse(host_or_path) | ||||
|         @socket = TCPSocket.new(uri.host.not_nil!, uri.port.not_nil!) | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| require "http/params" | ||||
| require "./sig_helper" | ||||
|  | ||||
| struct Invidious::DecryptFunction | ||||
| class Invidious::DecryptFunction | ||||
|   @last_update : Time = Time.utc - 42.days | ||||
|  | ||||
|   def initialize | ||||
|   def initialize(uri_or_path) | ||||
|     @client = SigHelper::Client.new(uri_or_path) | ||||
|     self.check_update | ||||
|   end | ||||
|  | ||||
| @@ -16,19 +17,18 @@ struct Invidious::DecryptFunction | ||||
|  | ||||
|     # Get the time when the player was updated, in the event where | ||||
|     # multiple invidious processes are run in parallel. | ||||
|     player_ts = Invidious::SigHelper::Client.get_player_timestamp | ||||
|     player_time = Time.unix(player_ts || 0) | ||||
|     player_time = Time.unix(@client.get_player_timestamp || 0) | ||||
|  | ||||
|     if (now - player_time) > 5.minutes | ||||
|       LOGGER.debug("Signature: Player might be outdated, updating") | ||||
|       Invidious::SigHelper::Client.force_update | ||||
|       @client.force_update | ||||
|       @last_update = Time.utc | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def decrypt_nsig(n : String) : String? | ||||
|     self.check_update | ||||
|     return SigHelper::Client.decrypt_n_param(n) | ||||
|     return @client.decrypt_n_param(n) | ||||
|   rescue ex | ||||
|     LOGGER.debug(ex.message || "Signature: Unknown error") | ||||
|     LOGGER.trace(ex.inspect_with_backtrace) | ||||
| @@ -37,7 +37,7 @@ struct Invidious::DecryptFunction | ||||
|  | ||||
|   def decrypt_signature(str : String) : String? | ||||
|     self.check_update | ||||
|     return SigHelper::Client.decrypt_sig(str) | ||||
|     return @client.decrypt_sig(str) | ||||
|   rescue ex | ||||
|     LOGGER.debug(ex.message || "Signature: Unknown error") | ||||
|     LOGGER.trace(ex.inspect_with_backtrace) | ||||
| @@ -46,7 +46,7 @@ struct Invidious::DecryptFunction | ||||
|  | ||||
|   def get_sts : UInt64? | ||||
|     self.check_update | ||||
|     return SigHelper::Client.get_signature_timestamp | ||||
|     return @client.get_signature_timestamp | ||||
|   rescue ex | ||||
|     LOGGER.debug(ex.message || "Signature: Unknown error") | ||||
|     LOGGER.trace(ex.inspect_with_backtrace) | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| private DECRYPT_FUNCTION = IV::DecryptFunction.new | ||||
|  | ||||
| enum VideoType | ||||
|   Video | ||||
|   Livestream | ||||
| @@ -108,14 +106,14 @@ struct Video | ||||
|  | ||||
|       LOGGER.debug("Videos: Decoding '#{cfr}'") | ||||
|  | ||||
|       unsig = DECRYPT_FUNCTION.decrypt_signature(cfr["s"]) | ||||
|       unsig = DECRYPT_FUNCTION.try &.decrypt_signature(cfr["s"]) | ||||
|       params[sp] = unsig if unsig | ||||
|     else | ||||
|       url = URI.parse(fmt["url"].as_s) | ||||
|       params = url.query_params | ||||
|     end | ||||
|  | ||||
|     n = DECRYPT_FUNCTION.decrypt_nsig(params["n"]) | ||||
|     n = DECRYPT_FUNCTION.try &.decrypt_nsig(params["n"]) | ||||
|     params["n"] = n if n | ||||
|  | ||||
|     params["host"] = url.host.not_nil! | ||||
|   | ||||
| @@ -2,8 +2,6 @@ | ||||
| # This file contains youtube API wrappers | ||||
| # | ||||
|  | ||||
| private STS_FETCHER = IV::DecryptFunction.new | ||||
|  | ||||
| module YoutubeAPI | ||||
|   extend self | ||||
|  | ||||
| @@ -462,7 +460,7 @@ module YoutubeAPI | ||||
|     } of String => String | Int64 | ||||
|  | ||||
|     if {"WEB", "TVHTML5"}.any? { |s| client_config.name.starts_with? s } | ||||
|       if sts = STS_FETCHER.get_sts | ||||
|       if sts = DECRYPT_FUNCTION.try &.get_sts | ||||
|         playback_ctx["signatureTimestamp"] = sts.to_i64 | ||||
|       end | ||||
|     end | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Samantaz Fox
					Samantaz Fox