2013-06-12 21 views
7

Sto sviluppando un'applicazione per OS X. L'applicazione prevede la comunicazione con un server tramite richieste python, utilizzando una connessione protetta.SSLError in Richieste durante il confezionamento come OS X .app

Sono in grado di eseguire il file python che intendo pacchetto e che riesce con la connessione SSL. Tuttavia, quando ho confezionare il file con py2app e provo a farlo funzionare, ottengo il seguente errore:

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 

sono stato in grado di confezionare una parte della mia applicazione con successo. Il problema inizia quando il file di destinazione dipende, da qualche parte nella catena, su Richieste.

Sto usando zc.buildout per organizzare le mie importazioni. Pertanto, sto eseguendo un interprete python locale creato dal buildout, quindi eventuali correzioni, sfortunatamente, saranno più facili da implementare se non implicano la modifica del sistema Python. Tuttavia, tutti i suggerimenti sono benvenuti e farò del mio meglio per modificarli per le mie specifiche.

Questo succede solo quando eseguo l'app pacchettizzata. Qualche idea?

risposta

6

L'easiests soluzione è aggiungere un'opzione per py2app al file setup.py:

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

Questo include l'intero pacchetto in bundle dell'applicazione, tra cui il pacchetto certificato.

Ho archiviato uno issue for this in my py2app tracker, una versione futura di py2app includerà la logica per rilevare l'utilizzo della libreria richiesta e copierà automaticamente il pacchetto di certificati.

+0

Ciao Ronald, questa soluzione alternativa sembra non funzionare più. Ci sono novità sull'aggiornamento a py2app? Grazie! –

3

Le richieste utilizzano un gruppo di certificati per verificare l'identità di un server. Questo pacchetto viene mantenuto (deve essere) in un file indipendente. Richiede normalmente le navi con il proprio bundle, ma se viene impacchettato in un unico file, il pacchetto viene perso. È possibile spedire un nuovo pacchetto accanto all'app o lasciare che le richieste utilizzino il certificato di sistema. (non so, dove OS X mantiene questo file, ma sulla mia macchina linux sua /etc/ssl/certs/ca-certificates.crt)

da vedere, in cui le richieste si attende che il file che si può fare questo:

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

Per modificare il posizione, in cui le richieste si presenta per il bundle si può passare il verify -parameter con un valore stringa:

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

Se non si vuole passare il parametro ogni volta, creare una sessione e configurarlo per utilizzare il vostro pacco :

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

La precedente risposta accettata non ha funzionato per me, forse il modo in cui le richieste di lavoro sono cambiate.

Per risolvere questo ho cambiato le mie opzioni setup.py includere il pacchetto certifi in cui il file del certificato PEM vive:

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

poi aggiunti presente alle richieste Python chiama:

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

... 

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

Questo potrebbe essere diverso su altre versioni di Python.

+0

Sì, questo è stato un passo importante anche per il mio pacchetto. Grazie a eAi – Jon

+0

FYI per impostazione predefinita il mio pacchetto di richieste utilizzava il pacchetto 'certifi' per' cacert.pem' piuttosto che il suo, ma 'certifi' era in site-package.zip piuttosto che in una cartella aperta. Un'alternativa potrebbe essere '' 'pem_path = "lib/python2.7/le domande/cacert.pem" se is_py2app altro Nessuno ' '' utilizzare quello confezionato con le richieste (non necessitano di certifi da aggiungere). Ma fa poca differenza, immagino. – Jon

+0

Ciao @eAi Mi dispiace se questa è una domanda stupida. Ma cos'è 'sys' nella riga' is_py2app = hasattr (sys, "frozen") '? –

0

Mi sono imbattuto nello stesso problema e ho dovuto distribuire la mia applicazione agli utenti che potrebbero non avere Python o il pacchetto certifi installato sul loro Mac. Attingendo alle ispirazioni dalle risposte qui, ho trovato la seguente soluzione.

Passaggio 1: scaricare un pacchetto OpenSSL da https://www.openssl.org/source/. Trova /openssl-1.0.2n/certs/demo/ca-cert.pem e posizionalo nella stessa directory del programma Python (ad esempio main.py).

Passaggio 2: creare un setup.py come al solito, ma includere ca-cert.pem nell'elenco DATA_FILES. Così il vostro setup.py dovrebbe essere simile a questa:

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'], 
) 

Fase 3: utilizzare il parametro verify lo richiede utilizzeranno il file del certificato che fornisci.

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

In alternativa, è anche possibile creare una sessione in modo che non è necessario specificare verify ogni volta.

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

Passaggio 4: pacchetto dell'applicazione utilizzando py2app come al solito. L'app risultante dovrebbe essere in grado di funzionare normalmente.

python setup.py py2app