mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
bundle ssl certs; share con across all sync types
This commit is contained in:
parent
92352d4725
commit
d148a6cf1b
5 changed files with 85 additions and 20 deletions
55
anki/ankiweb.certs
Normal file
55
anki/ankiweb.certs
Normal file
|
@ -0,0 +1,55 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIFFzCCA/+gAwIBAgIRAP+ceCiXnKf8x8mBIBmTckswDQYJKoZIhvcNAQEFBQAw
|
||||
cTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ29tb2RvIENBIExpbWl0ZWQxFzAVBgNV
|
||||
BAMTDlBvc2l0aXZlU1NMIENBMB4XDTExMDkxNTAwMDAwMFoXDTE0MDkxNDIzNTk1
|
||||
OVowTzEhMB8GA1UECxMYRG9tYWluIENvbnRyb2wgVmFsaWRhdGVkMRQwEgYDVQQL
|
||||
EwtQb3NpdGl2ZVNTTDEUMBIGA1UEAxMLYW5raXdlYi5uZXQwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQDEDfc2WFrF5mkg4yrrbu/bxqW5SLu1qPp3Vtlv
|
||||
+he8Fzkn44Zc8in7Q/t8pOxRMNq5nRjsKNUr51Zv206Z8aDzV6Mi2LtdHhADTOQW
|
||||
UGa2+ANcvGJg6lCJ4WvQwcDIktO9kGgmlkMvuPAskF+nhRi7TlTaU8lhHlhMV5zu
|
||||
G0XfXjPGitK1m5egIY78PJoVK+M/k44NMxi0sb+XgErXW0k6QdCZvba0z5Heks7+
|
||||
aIFmLjx7bcEQxQS/+1nIK05nNrDPi7TymwZOM+b2T48t7+x9H9cjEeLUZsCiETja
|
||||
SBLyj/2WLFYfH7jZuwylwcCvJ5PlnutAk7za3iASpGpUvWdFAgMBAAGjggHKMIIB
|
||||
xjAfBgNVHSMEGDAWgBS4yhHpBjF528OUxugZKry7NRYxpDAdBgNVHQ4EFgQUGUTe
|
||||
GYqlhmH/El7O10/hoPgIdqEwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAw
|
||||
HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMEYGA1UdIAQ/MD0wOwYLKwYB
|
||||
BAGyMQECAgcwLDAqBggrBgEFBQcCARYeaHR0cDovL3d3dy5wb3NpdGl2ZXNzbC5j
|
||||
b20vQ1BTMGkGA1UdHwRiMGAwL6AtoCuGKWh0dHA6Ly9jcmwuY29tb2RvY2EuY29t
|
||||
L1Bvc2l0aXZlU1NMQ0EuY3JsMC2gK6AphidodHRwOi8vY3JsLmNvbW9kby5uZXQv
|
||||
UG9zaXRpdmVTU0xDQS5jcmwwawYIKwYBBQUHAQEEXzBdMDUGCCsGAQUFBzAChilo
|
||||
dHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9Qb3NpdGl2ZVNTTENBLmNydDAkBggrBgEF
|
||||
BQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMCcGA1UdEQQgMB6CC2Fua2l3
|
||||
ZWIubmV0gg93d3cuYW5raXdlYi5uZXQwDQYJKoZIhvcNAQEFBQADggEBAI6Mcuwd
|
||||
OQTvTkeZ45j2VcI1hR/nqSf2VnisxRQxNRr+n8grjt1ulqYJWJyOrocUINW7XyoJ
|
||||
jHcFpS30m/E4ZedaHXq++hJqjat140r5TRcBigAHnZj7u69hjAhwG/A6Er0JFbX+
|
||||
eCwe1SCBUgDLGhcNA4o3cykmgK6qG/drj5/CVwpTVKzQ65JGxEMgWehELraPzbx9
|
||||
mi3e9BMSC11eEsE6O0CpBL+ENcXngYpyi1R3GYFce9oFk+ps/1yYiUstgStq4obJ
|
||||
8MdDZKB8qOLFPe097FGRcOz1JRDYDVD8JQ+d+o4T3/EHuxZ2EJXhAXJDc/FoKzru
|
||||
Pb1JBxNB1O0QCmE=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
|
||||
MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
|
||||
IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
|
||||
MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
|
||||
FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
|
||||
bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
|
||||
dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
|
||||
H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
|
||||
uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
|
||||
mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
|
||||
a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
|
||||
E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
|
||||
WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
|
||||
VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
|
||||
Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
|
||||
cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
|
||||
IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
|
||||
AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
|
||||
YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
|
||||
6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
|
||||
Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
|
||||
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
|
||||
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
|
||||
-----END CERTIFICATE-----
|
|
@ -43,6 +43,8 @@ SYNC_HOST = os.environ.get("SYNC_HOST") or "dev.ankiweb.net"
|
|||
SYNC_PORT = int(os.environ.get("SYNC_PORT") or 80)
|
||||
SYNC_URL = "http://%s:%d/sync/" % (SYNC_HOST, SYNC_PORT)
|
||||
SYNC_VER = 0
|
||||
HTTP_CERTS = os.path.join(os.path.basename(__file__), "ankiweb.certs")
|
||||
HTTP_TIMEOUT = 60
|
||||
|
||||
# deck schema
|
||||
SCHEMA_VERSION = 1
|
||||
|
|
24
anki/sync.py
24
anki/sync.py
|
@ -7,7 +7,7 @@ from cStringIO import StringIO
|
|||
from datetime import date
|
||||
from anki.db import DB
|
||||
from anki.errors import *
|
||||
from anki.utils import ids2str, checksum, intTime
|
||||
from anki.utils import ids2str, checksum, intTime, httpCon
|
||||
from anki.consts import *
|
||||
from anki.lang import _
|
||||
from hooks import runHook
|
||||
|
@ -383,7 +383,7 @@ class HttpSyncer(object):
|
|||
|
||||
# retrieving a host key for future operations
|
||||
def hostKey(self, pw):
|
||||
h = httplib2.Http(timeout=60)
|
||||
h = httpCon()
|
||||
resp, cont = h.request(
|
||||
SYNC_URL+"hostKey?" + urllib.urlencode(dict(u=self.user,p=pw)))
|
||||
if resp['status'] != '200':
|
||||
|
@ -452,11 +452,10 @@ class RemoteServer(Syncer, HttpSyncer):
|
|||
def __init__(self, user, hkey):
|
||||
self.user = user
|
||||
self.hkey = hkey
|
||||
self.con = None
|
||||
self.con = httpCon()
|
||||
|
||||
def meta(self):
|
||||
h = httplib2.Http(timeout=60)
|
||||
resp, cont = h.request(
|
||||
resp, cont = self.con.request(
|
||||
SYNC_URL+"meta?" + urllib.urlencode(dict(u=self.user,v=SYNC_VER)))
|
||||
# fixme: convert these into easily-catchable errors
|
||||
if resp['status'] in ('503', '504'):
|
||||
|
@ -470,7 +469,6 @@ class RemoteServer(Syncer, HttpSyncer):
|
|||
return simplejson.loads(cont)
|
||||
|
||||
def applyChanges(self, **kw):
|
||||
self.con = httplib2.Http(timeout=60)
|
||||
return self._run("applyChanges", kw)
|
||||
|
||||
def chunk(self, **kw):
|
||||
|
@ -495,16 +493,14 @@ class RemoteServer(Syncer, HttpSyncer):
|
|||
|
||||
class FullSyncer(HttpSyncer):
|
||||
|
||||
def __init__(self, col, hkey):
|
||||
def __init__(self, col, hkey, con):
|
||||
self.col = col
|
||||
self.hkey = hkey
|
||||
|
||||
def _con(self):
|
||||
return httplib2.Http(timeout=60)
|
||||
self.con = con
|
||||
|
||||
def download(self):
|
||||
self.col.close()
|
||||
resp, cont = self._con().request(
|
||||
resp, cont = self.con.request(
|
||||
SYNC_URL+"download?" + urllib.urlencode(self._vars()))
|
||||
if resp['status'] != '200':
|
||||
raise Exception("Invalid response code: %s" % resp['status'])
|
||||
|
@ -518,7 +514,7 @@ class FullSyncer(HttpSyncer):
|
|||
|
||||
def upload(self):
|
||||
self.col.beforeUpload()
|
||||
assert self.postData(self._con(), "upload", open(self.col.path, "rb"),
|
||||
assert self.postData(self.con, "upload", open(self.col.path, "rb"),
|
||||
self._vars(), comp=6) == "OK"
|
||||
|
||||
# Media syncing
|
||||
|
@ -589,9 +585,9 @@ class MediaSyncer(object):
|
|||
|
||||
class RemoteMediaServer(MediaSyncer, HttpSyncer):
|
||||
|
||||
def __init__(self, hkey):
|
||||
def __init__(self, hkey, con):
|
||||
self.hkey = hkey
|
||||
self.con = httplib2.Http(timeout=60)
|
||||
self.con = con
|
||||
|
||||
def remove(self, **kw):
|
||||
return simplejson.loads(
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
import re, os, random, time, types, math, htmlentitydefs, subprocess, \
|
||||
tempfile, shutil, string
|
||||
tempfile, shutil, string, httplib2
|
||||
from hashlib import sha1
|
||||
from anki.lang import _, ngettext
|
||||
from anki.consts import *
|
||||
import locale, sys
|
||||
|
||||
if sys.version_info[1] < 5:
|
||||
|
@ -297,3 +298,13 @@ def call(argv, wait=True, **kwargs):
|
|||
|
||||
isMac = sys.platform.startswith("darwin")
|
||||
isWin = sys.platform.startswith("win32")
|
||||
|
||||
# OS helpers
|
||||
##############################################################################
|
||||
|
||||
def httpCon():
|
||||
disable = os.environ.get("SSL_NOVALIDATE") or False
|
||||
return httplib2.Http(
|
||||
timeout=HTTP_TIMEOUT,
|
||||
disable_ssl_certificate_validation=disable,
|
||||
ca_certs=HTTP_CERTS)
|
||||
|
|
|
@ -4,7 +4,7 @@ import nose, os, tempfile, shutil, time
|
|||
from tests.shared import assertException
|
||||
|
||||
from anki.errors import *
|
||||
from anki.utils import intTime
|
||||
from anki.utils import intTime, httpCon
|
||||
from anki.sync import Syncer, FullSyncer, LocalServer, RemoteServer, \
|
||||
MediaSyncer, RemoteMediaServer
|
||||
from anki.notes import Note
|
||||
|
@ -65,7 +65,7 @@ def test_hkey():
|
|||
def test_download():
|
||||
if not TEST_REMOTE:
|
||||
return
|
||||
f = FullSyncer(ts.client.col, "abc")
|
||||
f = FullSyncer(ts.client.col, "abc", ts.server.con)
|
||||
assertException(Exception, f.download)
|
||||
f.hkey = TEST_HKEY
|
||||
f.download()
|
||||
|
@ -77,7 +77,7 @@ def test_remoteSync():
|
|||
# not yet associated, so will require a full sync
|
||||
assert ts.client.sync() == "fullSync"
|
||||
# upload
|
||||
f = FullSyncer(ts.client.col, TEST_HKEY)
|
||||
f = FullSyncer(ts.client.col, TEST_HKEY, ts.server.con)
|
||||
f.upload()
|
||||
ts.client.col.reopen()
|
||||
# should report no changes
|
||||
|
@ -89,7 +89,7 @@ def test_remoteSync():
|
|||
assert ts.client.sync() == "noChanges"
|
||||
# downloading the remote col should give us the same mod
|
||||
lmod = ts.client.col.mod
|
||||
f = FullSyncer(ts.client.col, TEST_HKEY)
|
||||
f = FullSyncer(ts.client.col, TEST_HKEY, ts.server.con)
|
||||
f.download()
|
||||
d = aopen(ts.client.col.path)
|
||||
assert d.mod == lmod
|
||||
|
@ -101,7 +101,8 @@ def test_remoteSync():
|
|||
|
||||
def setup_remoteMedia():
|
||||
setup_basic()
|
||||
ts.server = RemoteMediaServer(TEST_HKEY)
|
||||
con = httpCon()
|
||||
ts.server = RemoteMediaServer(TEST_HKEY, con)
|
||||
ts.server2 = RemoteServer(TEST_USER, TEST_HKEY)
|
||||
ts.client = MediaSyncer(ts.deck1, ts.server)
|
||||
|
||||
|
|
Loading…
Reference in a new issue