SSLError в запросах при упаковке как OS X .app

Я разрабатываю приложение для OS X. Приложение включает в себя связь с сервером через запросы Python, используя безопасное соединение.

Я могу запустить файл python, который я собираюсь упаковать, и это успешно с SSL-соединением. Однако, когда я упаковываю файл с py2app и пытаюсь запустить его, я получаю следующую ошибку:

Traceback (most recent call last):
File "/Users/yossi/Documents/repos/drunken-octo-nemesis/dist/drunken-octo.app/Contents/Resources/__boot__.py", line 338, in <module>
    _run()
File "/Users/yossi/Documents/repos/drunken-octo-nemesis/dist/drunken-octo.app/Contents/Resources/__boot__.py", line 333, in _run
    exec(compile(source, path, 'exec'), globals(), globals())
File "/Users/yossi/Documents/repos/drunken-octo-nemesis/dist/drunken-octo.app/Contents/Resources/media_test.py", line 16, in <module>
    cmpbl.syncWithCloud()
File "src/compare_book_lists.pyc", line 172, in syncWithCloud
File "src/compare_book_lists.pyc", line 64, in checkMediaOnCloud
File "src/get_cloud_book_list.pyc", line 26, in getCloudFulfilledBookList
File "requests/api.pyc", line 55, in get
File "requests/api.pyc", line 44, in request
File "requests/sessions.pyc", line 354, in request
File "requests/sessions.pyc", line 460, in send
File "requests/adapters.pyc", line 250, in send
requests.exceptions.SSLError: [Errno 185090050] _ssl.c:340: error:0B084002:x509 certificate routines:X509_load_cert_crl_file:system lib
2013-06-12 11:39:49.119 drunken-octo[1656:707] drunken-octo Error

Мне удалось успешно упаковать часть моего заявления. Проблема начинается, когда целевой файл где-то в цепочке зависит от запросов.

Я использую zc.buildout для организации своего импорта. Поэтому я работаю в локальном интерпретаторе Python, созданном компоновщиком, поэтому любые исправления, к сожалению, будет проще реализовать, если они не предполагают изменение системы Python. Тем не менее, все предложения приветствуются, и я сделаю все возможное, чтобы изменить их для моей специфики.

Это происходит только тогда, когда я запускаю упакованное приложение. Есть идеи?

4 ответа

Решение

Обходной путь easyiests - добавить опцию для py2app в ваш файл setup.py:

setup(
   ...
   options={
      'py2app':{
          'packages': [ 'requests' ]
       }
   }
)

Это включает в себя весь пакет в комплекте приложений, включая пакет сертификатов.

Я подал проблему для этого в моем трекере py2app, будущая версия py2app будет включать логику для обнаружения использования библиотеки запросов и будет автоматически копировать комплект сертификатов.

Requests использует комплект сертификатов для проверки подлинности сервера. Этот комплект хранится (он должен быть) в отдельном файле. Обычно запрашивает корабли со своим собственным пакетом, но если он упакован в один файл, пакет теряется. Вы можете отправить новый пакет вместе с вашим приложением или позволить запросам использовать общесистемный сертификат. (Я не знаю, где OS X хранит этот файл, но на моем linux box его /etc/ssl/certs/ca-certificates.crt)

Чтобы увидеть, где запросы ожидают файл, вы можете сделать это:

import requests
print(requests.certs.where())

Чтобы изменить местоположение, где запросы ищет пакет, вы можете передать verify-параметр со строковым значением:

import requests
requests.get("https://httpbin.org/", verify="path/to/your/bundle")

Если вы не хотите каждый раз передавать параметр, создайте сеанс и настройте его для использования вашего пакета:

import requests
s = requests.Session()
s.verify = "path/to/your/bundle"
s.get("https://httpbin.org")

Предыдущий принятый ответ не работал для меня - возможно, способ работы запросов изменился.

Чтобы решить эту проблему, я изменил мои параметры setup.py, чтобы включить пакет certifi, в котором находится файл сертификата pem:

OPTIONS = {'argv_emulation': True,'packages': ['certifi']}

Затем добавил это в запросы запросов Python:

is_py2app = hasattr(sys, "frozen")
pem_path = "lib/python2.7/certifi/cacert.pem" if is_py2app else None 

...

requests.get(..., verify=pem_path)

Это может отличаться в других версиях Python.

Я столкнулся с той же проблемой, и мне пришлось распространять свое приложение среди пользователей, у которых может не быть установленный Python или пакет certifi на их Mac. Опираясь на вдохновляющие ответы здесь, я пришел к следующему решению.

Шаг 1. Загрузите пакет OpenSSL с веб- сайта https://www.openssl.org/source/. найти /openssl-1.0.2n/certs/demo/ca-cert.pem и поместите его в тот же каталог, что и ваша программа на Python (например, main.py).

Шаг 2: Создайте setup.py как обычно, но включают ca-cert.pem в списке DATA_FILES. Так что ваши setup.py должен выглядеть примерно так:

from setuptools import setup

APP = ['main.py']
DATA_FILES = ['ca-cert.pem']
OPTIONS = {'argv_emulation': False}

setup(
    app=APP,
    data_files=DATA_FILES,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)

Шаг 3: Используйте verify Параметр, поэтому запросы будут использовать предоставленный вами файл сертификата.

import requests
requests.get("https://httpbin.org/", verify="ca-cert.pem")

Кроме того, вы также можете создать сеанс, так что вам не нужно указывать verify каждый раз.

import requests
s = requests.Session()
s.verify = "ca-cert.pem"
s.get("https://httpbin.org")

Шаг 4: Упакуйте приложение, используя py2app как обычно. Полученное приложение должно нормально работать.

python setup.py py2app
Другие вопросы по тегам