diff options
| author | 2011-12-08 18:40:55 +0100 | |
|---|---|---|
| committer | 2011-12-08 18:40:55 +0100 | |
| commit | 12e0357c2fb7cf9aabb4744a8fed49426c21ba68 (patch) | |
| tree | e1c9c3ffbe01aa5a346a3f1cb8dd5b894620f1cd | |
| parent | fixed deprecation warnings (diff) | |
| download | pyload-12e0357c2fb7cf9aabb4744a8fed49426c21ba68.tar.xz | |
fixed order consistence, fixed typo in json_app
| -rw-r--r-- | module/database/FileDatabase.py | 59 | ||||
| -rw-r--r-- | module/lib/thrift/transport/TSSLSocket.py | 176 | ||||
| -rw-r--r-- | module/lib/thrift/transport/TSocket.py | 4 | ||||
| -rw-r--r-- | module/web/json_app.py | 2 | ||||
| -rwxr-xr-x | pyLoadCore.py | 2 | 
5 files changed, 233 insertions, 10 deletions
| diff --git a/module/database/FileDatabase.py b/module/database/FileDatabase.py index 1df8998b0..6c7bfe1de 100644 --- a/module/database/FileDatabase.py +++ b/module/database/FileDatabase.py @@ -169,8 +169,10 @@ class FileHandler:          self.core.pullManager.addEvent(e)          self.core.hookManager.dispatchEvent("packageDeleted", id) -        if id in self.packageCache: -            del self.packageCache[id] +        #if id in self.packageCache: +        #   del self.packageCache[id] + +        self.packageCache = {} # force order refresh      #----------------------------------------------------------------------      @lock @@ -435,6 +437,8 @@ class FileHandler:          pack = self.getPackage(id)          e = InsertEvent("pack", id, pack.order, "collector" if not pack.queue else "queue")          self.core.pullManager.addEvent(e) +         +        self.packageCache = {} # force order refresh      @lock      @change @@ -457,10 +461,12 @@ class FileHandler:          p.order = position          self.db.commit() - -        e = ReloadAllEvent("collector" if not p.queue else "queue") +         +        e = InsertEvent("pack", id, pack.order, "collector" if not pack.queue else "queue")          self.core.pullManager.addEvent(e) +        self.packageCache = {} # force order refresh +      @lock      @change      def reorderFile(self, id, position): @@ -486,10 +492,11 @@ class FileHandler:              self.cache[id].order = position          self.db.commit() - -        e = ReloadAllEvent("collector" if not self.getPackage(f["package"]).queue else "queue") - +             +        e = InsertEvent("file", id, f["order"], "collector" if not self.getPackage(f["package"]).queue else "queue")          self.core.pullManager.addEvent(e) +         +        self.cache = {} # force order refresh      @change      def updateFileInfo(self, data, pid): @@ -541,6 +548,9 @@ class FileHandler:                  deleted.append(id)                  self.deletePackage(int(id)) + +        self.packageCache = {} # force order refresh +              return deleted      @lock @@ -548,6 +558,11 @@ class FileHandler:      def restartFailed(self):          """ restart all failed links """          self.db.restartFailed() +     +    @lock +    @change +    def fixPackageOrder(self, queue=0): +        self.db.fixPackageOrder(queue)  class FileMethods():      @style.queue @@ -849,12 +864,42 @@ class FileMethods():      @style.queue      def deleteFinished(self):          self.c.execute("DELETE FROM links WHERE status IN (0,4)") +        self.c.execute("DELETE FROM links WHERE status IN (0,4)")          self.c.execute("DELETE FROM packages WHERE NOT EXISTS(SELECT 1 FROM links WHERE packages.id=links.package)")      @style.queue      def restartFailed(self):          self.c.execute("UPDATE links SET status=3,error='' WHERE status IN (8, 9)") +     +     +    @style.queue +    def fixPackageOrder(self, queue=0): +        found = 0 +        order = 0 +        i = 0 +        self.c.execute("SELECT count(*) FROM packages WHERE queue = ?", (queue, )) +        count = self.c.fetchone()[0] +        if count == 0: +            return +        while order < count: +            self.c.execute("SELECT id FROM packages WHERE packageorder = ? AND queue = ?", (i, queue)) +            all = self.c.fetchall() +            if len(all) == 0: +                i += 1 +            elif len(all) == 1: +                self.c.execute("UPDATE packages SET packageorder=? WHERE id = ?", (order,  all[0][0])) +                order += 1 +                i += 1 +            elif len(all) > 1: +                self.c.execute("UPDATE packages SET packageorder=? WHERE id = ?", (order,  all[0][0])) +                order += 1 +                i += len(all) +                del all[0] +                self.c.execute("UPDATE packages SET packageorder=packageorder+? WHERE packageorder >= ? AND queue=?", (len(all), order,  queue)) +                for r in all: +                    self.c.execute("UPDATE packages SET packageorder=? WHERE id = ?", order, r[0]) +                    order += 1      @style.queue diff --git a/module/lib/thrift/transport/TSSLSocket.py b/module/lib/thrift/transport/TSSLSocket.py new file mode 100644 index 000000000..be358448a --- /dev/null +++ b/module/lib/thrift/transport/TSSLSocket.py @@ -0,0 +1,176 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +#   http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +import os +import socket +import ssl + +from thrift.transport import TSocket +from thrift.transport.TTransport import TTransportException + +class TSSLSocket(TSocket.TSocket): +  """ +  SSL implementation of client-side TSocket + +  This class creates outbound sockets wrapped using the +  python standard ssl module for encrypted connections. +   +  The protocol used is set using the class variable +  SSL_VERSION, which must be one of ssl.PROTOCOL_* and +  defaults to  ssl.PROTOCOL_TLSv1 for greatest security. +  """ +  SSL_VERSION = ssl.PROTOCOL_TLSv1 + +  def __init__(self, host='localhost', port=9090, validate=True, ca_certs=None, unix_socket=None): +    """ +    @param validate: Set to False to disable SSL certificate validation entirely. +    @type validate: bool +    @param ca_certs: Filename to the Certificate Authority pem file, possibly a +    file downloaded from: http://curl.haxx.se/ca/cacert.pem  This is passed to +    the ssl_wrap function as the 'ca_certs' parameter. +    @type ca_certs: str +     +    Raises an IOError exception if validate is True and the ca_certs file is +    None, not present or unreadable. +    """ +    self.validate = validate +    self.is_valid = False +    self.peercert = None +    if not validate: +      self.cert_reqs = ssl.CERT_NONE +    else: +      self.cert_reqs = ssl.CERT_REQUIRED +    self.ca_certs = ca_certs +    if validate: +      if ca_certs is None or not os.access(ca_certs, os.R_OK): +        raise IOError('Certificate Authority ca_certs file "%s" is not readable, cannot validate SSL certificates.' % (ca_certs)) +    TSocket.TSocket.__init__(self, host, port, unix_socket) + +  def open(self): +    try: +      res0 = self._resolveAddr() +      for res in res0: +        sock_family, sock_type= res[0:2] +        ip_port = res[4] +        plain_sock = socket.socket(sock_family, sock_type) +        self.handle = ssl.wrap_socket(plain_sock, ssl_version=self.SSL_VERSION, +            do_handshake_on_connect=True, ca_certs=self.ca_certs, cert_reqs=self.cert_reqs)  +        self.handle.settimeout(self._timeout) +        try: +          self.handle.connect(ip_port) +        except socket.error, e: +          if res is not res0[-1]: +            continue +          else: +            raise e +        break +    except socket.error, e: +      if self._unix_socket: +        message = 'Could not connect to secure socket %s' % self._unix_socket +      else: +        message = 'Could not connect to %s:%d' % (self.host, self.port) +      raise TTransportException(type=TTransportException.NOT_OPEN, message=message) +    if self.validate: +      self._validate_cert() + +  def _validate_cert(self): +    """internal method to validate the peer's SSL certificate, and to check the +    commonName of the certificate to ensure it matches the hostname we +    used to make this connection.  Does not support subjectAltName records +    in certificates. +     +    raises TTransportException if the certificate fails validation.""" +    cert = self.handle.getpeercert() +    self.peercert = cert +    if 'subject' not in cert: +      raise TTransportException(type=TTransportException.NOT_OPEN, +                      message='No SSL certificate found from %s:%s' % (self.host, self.port)) +    fields = cert['subject'] +    for field in fields: +      # ensure structure we get back is what we expect +      if not isinstance(field, tuple): +        continue +      cert_pair = field[0] +      if len(cert_pair) < 2: +        continue +      cert_key, cert_value = cert_pair[0:2] +      if cert_key != 'commonName': +        continue +      certhost = cert_value +      if certhost == self.host: +        # success, cert commonName matches desired hostname +        self.is_valid = True +        return  +      else: +        raise TTransportException(type=TTransportException.UNKNOWN, +                          message='Host name we connected to "%s" doesn\'t match certificate provided commonName "%s"' % (self.host, certhost)) +    raise TTransportException(type=TTransportException.UNKNOWN, +                      message='Could not validate SSL certificate from host "%s".  Cert=%s' % (self.host, cert)) + +class TSSLServerSocket(TSocket.TServerSocket): +  """ +  SSL implementation of TServerSocket + +  This uses the ssl module's wrap_socket() method to provide SSL +  negotiated encryption. +  """ +  SSL_VERSION = ssl.PROTOCOL_TLSv1 + +  def __init__(self, host=None, port=9090, certfile='cert.pem', unix_socket=None): +    """Initialize a TSSLServerSocket +     +    @param certfile: The filename of the server certificate file, defaults to cert.pem +    @type certfile: str +    @param host: The hostname or IP to bind the listen socket to, i.e. 'localhost' for only allowing +    local network connections. Pass None to bind to all interfaces. +    @type host: str +    @param port: The port to listen on for inbound connections. +    @type port: int +    """ +    self.setCertfile(certfile) +    TSocket.TServerSocket.__init__(self, host, port) + +  def setCertfile(self, certfile): +    """Set or change the server certificate file used to wrap new connections. +     +    @param certfile: The filename of the server certificate, i.e. '/etc/certs/server.pem' +    @type certfile: str +     +    Raises an IOError exception if the certfile is not present or unreadable. +    """ +    if not os.access(certfile, os.R_OK): +      raise IOError('No such certfile found: %s' % (certfile)) +    self.certfile = certfile + +  def accept(self): +    plain_client, addr = self.handle.accept() +    try: +      client = ssl.wrap_socket(plain_client, certfile=self.certfile, +                      server_side=True, ssl_version=self.SSL_VERSION) +    except ssl.SSLError, ssl_exc: +      # failed handshake/ssl wrap, close socket to client +      plain_client.close() +      # raise ssl_exc +      # We can't raise the exception, because it kills most TServer derived serve() +      # methods. +      # Instead, return None, and let the TServer instance deal with it in +      # other exception handling.  (but TSimpleServer dies anyway) +      return None  +    result = TSocket.TSocket() +    result.setHandle(client) +    return result diff --git a/module/lib/thrift/transport/TSocket.py b/module/lib/thrift/transport/TSocket.py index be6167802..4e0e1874f 100644 --- a/module/lib/thrift/transport/TSocket.py +++ b/module/lib/thrift/transport/TSocket.py @@ -151,8 +151,8 @@ class TServerSocket(TSocketBase, TServerTransportBase):      self.handle = socket.socket(res[0], res[1])      self.handle.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) -    if hasattr(self.handle, 'set_timeout'): -      self.handle.set_timeout(None) +    if hasattr(self.handle, 'settimeout'): +      self.handle.settimeout(None)      self.handle.bind(res[4])      self.handle.listen(128) diff --git a/module/web/json_app.py b/module/web/json_app.py index 2d0f56357..f3626405c 100644 --- a/module/web/json_app.py +++ b/module/web/json_app.py @@ -186,7 +186,7 @@ def add_package():          PYLOAD.setPackageData(pack, data) -@route("/json/move_package/<dest:int/<id:int>") +@route("/json/move_package/<dest:int>/<id:int>")  @login_required('MODIFY')  def move_package(dest, id):      try: diff --git a/pyLoadCore.py b/pyLoadCore.py index 99d8642bd..4d0a112aa 100755 --- a/pyLoadCore.py +++ b/pyLoadCore.py @@ -472,6 +472,8 @@ class Core(object):          self.files = FileHandler(self)          self.db.manager = self.files #ugly? +        self.files.fixPackageOrder(0) +        self.files.fixPackageOrder(1)      def init_webserver(self):          if self.config['webinterface']['activated']: | 
