在应用中为 discord.py 安装 ssl 证书

Install ssl certificates for discord.py in an app

我正在制作一个基于 python 的 mac 应用程序,它使用 discord.py 来处理不和谐的事情。正如我从以前制作 discord 机器人的经验中了解到的那样,运行ning discord 机器人要求您 运行 Install Certificates.command 在您的 python 版本中。但是,如果其他用户使用此应用程序,我不想要求他们安装 python。我从 Install Certificates.command 中提取了一段代码,认为它会将证书放在用户计算机上的正确位置。但是,测试人员在他们的计算机上运行该应用程序时遇到此错误 运行:

Traceback (most recent call last):
  File "Interface.py", line 136, in <module>
  File "installCerts.py", line 25, in installCerts
FileNotFoundError: [Errno 2] No such file or directory: '/Library/Frameworks/Python.framework/Versions/3.8/etc/openssl'
[2514] Failed to execute script 'Interface' due to unhandled exception: [Errno 2] No such file or directory: '/Library/Frameworks/Python.framework/Versions/3.8/etc/openssl'
[2514] Traceback:
Traceback (most recent call last):
  File "Interface.py", line 136, in <module>
  File "installCerts.py", line 25, in installCerts
FileNotFoundError: [Errno 2] No such file or directory: '/Library/Frameworks/Python.framework/Versions/3.8/etc/openssl'

很清楚这个错误在说什么:他们没有安装 python (3.8),所以它不能把 ssl 证书放在任何地方(这是因为应用程序是 运行在 python 3.8 环境中)。

对了,错误中提到的路径是ssl.get_default_verify_paths().openssl_cafile给的路径的目录名。

我不是很精通网络连接之类的细节,所以我不知道这些证书的确切作用。这是我的问题:

是否可以在用户不在计算机上安装 python 的情况下使它工作?

即我可以将 ssl 证书添加到应用程序的本地 python 版本吗(据我所知,在我的应用程序中,python 只是一个大的捆绑 exec 文件)?在文件系统的深处是否有某个地方可以放置证书以使不和谐的连接发生? .几乎任何解决方案都会受到赞赏。

附加信息:

我安装证书的代码:

STAT_0o775 = (stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
                  | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP
                  | stat.S_IROTH | stat.S_IXOTH)

    openssl_dir, openssl_cafile = os.path.split(
        ssl.get_default_verify_paths().openssl_cafile)
    os.chdir(openssl_dir) #Error happens here
    relpath_to_certifi_cafile = os.path.relpath(certifi.where())
    print(" -- removing any existing file or link")
    try:
        os.remove(openssl_cafile)
    except FileNotFoundError:
        pass
    print(" -- creating symlink to certifi certificate bundle")
    os.symlink(relpath_to_certifi_cafile, openssl_cafile)
    print(" -- setting permissions")
    os.chmod(openssl_cafile, STAT_0o775)
    print(" -- update complete")

当用户没有安装正确的证书时discord.py抛出的错误:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/aiohttp/connector.py", line 969, in _wrap_create_connection
    return await self._loop.create_connection(*args, **kwargs)  # type: ignore  # noqa
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncio/base_events.py", line 1050, in create_connection
    transport, protocol = await self._create_connection_transport(
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncio/base_events.py", line 1080, in _create_connection_transport
    await waiter
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncio/sslproto.py", line 529, in data_received
    ssldata, appdata = self._sslpipe.feed_ssldata(data)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncio/sslproto.py", line 189, in feed_ssldata
    self._sslobj.do_handshake()
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/ssl.py", line 944, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1125)

如果您需要更多信息,请告诉我。

好的。这非常艰难,但经过大量研究后我得到了答案。 python 中的 ssl 基本上只是 openSSL 的一组绑定。当您执行 import ssl 时,它会构建一个 openSSL 环境(我认为我在这里使用的词不完全正确)。如您所见,它默认位于 Python 中的 openSSL 文件夹,因为从 python 的角度来看,这是 openSSL 保存其证书的地方。事实证明,ssl.DefaultVerifyPaths 个对象还有其他属性,即 cafile。这就是我如何按照自己的意愿创建通往证书的路径。你看,当 openSSL 构建时,它会查找环境变量 SSL_CERT_FILE。只要我在导入 ssl 之前用 os.environ 设置该变量,它就会起作用,因为 ssl 会找到证书。我将 installCerts 简化为以下内容:

import os
import stat
import certifi

def installCerts():
    os.environ['SSL_CERT_FILE'] = certifi.where()
    import ssl
    # ssl build needs to happen after enviro var is set
    STAT_0o775 = (stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
                  | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP
                  | stat.S_IROTH | stat.S_IXOTH)
    cafile = ssl.get_default_verify_paths().cafile
    os.chmod(cafile, STAT_0o775)

而且它现在似乎在其他人的计算机上运行良好,无需他们安装 python。

这个问题对我有帮助: