streamlink/streamlink-appimage

[plugin.api.websocket][error] [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)

Yesterday17 opened this issue · 10 comments

The same problem as niess/python-appimage#24 ?

This is not an AppImage packaging issue. Streamlink issues do not belong here. Also no debug log at all, which is useless.

This is not a streamlink issue. In fact it only breaks in appimage release. Please see the issue linked above.

What do you expect anyone to do here if you don't even post anything useful at all, like the exact appimage you were using and the exact command you were running which led to the problem?

The error message you've posted is coming from Streamlink's websocket module, and the issue is a TLS/SSL certificate issue. Streamlink's AppImages bundle a Python install which is built from the official Python manylinux2014 docker images, and all the latest dependencies are bundled as well, including certifi for the necessary root certificates.

The issue you've linked is unrelated.

The exception itself is self-explaining. Python (somehow) failed to get local issuer certificate. It's a CA issue, which does not exists in host environment at all.

Appimage prepared all the dependencies, but the local ca list could not be retrived. Why the issue is unrelated?

It seems the issue is actually unrelated, but the behavior is strange. I'll investigate it later to find out what has happened. Sorry for disturbing.

Streamlink doesn't set any custom paths for the cert param of any session initialization or specific request made by requests, which means it defaults to the value which certifi.where() returns. certify.where() returns its locally bundled cacert.pem file. This should work even in cases of AppImages, where the squashfs gets mounted to a temporary location before execution, because certify uses relative file paths.

requests however allows you to override this file via the REQUESTS_CA_BUNDLE or CURL_CA_BUNDLE env vars.

I tried to add $SSL_CERT_FILE manually with:

export SSL_CERT_FILE='path-to-cacert.pem'

And everything works now. I believe the issue is related. Shouldn't it be included in appimage like https://github.com/pypa/manylinux/blob/121d0775b4c738b668ede697ed7c07442519603b/docker/build_scripts/build.sh#L138-L146 do?

Let me have a look. I was talking about requests, but websocket-client apparently doesn't use the bundled CA file.

So there are two options to avoid having Streamlink use two different CA cert files:

  1. Set OpenSSL's SSL_CERT_FILE env var with a value pointing towards the cacert.pem file bundled by certifi in the AppImage's AppRun and only make changes to the AppImage. Optionally also only set it if it's unset on the user's system, so custom values can still be set.
  2. Update Streamlink's WebsocketClient and set the ca_cert parameter on the SSL options dict, with a default value of the cacert.pam file bundled by certifi, similar to all HTTP requests made by requests.
    streamlink/streamlink@9892d3d

Since Streamlink shouldn't be using two different implementations regardless whether an AppImage is used or not, the second solution sounds like a better idea.