diff --git a/.travis.yml b/.travis.yml index cfccc32..a36f66a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,13 @@ language: python python: - "2.7" +# The way the selection of the Python version is currently made in Makefile +# leads to travis always picking up Python 2 for the task. +# All versions of Python are appearantly present in a travis environment. +# Once the makefile has been adjusted the following lines should be enabled. +# - "3.5" +# - "3.6" +# - "3.7-dev" notifications: email: diff --git a/Makefile b/Makefile index 66b2d82..37c0104 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,8 @@ +# Once there is Python 3 support in this package and it's dependencies +# the detection of the used Python version should be changed. +# The following line prefers `python` as this will allow this to work +# in CI (e.g. Travis CI) and put up the configured Python version: +# SYSTEMPYTHON = `which python python3 python2 | head -n 1` SYSTEMPYTHON = `which python2 python | head -n 1` VIRTUALENV = virtualenv --python=$(SYSTEMPYTHON) ENV = ./local diff --git a/syncserver.wsgi b/syncserver.wsgi index 4b0503c..1564720 100644 --- a/syncserver.wsgi +++ b/syncserver.wsgi @@ -6,7 +6,10 @@ import os import sys import site from logging.config import fileConfig -from ConfigParser import NoSectionError +try: + from ConfigParser import NoSectionError +except ImportError: + from configparser import NoSectionError # detecting if virtualenv was used in this dir _CURDIR = os.path.dirname(os.path.abspath(__file__)) diff --git a/syncserver/__init__.py b/syncserver/__init__.py index 382e646..3650c01 100644 --- a/syncserver/__init__.py +++ b/syncserver/__init__.py @@ -2,9 +2,13 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this file, # You can obtain one at http://mozilla.org/MPL/2.0/. +import binascii import os import logging -from urlparse import urlparse, urlunparse, urljoin +try: + from urlparse import urlparse, urlunparse, urljoin +except ImportError: + from urllib.parse import urlparse, urlunparse, urljoin import requests @@ -31,7 +35,7 @@ def includeme(config): """Install SyncServer application into the given Pyramid configurator.""" # Set the umask so that files are created with secure permissions. # Necessary for e.g. created-on-demand sqlite database files. - os.umask(0077) + os.umask(0o077) # If PyOpenSSL is available, configure requests to use it. # This helps improve security on older python versions. @@ -50,7 +54,7 @@ def includeme(config): secret = settings.get("syncserver.secret") if secret is None: - secret = os.urandom(32).encode("hex") + secret = generate_random_hex_key(64) sqluri = settings.get("syncserver.sqluri") if sqluri is None: rootdir = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) @@ -138,7 +142,7 @@ def includeme(config): # Default to a randomly-generated secret. # This setting isn't useful in a self-hosted setup # and setting a default avoids scary-sounding warnings. - settings["fxa.metrics_uid_secret_key"] = os.urandom(16).encode("hex") + settings["fxa.metrics_uid_secret_key"] = generate_random_hex_key(32) # Include the relevant sub-packages. config.scan("syncserver", ignore=["syncserver.wsgi_app"]) @@ -197,6 +201,10 @@ def str_to_bool(value): raise ValueError("unable to parse boolean from %r" % (value,)) +def generate_random_hex_key(length): + return binascii.hexlify(os.urandom(length // 2)) + + @subscriber(NewRequest) def reconcile_wsgi_environ_with_public_url(event): """Event-listener that checks and tweaks WSGI environ based on public_url. diff --git a/syncserver/staticnode.py b/syncserver/staticnode.py index bfc4142..9c73f65 100644 --- a/syncserver/staticnode.py +++ b/syncserver/staticnode.py @@ -10,7 +10,12 @@ are implicitly assigned to a single, static node. """ import time -import urlparse + +try: + from urlparse import urlparse +except ImportError: + from urllib.parse import urlparse + from mozsvc.exceptions import BackendError from sqlalchemy import Column, Integer, String, BigInteger, Index @@ -98,7 +103,7 @@ class StaticNodeAssignment(object): def __init__(self, sqluri, node_url, **kw): self.sqluri = sqluri self.node_url = node_url - self.driver = urlparse.urlparse(sqluri).scheme.lower() + self.driver = urlparse(sqluri).scheme.lower() sqlkw = { "logging_name": "syncserver", "connect_args": {}, @@ -111,7 +116,7 @@ class StaticNodeAssignment(object): sqlkw["connect_args"]["check_same_thread"] = False # If using a :memory: database, we must use a QueuePool of # size 1 so that a single connection is shared by all threads. - if urlparse.urlparse(sqluri).path.lower() in ("/", "/:memory:"): + if urlparse(sqluri).path.lower() in ("/", "/:memory:"): sqlkw["pool_size"] = 1 sqlkw["max_overflow"] = 0 if "mysql" in self.driver: