mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-04-27 14:57:41 +00:00
Merge pull request #231 from untitaker/safe-hrefs
Create always safe hrefs
This commit is contained in:
commit
4bb4b019ce
6 changed files with 16 additions and 16 deletions
|
|
@ -14,7 +14,7 @@ from .. import EVENT_TEMPLATE, TASK_TEMPLATE, VCARD_TEMPLATE, \
|
||||||
|
|
||||||
def format_item(item_template, uid=None):
|
def format_item(item_template, uid=None):
|
||||||
# assert that special chars are handled correctly.
|
# assert that special chars are handled correctly.
|
||||||
r = '{}@vdirsyncer'.format(random.random())
|
r = random.random()
|
||||||
return Item(item_template.format(r=r, uid=uid or r))
|
return Item(item_template.format(r=r, uid=uid or r))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ class ServerMixin(object):
|
||||||
url = url.rstrip('/') + '/' + collection
|
url = url.rstrip('/') + '/' + collection
|
||||||
|
|
||||||
rv = {'url': url, 'username': 'bob', 'password': 'bob',
|
rv = {'url': url, 'username': 'bob', 'password': 'bob',
|
||||||
'collection': collection, 'unsafe_href_chars': ''}
|
'collection': collection}
|
||||||
|
|
||||||
if collection is not None:
|
if collection is not None:
|
||||||
s = self.storage_class(**rv)
|
s = self.storage_class(**rv)
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ class TestFilesystemStorage(StorageTests):
|
||||||
s = self.storage_class(str(tmpdir), '.txt')
|
s = self.storage_class(str(tmpdir), '.txt')
|
||||||
s.upload(Item(u'UID:a/b/c'))
|
s.upload(Item(u'UID:a/b/c'))
|
||||||
item_file, = tmpdir.listdir()
|
item_file, = tmpdir.listdir()
|
||||||
assert str(item_file).endswith('a_b_c.txt')
|
assert '/' not in item_file.basename and item_file.isfile()
|
||||||
|
|
||||||
def test_too_long_uid(self, tmpdir):
|
def test_too_long_uid(self, tmpdir):
|
||||||
s = self.storage_class(str(tmpdir), '.txt')
|
s = self.storage_class(str(tmpdir), '.txt')
|
||||||
|
|
|
||||||
|
|
@ -341,15 +341,14 @@ class DavStorage(Storage):
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, url, username='', password='', verify=True, auth=None,
|
def __init__(self, url, username='', password='', verify=True, auth=None,
|
||||||
useragent=USERAGENT, unsafe_href_chars='@',
|
useragent=USERAGENT, verify_fingerprint=None, auth_cert=None,
|
||||||
verify_fingerprint=None, auth_cert=None, **kwargs):
|
**kwargs):
|
||||||
super(DavStorage, self).__init__(**kwargs)
|
super(DavStorage, self).__init__(**kwargs)
|
||||||
|
|
||||||
url = url.rstrip('/') + '/'
|
url = url.rstrip('/') + '/'
|
||||||
self.session = DavSession(url, username, password, verify, auth,
|
self.session = DavSession(url, username, password, verify, auth,
|
||||||
useragent, verify_fingerprint,
|
useragent, verify_fingerprint,
|
||||||
auth_cert)
|
auth_cert)
|
||||||
self.unsafe_href_chars = unsafe_href_chars
|
|
||||||
|
|
||||||
# defined for _repr_attributes
|
# defined for _repr_attributes
|
||||||
self.username = username
|
self.username = username
|
||||||
|
|
@ -369,7 +368,7 @@ class DavStorage(Storage):
|
||||||
return _normalize_href(self.session.url, *args, **kwargs)
|
return _normalize_href(self.session.url, *args, **kwargs)
|
||||||
|
|
||||||
def _get_href(self, item):
|
def _get_href(self, item):
|
||||||
href = utils.generate_href(item.ident, unsafe=self.unsafe_href_chars)
|
href = utils.generate_href(item.ident)
|
||||||
return self._normalize_href(href + self.fileext)
|
return self._normalize_href(href + self.fileext)
|
||||||
|
|
||||||
def _is_item_mimetype(self, mimetype):
|
def _is_item_mimetype(self, mimetype):
|
||||||
|
|
|
||||||
|
|
@ -87,9 +87,7 @@ class FilesystemStorage(Storage):
|
||||||
return os.path.join(self.path, to_native(href, self.encoding))
|
return os.path.join(self.path, to_native(href, self.encoding))
|
||||||
|
|
||||||
def _get_href(self, ident):
|
def _get_href(self, ident):
|
||||||
# XXX: POSIX only defines / and \0 as invalid chars, but we should make
|
return generate_href(ident) + self.fileext
|
||||||
# this work crossplatform.
|
|
||||||
return generate_href(ident, '/') + self.fileext
|
|
||||||
|
|
||||||
def list(self):
|
def list(self):
|
||||||
for fname in os.listdir(self.path):
|
for fname in os.listdir(self.path):
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,11 @@ from .compat import iteritems, to_unicode
|
||||||
from .. import exceptions
|
from .. import exceptions
|
||||||
|
|
||||||
|
|
||||||
|
SAFE_UID_CHARS = ('abcdefghijklmnopqrstuvwxyz'
|
||||||
|
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||||
|
'0123456789_.-+')
|
||||||
|
|
||||||
|
|
||||||
_missing = object()
|
_missing = object()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -159,10 +164,8 @@ class cached_property(object):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def generate_href(ident=None, unsafe=''):
|
def generate_href(ident=None, safe=SAFE_UID_CHARS):
|
||||||
if ident and \
|
if not ident or set(ident) - set(safe):
|
||||||
ident.encode('ascii', 'ignore').decode('ascii') == ident:
|
return to_unicode(uuid.uuid4().hex)
|
||||||
for char in unsafe:
|
else:
|
||||||
ident = ident.replace(char, '_')
|
|
||||||
return ident
|
return ident
|
||||||
return to_unicode(uuid.uuid4().hex)
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue