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