net.py: the verifying HTTPS handler triggers Cloudflare challenges on Android (DoodStream)

Open
#1,456 10 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
35/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Quiet
Tech stack
python
Domain
networking

Research direction

Start by reading lib/net.py, especially _update_opener and the three urllib request calls, then inspect realdebrid.py and hmf.__get_resolvers. Reproduce the Android Kodi 21.3 DoodStream behavior if possible and confirm the proposed opener and TLS-context scope with maintainers. Done means the approved design preserves strict verification for debrid requests without triggering Cloudflare challenges elsewhere.

Written by the indexing model from the issue text.

Description

Since 167b82e the verifying branch of the ssl setup in lib/net.py actually installs its HTTPSHandler. On Android with Kodi 21 that makes every DoodStream request come back as a Cloudflare challenge:

[hoster]: resolve: https://vide0.net/e/nhpifwf3lkvc
ResolveURL: ResolverError - From: DoodStream Link: https://vide0.net/e/nhpifwf3lkvc: Cloudflare challenge

That is net.py's own detection firing — HTTP 403 with server: cloudflare and cf-mitigated: challenge.

(This description replaces an earlier version of it. That one argued the branch had never been active and proposed removing it — both wrong, and it would have taken cafile and ALPN away from RealDebrid. Thanks for the correction; everything below is the result of chasing it properly.)

It is the OpenSSL version, not Python and not the platform

Same Android device, same zip, one DoodStream play each, with a line logging what the branch actually does:

Kodi 22 B1   python=3.14.6   openssl=OpenSSL 3.5.7 9 Jun 2026
             verifying branch OK, handler installed | min=770 max=772

Kodi 21.3 python=3.11.7 openssl=OpenSSL 1.1.1w 11 Sep 2023
verifying branch OK, handler installed | min=770 max=772

  attempts Cloudflare challenge play file link
Kodi 21.3 3 6 0
Kodi 22 B1 3 0 3

All three on 22 went through to demuxer and both streams on cloudatacdn.com.

The branch installs correctly on both — 770 / 772 is TLSv1_1 / TLSv1_3, exactly as set. So nothing is failing silently, and RealDebrid is properly verified on Kodi 22. The only relevant difference is the TLS stack: cipher list, extensions and offered groups in the ClientHello differ between 1.1.1w and 3.5.7, and that is what Cloudflare fingerprints. 1.1.1 went EOL in September 2023. Nothing in your code is wrong; on the older stack it just produces a profile Cloudflare no longer accepts, which is also why Windows, Linux and Kodi 22 all look fine.

Why a global switch cannot fix Kodi 21

The two callers want opposite things there — RealDebrid needs cafile and ALPN, hosts behind Cloudflare must not have them — and they cannot be told apart, because _update_opener ends in:

opener = urllib_request.build_opener(*handlers)
urllib_request.install_opener(opener)

That is global, so the last Net constructed wins for everybody. hmf.__get_resolvers instantiates every relevant resolver before calling one of them, so the context in effect at request time comes from whichever resolver happened to be built last, not from the one making the request. It works today only because every Net builds the same context.

Prototype

Two changes. First, give each Net its own opener instead of installing it globally:

-        opener = urllib_request.build_opener(*handlers)
-        urllib_request.install_opener(opener)
+        self._opener = urllib_request.build_opener(*handlers)

and the three urllib_request.urlopen(...) calls become self._opener.open(...).

Second, make the strict context opt-in:

-    def __init__(self, cookie_file='', proxy='', user_agent='', ssl_verify=True, http_debug=False):
+    def __init__(self, cookie_file='', proxy='', user_agent='', ssl_verify=True, http_debug=False,
+                 strict_tls=False):
...
+        self._strict_tls = strict_tls
...
-        else:
+        elif self._strict_tls:

with realdebrid asking for it:

-        self.net = common.Net()
+        self.net = common.Net(strict_tls=True)

Both contexts measured side by side

I have no RealDebrid account, and it cannot be worked around — _is_enabled() is get_setting('enabled') == 'true' and cls.get_setting('token'), so without a token it is never instantiated and its Net is never built.

I do have Premiumize, so I wired strict_tls=True into premiumize_me as a stand-in. One session on Kodi 21.3, one DoodStream play:

4x   STRICT OK | min=770 max=772 | cafile=/data/.../assets/system/certs/cacert.pem
29x  default | urllib context | python=3.11.7 openssl=OpenSSL 1.1.1w

Both contexts alive in the same session, each on the right caller, and DoodStream resolved 2 of 2 with no challenges — 4 of 4 in an earlier run. That is the part that matters: the instance-owned opener really does keep them apart.

Premiumize also reached its API over the strict context. valid_url calls get_all_hosters(), which does a real request to premiumize.me, and that method logs Error getting Premiumize hosts at LOGERROR on failure — the log contains no Premiumize line at all. Absence of an error rather than a positive confirmation, but it is as close as I can get without an RD subscription.

What still needs someone else

Whether RealDebrid itself is unaffected. It receives exactly the context master builds today, but the opener change touches every caller including the debrid resolvers, so that wants a look from you or an RD user.

Not opening a PR — this changes the Net signature and removes global opener state, which is your call. Say what you would like and I will build and measure it on the Android 21.3 device.

net.py

realdebrid.py

Dominant language
Python
Stars
231
Forks
87
Avg merge
1d 3h
Merged PRs (30d)
21

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from Gujal00/ResolveURL

All issues in Gujal00/ResolveURL

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.