From 711e72c292327674c4a0593fdbb83d6347738ec9 Mon Sep 17 00:00:00 2001 From: dirkf Date: Thu, 6 Feb 2025 21:09:00 +0000 Subject: [PATCH] [JSInterp] Fix bit-shift coercion for player 9c6dfc4a --- test/test_jsinterp.py | 4 ++++ test/test_youtube_signature.py | 4 ++++ youtube_dl/compat.py | 5 +++++ youtube_dl/jsinterp.py | 27 +++++++++++++++++++++------ 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/test/test_jsinterp.py b/test/test_jsinterp.py index 12e7b9b94..6c34bc896 100644 --- a/test/test_jsinterp.py +++ b/test/test_jsinterp.py @@ -459,6 +459,10 @@ class TestJSInterpreter(unittest.TestCase): self._test('function f(){return undefined >> 5}', 0) self._test('function f(){return 42 << NaN}', 42) self._test('function f(){return 42 << Infinity}', 42) + self._test('function f(){return 0.0 << null}', 0) + self._test('function f(){return NaN << 42}', 0) + self._test('function f(){return "21.9" << 1}', 42) + self._test('function f(){return 21 << 4294967297}', 42) def test_negative(self): self._test('function f(){return 2 * -2.0 ;}', -4) diff --git a/test/test_youtube_signature.py b/test/test_youtube_signature.py index fcbc9d7a8..67ef75fde 100644 --- a/test/test_youtube_signature.py +++ b/test/test_youtube_signature.py @@ -219,6 +219,10 @@ _NSIG_TESTS = [ 'https://www.youtube.com/s/player/2f1832d2/player_ias.vflset/en_US/base.js', 'YWt1qdbe8SAfkoPHW5d', 'RrRjWQOJmBiP', ), + ( + 'https://www.youtube.com/s/player/9c6dfc4a/player_ias.vflset/en_US/base.js', + 'jbu7ylIosQHyJyJV', 'uwI0ESiynAmhNg', + ), ] diff --git a/youtube_dl/compat.py b/youtube_dl/compat.py index c621f7476..26b655fb6 100644 --- a/youtube_dl/compat.py +++ b/youtube_dl/compat.py @@ -3116,17 +3116,21 @@ else: compat_kwargs = lambda kwargs: kwargs +# compat_numeric_types try: compat_numeric_types = (int, float, long, complex) except NameError: # Python 3 compat_numeric_types = (int, float, complex) +# compat_integer_types try: compat_integer_types = (int, long) except NameError: # Python 3 compat_integer_types = (int, ) +# compat_int +compat_int = compat_integer_types[-1] if sys.version_info < (2, 7): def compat_socket_create_connection(address, timeout, source_address=None): @@ -3532,6 +3536,7 @@ __all__ = [ 'compat_http_client', 'compat_http_server', 'compat_input', + 'compat_int', 'compat_integer_types', 'compat_itertools_count', 'compat_itertools_zip_longest', diff --git a/youtube_dl/jsinterp.py b/youtube_dl/jsinterp.py index 7835187f5..2859bc734 100644 --- a/youtube_dl/jsinterp.py +++ b/youtube_dl/jsinterp.py @@ -24,6 +24,8 @@ from .compat import ( compat_collections_chain_map as ChainMap, compat_contextlib_suppress, compat_filter as filter, + compat_int, + compat_integer_types, compat_itertools_zip_longest as zip_longest, compat_map as map, compat_numeric_types, @@ -70,14 +72,27 @@ class JS_Undefined(object): pass -def _js_bit_op(op): +def _js_bit_op(op, is_shift=False): - def zeroise(x): - return 0 if x in (None, JS_Undefined, _NaN, _Infinity) else x + def zeroise(x, is_shift_arg=False): + if isinstance(x, compat_integer_types): + return (x % 32) if is_shift_arg else (x & 0xffffffff) + try: + x = float(x) + if is_shift_arg: + x = int(x % 32) + elif x < 0: + x = -compat_int(-x % 0xffffffff) + else: + x = compat_int(x % 0xffffffff) + except (ValueError, TypeError): + # also here for int(NaN), including float('inf') % 32 + x = 0 + return x @wraps_op(op) def wrapped(a, b): - return op(zeroise(a), zeroise(b)) & 0xffffffff + return op(zeroise(a), zeroise(b, is_shift)) & 0xffffffff return wrapped @@ -253,8 +268,8 @@ def _js_typeof(expr): # avoid dict to maintain order # definition None => Defined in JSInterpreter._operator _OPERATORS = ( - ('>>', _js_bit_op(operator.rshift)), - ('<<', _js_bit_op(operator.lshift)), + ('>>', _js_bit_op(operator.rshift, True)), + ('<<', _js_bit_op(operator.lshift, True)), ('+', _js_add), ('-', _js_arith_op(operator.sub)), ('*', _js_arith_op(operator.mul)),