From d765544edd757e274016d10346eff8ef4948c572 Mon Sep 17 00:00:00 2001 From: Jean-Marc Martins Date: Fri, 13 Dec 2013 14:31:09 +0100 Subject: [PATCH 1/3] Add ssl protocol and ciphers in config --- config | 4 ++++ radicale/__init__.py | 7 ++++--- radicale/config.py | 2 ++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/config b/config index c4898e1..8b7c648 100644 --- a/config +++ b/config @@ -25,6 +25,10 @@ ssl = False certificate = /etc/apache2/ssl/server.crt # SSL private key key = /etc/apache2/ssl/server.key +# SSL Protocol used. See python's ssl module for available values +protocol = PROTOCOL_SSLv23 +# Ciphers available. See python's ssl module for available ciphers +ciphers = None # Reverse DNS to resolve client address in logs dns_lookup = True # Root URL of Radicale (starting and ending with a slash) diff --git a/radicale/__init__.py b/radicale/__init__.py index 41bab4f..389c751 100644 --- a/radicale/__init__.py +++ b/radicale/__init__.py @@ -98,7 +98,9 @@ class HTTPSServer(HTTPServer): server_side=True, certfile=config.get("server", "certificate"), keyfile=config.get("server", "key"), - ssl_version=ssl.PROTOCOL_SSLv23) + ssl_version=getattr(ssl, config.get("server", "protocol"), + ssl.PROTOCOL_SSLv23), + ciphers=config.get("server", "ciphers")) self.server_bind() self.server_activate() @@ -271,8 +273,7 @@ class Application(object): authorization = environ.get("HTTP_AUTHORIZATION", None) if authorization: - authorization = \ - authorization.decode("ascii").lstrip("Basic").strip() + authorization = authorization.lstrip("Basic").strip() user, password = self.decode(base64.b64decode( authorization.encode("ascii")), environ).split(":", 1) else: diff --git a/radicale/config.py b/radicale/config.py index 9cdad82..08482b3 100644 --- a/radicale/config.py +++ b/radicale/config.py @@ -45,6 +45,8 @@ INITIAL_CONFIG = { "ssl": "False", "certificate": "/etc/apache2/ssl/server.crt", "key": "/etc/apache2/ssl/server.key", + "protocol": "PROTOCOL_SSLv23", + "ciphers": None, "dns_lookup": "True", "base_prefix": "/", "realm": "Radicale - Password Required"}, From f377bd1356c3f5d1e16c40a6b71c398b630899f2 Mon Sep 17 00:00:00 2001 From: Jean-Marc Martins Date: Fri, 13 Dec 2013 15:17:30 +0100 Subject: [PATCH 2/3] Fix ssl protocol --- config | 2 +- radicale/__init__.py | 2 +- radicale/config.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config b/config index 8b7c648..42ce247 100644 --- a/config +++ b/config @@ -28,7 +28,7 @@ key = /etc/apache2/ssl/server.key # SSL Protocol used. See python's ssl module for available values protocol = PROTOCOL_SSLv23 # Ciphers available. See python's ssl module for available ciphers -ciphers = None +ciphers = # Reverse DNS to resolve client address in logs dns_lookup = True # Root URL of Radicale (starting and ending with a slash) diff --git a/radicale/__init__.py b/radicale/__init__.py index 389c751..f14f4f3 100644 --- a/radicale/__init__.py +++ b/radicale/__init__.py @@ -100,7 +100,7 @@ class HTTPSServer(HTTPServer): keyfile=config.get("server", "key"), ssl_version=getattr(ssl, config.get("server", "protocol"), ssl.PROTOCOL_SSLv23), - ciphers=config.get("server", "ciphers")) + ciphers=config.get("server", "ciphers") or None) self.server_bind() self.server_activate() diff --git a/radicale/config.py b/radicale/config.py index 08482b3..71d27a8 100644 --- a/radicale/config.py +++ b/radicale/config.py @@ -46,7 +46,7 @@ INITIAL_CONFIG = { "certificate": "/etc/apache2/ssl/server.crt", "key": "/etc/apache2/ssl/server.key", "protocol": "PROTOCOL_SSLv23", - "ciphers": None, + "ciphers": "", "dns_lookup": "True", "base_prefix": "/", "realm": "Radicale - Password Required"}, From 56581a998a604ce018fe44d768ba2d398c9be08b Mon Sep 17 00:00:00 2001 From: Jean-Marc Martins Date: Tue, 17 Dec 2013 14:35:55 +0100 Subject: [PATCH 3/3] =?UTF-8?q?Fix=20database=20Fix=20bug=20#77=20HELL?= =?UTF-8?q?=C2=A0YEAH=20!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- radicale/storage/database.py | 60 +++++++++++++++++++----------------- schema.sql | 39 ++++++++++++----------- 2 files changed, 52 insertions(+), 47 deletions(-) diff --git a/radicale/storage/database.py b/radicale/storage/database.py index 0e40b0a..527c19c 100644 --- a/radicale/storage/database.py +++ b/radicale/storage/database.py @@ -24,7 +24,7 @@ SQLAlchemy storage backend. import time from datetime import datetime from contextlib import contextmanager -from sqlalchemy import create_engine, Column, String, DateTime, ForeignKey +from sqlalchemy import create_engine, Column, Unicode, Integer, ForeignKey from sqlalchemy import func from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy.ext.declarative import declarative_base @@ -44,8 +44,8 @@ class DBCollection(Base): """Table of collections.""" __tablename__ = "collection" - path = Column(String, primary_key=True) - parent_path = Column(String, ForeignKey("collection.path")) + path = Column(Unicode, primary_key=True) + parent_path = Column(Unicode, ForeignKey("collection.path")) parent = relationship( "DBCollection", backref="children", remote_side=[path]) @@ -55,9 +55,9 @@ class DBItem(Base): """Table of collection's items.""" __tablename__ = "item" - name = Column(String, primary_key=True) - tag = Column(String) - collection_path = Column(String, ForeignKey("collection.path")) + name = Column(Unicode, primary_key=True) + tag = Column(Unicode) + collection_path = Column(Unicode, ForeignKey("collection.path")) collection = relationship("DBCollection", backref="items") @@ -66,10 +66,10 @@ class DBHeader(Base): """Table of item's headers.""" __tablename__ = "header" - key = Column(String, primary_key=True) - value = Column(String) + name = Column(Unicode, primary_key=True) + value = Column(Unicode) collection_path = Column( - String, ForeignKey("collection.path"), primary_key=True) + Unicode, ForeignKey("collection.path"), primary_key=True) collection = relationship("DBCollection", backref="headers") @@ -78,23 +78,22 @@ class DBLine(Base): """Table of item's lines.""" __tablename__ = "line" - key = Column(String) - value = Column(String) - item_name = Column(String, ForeignKey("item.name")) - timestamp = Column(DateTime, default=datetime.now, primary_key=True) + name = Column(Unicode) + value = Column(Unicode) + item_name = Column(Unicode, ForeignKey("item.name")) + timestamp = Column(Integer, default=lambda: time.time() * 10 ** 6, primary_key=True) - item = relationship( - "DBItem", backref="lines", order_by=timestamp) + item = relationship("DBItem", backref="lines", order_by=timestamp) class DBProperty(Base): """Table of collection's properties.""" __tablename__ = "property" - key = Column(String, primary_key=True) - value = Column(String) + name = Column(Unicode, primary_key=True) + value = Column(Unicode) collection_path = Column( - String, ForeignKey("collection.path"), primary_key=True) + Unicode, ForeignKey("collection.path"), primary_key=True) collection = relationship( "DBCollection", backref="properties", cascade="delete") @@ -119,17 +118,20 @@ class Collection(ical.Collection): .order_by(DBItem.name).all()) for item in items: text = "\n".join( - "%s:%s" % (line.key, line.value) for line in item.lines) + "%s:%s" % (line.name, line.value) for line in item.lines) item_objects.append(item_type(text, item.name)) return item_objects @property def _modification_time(self): """Collection's last modification time.""" - return ( + timestamp = ( self.session.query(func.max(DBLine.timestamp)) - .join(DBItem).filter_by(collection_path=self.path).first()[0] - or datetime.now()) + .join(DBItem).filter_by(collection_path=self.path).first()[0]) + if timestamp: + return datetime.fromtimestamp(float(timestamp) / 10 ** 6) + else: + return datetime.now() @property def _db_collection(self): @@ -156,7 +158,7 @@ class Collection(ical.Collection): for header in headers: db_header = DBHeader() - db_header.key, db_header.value = header.text.split(":", 1) + db_header.name, db_header.value = header.text.split(":", 1) db_header.collection_path = self.path self.session.add(db_header) @@ -169,7 +171,7 @@ class Collection(ical.Collection): for line in ical.unfold(item.text): db_line = DBLine() - db_line.key, db_line.value = line.split(":", 1) + db_line.name, db_line.value = line.split(":", 1) db_line.item_name = item.name self.session.add(db_line) @@ -189,9 +191,9 @@ class Collection(ical.Collection): headers = ( self.session.query(DBHeader) .filter_by(collection_path=self.path) - .order_by(DBHeader.key).all()) + .order_by(DBHeader.name).all()) return [ - ical.Header("%s:%s" % (header.key, header.value)) + ical.Header("%s:%s" % (header.name, header.value)) for header in headers] @classmethod @@ -241,16 +243,16 @@ class Collection(ical.Collection): self.session.query(DBProperty) .filter_by(collection_path=self.path).all()) for prop in db_properties: - properties[prop.key] = prop.value + properties[prop.name] = prop.value old_properties = properties.copy() yield properties # On exit if self._db_collection and old_properties != properties: for prop in db_properties: self.session.delete(prop) - for key, value in properties.items(): + for name, value in properties.items(): prop = DBProperty() - prop.key = key + prop.name = name prop.value = value prop.collection_path = self.path self.session.add(prop) diff --git a/schema.sql b/schema.sql index b6bb828..92c96bb 100644 --- a/schema.sql +++ b/schema.sql @@ -1,28 +1,31 @@ --- This is the database schema for PostgreSQL. +-- This is the database schema for PostgreSQL and MySQL and SQLite. create table collection ( - path varchar primary key not null, - parent_path varchar references collection (path)); + path varchar(200) not null, + parent_path varchar(200) references collection (path), + primary key (path)); create table item ( - name varchar primary key not null, - tag varchar not null, - collection_path varchar references collection (path) not null); + name varchar(200) not null, + tag text not null, + collection_path varchar(200) references collection (path), + primary key (name)); create table header ( - key varchar not null, - value varchar not null, - collection_path varchar references collection (path) not null, - primary key (key, collection_path)); + name varchar(200) not null, + value text not null, + collection_path varchar(200) references collection (path), + primary key (name, collection_path)); create table line ( - key varchar not null, - value varchar not null, - item_name varchar references item (name) not null, - timestamp timestamp not null); + name text not null, + value text not null, + item_name varchar(200) references item (name), + timestamp bigint not null, + primary key (timestamp)); create table property ( - key varchar not null, - value varchar not null, - collection_path varchar references collection (path) not null, - primary key (key, collection_path)); + name varchar(200) not null, + value text not null, + collection_path varchar(200) references collection (path), + primary key (name, collection_path));