Exemplo n.º 1
0
 def save(self):
     """Saves the `Host` in the :class:`Workspace` 's database"""
     cursor = Db.get().cursor()
     if self.id is not None:
         #If we have an ID, the host is already saved in the database : UPDATE
         cursor.execute(
             '''UPDATE hosts
             SET
                 name = ?,
                 hostname = ?,
                 uname = ?,
                 issue = ?,
                 machine_id = ?,
                 macs = ?
             WHERE id = ?''',
             (self.name, self.hostname, self.uname, self.issue,
              self.machine_id, json.dumps(self.macs), self.id))
     else:
         #The host doesn't exists in database : INSERT
         cursor.execute(
             '''INSERT INTO hosts(name, hostname, uname, issue, machine_id, macs)
             VALUES (?, ?, ?, ?, ?, ?) ''',
             (self.name, self.hostname, self.uname, self.issue,
              self.machine_id, json.dumps(self.macs)))
         cursor.close()
         cursor = Db.get().cursor()
         cursor.execute('SELECT id FROM hosts WHERE name=?', (self.name, ))
         self.id = cursor.fetchone()[0]
     cursor.close()
     Db.get().commit()
Exemplo n.º 2
0
    def save(self):
        """Save the Path in database

        If the Path object has an id it means it is already stored in database,
        so it is updated. Else it is inserted and the id is set in the object.

        """

        cursor = Db.get().cursor()
        if self.id is not None:
            cursor.execute(
                '''UPDATE paths
                SET
                    src = ?,
                    dst = ?
                WHERE id = ?''', (self.src.id if self.src is not None else 0,
                                  self.dst.id, self.id))
        else:
            cursor.execute(
                '''INSERT INTO paths(src, dst)
                VALUES (?, ?) ''',
                (self.src.id if self.src is not None else 0, self.dst.id))
            cursor.close()
            cursor = Db.get().cursor()
            cursor.execute('SELECT id FROM paths WHERE src=? AND dst=?', \
                    (self.src.id if self.src is not None else 0, self.dst.id))
            self.id = cursor.fetchone()[0]
        cursor.close()
        Db.get().commit()
Exemplo n.º 3
0
    def delete(self):
        """Removes the `Host` from the :class:`Workspace`

        Recursively removes all :class:`Path` s starting from this `Host`
        """

        from baboossh import Path
        if self.id is None:
            return {}
        from baboossh.utils import unstore_targets_merge
        del_data = {}
        for path in Path.find_all(src=self):
            unstore_targets_merge(del_data, path.delete())
        for endpoint in self.endpoints:
            endpoint.host = None
            endpoint.save()
        cursor = Db.get().cursor()
        cursor.execute('DELETE FROM hosts WHERE id = ?', (self.id, ))
        cursor.close()
        Db.get().commit()
        unstore_targets_merge(
            del_data, {
                "Host": [
                    type(self).get_id(self.hostname, self.uname, self.issue,
                                      self.machine_id, self.macs)
                ]
            })
        return del_data
Exemplo n.º 4
0
    def delete(self):
        """Delete an Endpoint from the :class:`.Workspace`"""

        from baboossh import Path
        from baboossh import Connection
        if self.id is None:
            return {}
        from baboossh.utils import unstore_targets_merge
        del_data = {}
        if self.host is not None:
            endpoints = self.host.endpoints
            if len(endpoints) == 1:
                unstore_targets_merge(del_data, self.host.delete())
        for connection in Connection.find_all(endpoint=self):
            unstore_targets_merge(del_data, connection.delete())
        for path in Path.find_all(dst=self):
            unstore_targets_merge(del_data, path.delete())
        cursor = Db.get().cursor()
        cursor.execute('DELETE FROM tags WHERE endpoint = ?', (self.id, ))
        cursor.execute('DELETE FROM endpoints WHERE id = ?', (self.id, ))
        cursor.close()
        Db.get().commit()
        unstore_targets_merge(
            del_data, {"Endpoint": [type(self).get_id(self.ip, self.port)]})
        return del_data
Exemplo n.º 5
0
    def create(cls, name: str):
        """Create a new workspace

        Create a new workspace with its dedicated folder (in `$HOME/.baboossh` by
        default) and its database.

        """

        if name == "":
            print("Cannot use workspace with empty name")
            raise ValueError
        if re.match(r'^[\w_\.-]+$', name) is None:
            print('Invalid characters in workspace name. \
                    Allowed characters are letters, numbers and ._-')
            raise ValueError
        workspace_folder = os.path.join(WORKSPACES_DIR, name)
        if not os.path.exists(workspace_folder):
            try:
                os.mkdir(workspace_folder)
                os.mkdir(os.path.join(workspace_folder, "loot"))
                os.mkdir(os.path.join(workspace_folder, "keys"))
                with open(os.path.join(workspace_folder, "workspace.version"), "w") as file:
                    file.write(BABOOSSH_VERSION)
            except OSError:
                print("Creation of the directory " + workspace_folder + " failed")
                raise OSError
            print("Workspace "+name+" created")
        else:
            print("Workspace already exists")
            raise ValueError
        #create database
        Db.build(name)
        return Workspace(name)
Exemplo n.º 6
0
    def save(self):
        """Save the `Connection` to the :class:`Workspace`'s database"""

        if self.user is None or self.creds is None:
            return
        cursor = Db.get().cursor()
        if self.id is not None:
            #If we have an ID, the endpoint is already saved in the database : UPDATE
            cursor.execute(
                '''UPDATE connections
                SET
                    endpoint= ?,
                    user = ?,
                    cred = ?,
                    root = ?
                WHERE id = ?''', (self.endpoint.id, self.user.id,
                                  self.creds.id, self.root, self.id))
        else:
            #The endpoint doesn't exists in database : INSERT
            cursor.execute(
                '''INSERT INTO connections(endpoint, user, cred, root)
                VALUES (?, ?, ?, ?) ''',
                (self.endpoint.id, self.user.id, self.creds.id, self.root))
            cursor.close()
            cursor = Db.get().cursor()
            cursor.execute(
                'SELECT id FROM connections WHERE endpoint=? AND user=? AND cred=?',
                (self.endpoint.id, self.user.id, self.creds.id))
            self.id = cursor.fetchone()[0]
        cursor.close()
        Db.get().commit()
Exemplo n.º 7
0
 def save(self):
     """Save the `Creds` to the :class:`Workspace` 's database"""
     cursor = Db.get().cursor()
     if self.id is not None:
         #If we have an ID, the creds is already saved in the database : UPDATE
         cursor.execute('''UPDATE creds
             SET
                 type = ?,
                 content = ?,
                 identifier = ?,
                 scope = ?,
                 found = ?
             WHERE id = ?''',
                        (self.creds_type, self.creds_content, self.obj.identifier, self.scope, self.found.id if self.found is not None else None, self.id))
     else:
         #The creds doesn't exists in database : INSERT
         cursor.execute('''INSERT INTO creds(type, content, identifier, scope, found)
             VALUES (?, ?, ?, ?, ?) ''',
                        (self.creds_type, self.creds_content, self.obj.identifier, self.scope, self.found.id if self.found is not None else None))
         cursor.close()
         cursor = Db.get().cursor()
         cursor.execute('SELECT id FROM creds WHERE type=? and identifier=?', (self.creds_type, self.obj.identifier))
         self.id = cursor.fetchone()[0]
     cursor.close()
     Db.get().commit()
Exemplo n.º 8
0
 def untag(self, tagname):
     cursor = Db.get().cursor()
     cursor.execute('DELETE FROM tags WHERE name = ? and endpoint = ?',
                    (tagname, self.id))
     cursor.close()
     Db.get().commit()
     try:
         self.tags.remove(tagname)
     except KeyError:
         pass
Exemplo n.º 9
0
    def delete(self):
        """Delete an Path from the :class:`.Workspace`"""

        if self.id is None:
            return {}
        cursor = Db.get().cursor()
        cursor.execute('DELETE FROM paths WHERE id = ?', (self.id, ))
        cursor.close()
        Db.get().commit()
        return {"Path": [type(self).get_id(self.src, self.dst)]}
Exemplo n.º 10
0
 def tag(self, tagname):
     cursor = Db.get().cursor()
     try:
         cursor.execute(
             '''INSERT INTO tags (name, endpoint) VALUES (?, ?)''',
             (tagname, self.id))
     except sqlite3.IntegrityError:
         pass
     cursor.close()
     Db.get().commit()
     self.tags.add(tagname)
Exemplo n.º 11
0
 def close(self):
     for tunnel in self.tunnels.values():
         tunnel.close()
     for connection in Connection.find_all():
         if connection.transport is not None:
             connection.close()
     for obj in self.store.values():
         for instance in obj.values():
             del instance
     Db.close()
     type(self).active = None
     print("Closing workspace "+self.name)
Exemplo n.º 12
0
    def delete(self):
        """Delete the `Connection` from the :class:`Workspace`'s database"""

        if self.id is None:
            return {}
        cursor = Db.get().cursor()
        cursor.execute('DELETE FROM connections WHERE id = ?', (self.id, ))
        cursor.close()
        Db.get().commit()
        return {
            "Connection":
            [type(self).get_id(self.endpoint, self.user, self.creds)]
        }
Exemplo n.º 13
0
    def __init__(self, endpoint, user, cred):
        """Create the object and fetches info from database if it has been saved.
        
        Args:
            endpoint (:class:`Endpoint`): The Connection's endpoint
            user (:class:`User`): The Connection's user
            cred (:class:`Creds`): The Connection's credentials
        """

        self.endpoint = endpoint
        self.user = user
        self.creds = cred
        self.id = None
        self.root = False
        self.sock = None
        self.transport = None
        self.used_by_connections = []
        self.used_by_tunnels = []
        if user is None or cred is None:
            return
        cursor = Db.get().cursor()
        cursor.execute(
            'SELECT id, root FROM connections WHERE endpoint=? AND user=? AND cred=?',
            (self.endpoint.id, self.user.id, self.creds.id))
        saved_connection = cursor.fetchone()
        cursor.close()
        if saved_connection is not None:
            self.id = saved_connection[0]
            self.root = saved_connection[1] != 0
Exemplo n.º 14
0
    def find_one(cls, endpoint_id=None, ip_port=None):
        """Find an `Endpoint` by its id or it's IP address:Port

        Args:
            endpoint_id (int): the `Endpoint` id to search
            ip_port (str): The IP and port as "<ip>:<port>"

        Returns:
            A single `Endpoint` or `None`.
        """

        cursor = Db.get().cursor()

        if endpoint_id is not None:
            if endpoint_id == 0:
                cursor.close()
                return None
            cursor.execute('''SELECT ip, port FROM endpoints WHERE id=?''',
                           (endpoint_id, ))
        elif ip_port is not None:
            ip, sep, port = ip_port.partition(":")
            if port == "":
                raise ValueError
            cursor.execute(
                '''SELECT ip, port FROM endpoints WHERE ip=? and port=?''',
                (ip, port))
        else:
            cursor.close()
            return None

        row = cursor.fetchone()
        cursor.close()
        if row is None:
            return None
        return Endpoint(row[0], row[1])
Exemplo n.º 15
0
    def find_all(cls, scope=None):
        """Returns a `List` of all `Host` s in the :class:`Workspace` matching the criteria

        Args:
            scope (bool): whether to return only `Host`s in scope (`True`),
                out of scope (`False`) or both (`None`)
            name (str): the `Host` s' name to match

        Returns:
            the `List` of `Host` s
        """

        ret = []
        cursor = Db.get().cursor()

        req = cursor.execute(
            'SELECT hostname, uname, issue, machine_id, macs FROM hosts')

        for row in req:
            host = Host(row[0], row[1], row[2], row[3], json.loads(row[4]))
            if scope is None:
                ret.append(host)
            elif host.scope == scope:
                ret.append(host)
        cursor.close()
        return ret
Exemplo n.º 16
0
    def search(cls, field, val, show_all=False):
        """Search in the workspace for an `Endpoint`

        Args:
            field (str): the `Endpoint` attribute to search in
            val (str): the value to search for
            show_all (bool): whether to include out-of scope `Endpoint` s in search results

        Returns:
            A `List` of `Endpoint` s corresponding to the search.
        """

        if field not in cls.search_fields:
            raise ValueError
        ret = []
        cursor = Db.get().cursor()
        val = "%" + val + "%"
        if show_all:
            #Ok this sounds fugly, but there seems to be no way to set a column name in a parameter. The SQL injection risk is mitigated as field must be in allowed fields, but if you find something better I take it
            cursor.execute(
                'SELECT ip, port FROM endpoints WHERE {} LIKE ?'.format(field),
                (val, ))
        else:
            cursor.execute(
                'SELECT ip, port FROM endpoints WHERE scope=? and {} LIKE ?'.
                format(field), (True, val))
        for row in cursor:
            ret.append(Endpoint(row[0], row[1]))
        return ret
Exemplo n.º 17
0
    def find_all(cls, scope=None, found=None):
        """Find all Endpoints matching the criteria

        Args:
            scope (bool):
                List Endpoints in scope (`True`), out of scope (`False`), or both (`None`)
            found (:class:`Endpoint`):
                The `Endpoint` the endpoints were discovered on

        Returns:
            A list of all `Endpoint` s in the :class:`.Workspace`
        """

        ret = []
        cursor = Db.get().cursor()
        if found is None:
            if scope is None:
                req = cursor.execute('SELECT ip, port FROM endpoints')
            else:
                req = cursor.execute(
                    'SELECT ip, port FROM endpoints WHERE scope=?', (scope, ))
        else:
            if scope is None:
                req = cursor.execute(
                    'SELECT ip, port FROM endpoints WHERE found=?',
                    (found.id, ))
            else:
                req = cursor.execute(
                    'SELECT ip, port FROM endpoints WHERE scope=? and found=?',
                    (scope, found.id))
        for row in req:
            ret.append(Endpoint(row[0], row[1]))
        return ret
Exemplo n.º 18
0
 def delete(self):
     """Delete a `Creds` from the :class:`.Workspace`"""
     from baboossh import Connection
     if self.id is None:
         return {}
     from baboossh.utils import unstore_targets_merge
     del_data = {}
     for connection in Connection.find_all(creds=self):
         unstore_targets_merge(del_data, connection.delete())
     self.obj.delete()
     cursor = Db.get().cursor()
     cursor.execute('DELETE FROM creds WHERE id = ?', (self.id, ))
     cursor.close()
     Db.get().commit()
     unstore_targets_merge(del_data, {"Creds":[type(self).get_id(self.creds_type, self.creds_content)]})
     return del_data
Exemplo n.º 19
0
    def find_all(cls, scope=None, found=None):
        """Find all `Creds`

        Args:
            scope (bool): List `Creds` in scope (`True`), out of scope
                (`False`), or both (`None`)
            found (:class:`Endpoint`):
                the `Endpoint` the `Creds` were discovered on

        Returns:
            A list of all `Creds` in the :class:`.Workspace`
        """

        ret = []
        cursor = Db.get().cursor()
        if found is None:
            if scope is None:
                req = cursor.execute('SELECT type, content FROM creds')
            else:
                req = cursor.execute('SELECT type, content FROM creds WHERE scope=?', (scope, ))
        else:
            if scope is None:
                req = cursor.execute('SELECT type, content FROM creds WHERE found=?', (found.id, ))
            else:
                req = cursor.execute('SELECT type, content FROM creds WHERE found=? AND scope=?', (found.id, scope))
        for row in req:
            ret.append(Creds(row[0], row[1]))
        return ret
Exemplo n.º 20
0
    def search(cls, field, val, show_all=False):
        """Search in the workspace for a `Host`

        Args:
            field (str): the `Host` attribute to search in
            val (str): the value to search for
            show_all (bool): whether to include out-of scope `Host` s in search results

        Returns:
            A `List` of `Host` s corresponding to the search.
        """

        if field not in cls.search_fields:
            raise ValueError
        ret = []
        cursor = Db.get().cursor()
        val = "%" + val + "%"
        #Ok this sounds fugly, but there seems to be no way to set a column name in a parameter. The SQL injection risk is mitigated as field must be in allowed fields, but if you find something better I take it
        for row in cursor.execute(
                'SELECT hostname, uname, issue, machine_id, macs FROM hosts WHERE {} LIKE ?'
                .format(field), (val, )):
            ret.append(Host(row[0], row[1], row[2], row[3],
                            json.loads(row[4])))
        if not show_all:
            ret = [host for host in ret if host.scope]
        return ret
Exemplo n.º 21
0
 def __init__(self, name):
     from baboossh import Endpoint
     self.name = name
     self.endpoints = []
     cursor = Db.get().cursor()
     for row in cursor.execute('SELECT endpoint FROM tags WHERE name=?',
                               (self.name, )):
         self.endpoints.append(Endpoint.find_one(endpoint_id=row[0]))
Exemplo n.º 22
0
    def find_one(cls,
                 connection_id=None,
                 endpoint=None,
                 scope=None,
                 gateway_to=None):
        """Find a `Connection` by its id, endpoint or if it can be used as a gateway to an :class:`Endpoint`

        Args:
            connection_id (int): the `Connection` id to search
            endpoint (:class:`Endpoint`): the `Connection` endpoint to search
            gateway_to (:class:`Endpoint`): the Endpoint to which you want to find a gateway
            scope (bool): whether to include only in scope Connections (`True`), out of scope Connections (`False`) or both (`None`)

        Returns:
            A single `Connection` or `None`.
        """

        if gateway_to is not None:
            if gateway_to.distance is not None and gateway_to.distance == 0:
                return None
            try:
                closest_host = Host.find_one(prev_hop_to=gateway_to)
            except NoPathError as exc:
                raise exc
            if closest_host is None:
                return None
            return cls.find_one(endpoint=closest_host.closest_endpoint,
                                scope=True)

        cursor = Db.get().cursor()
        if connection_id is not None:
            req = cursor.execute(
                'SELECT endpoint, user, cred FROM connections WHERE id=?',
                (connection_id, ))
        elif endpoint is not None:
            req = cursor.execute(
                'SELECT endpoint, user, cred FROM connections WHERE endpoint=? ORDER BY root ASC',
                (endpoint.id, ))
        else:
            cursor.close()
            return None
        if scope is None:
            row = cursor.fetchone()
            cursor.close()
            if row is None:
                return None
            return Connection(Endpoint.find_one(endpoint_id=row[0]),
                              User.find_one(user_id=row[1]),
                              Creds.find_one(creds_id=row[2]))
        for row in req:
            conn = Connection(Endpoint.find_one(endpoint_id=row[0]),
                              User.find_one(user_id=row[1]),
                              Creds.find_one(creds_id=row[2]))
            if scope == conn.scope:
                cursor.close()
                return conn
        cursor.close()
        return None
Exemplo n.º 23
0
 def endpoints(self):
     """Returns a `List` of the `Host` 's :class:`Endpoint` s"""
     from baboossh import Endpoint
     endpoints = []
     cursor = Db.get().cursor()
     for row in cursor.execute(
             'SELECT ip, port FROM endpoints WHERE host=?', (self.id, )):
         endpoints.append(Endpoint(row[0], row[1]))
     cursor.close()
     return endpoints
Exemplo n.º 24
0
    def distance(self):
        """Returns the `Host` 's number of hops from `"Local"`"""

        cursor = Db.get().cursor()
        cursor.execute(
            'SELECT distance FROM endpoints WHERE host=? ORDER BY distance DESC',
            (self.id, ))
        row = cursor.fetchone()
        cursor.close()
        return row[0]
Exemplo n.º 25
0
    def save(self):
        """Save the Endpoint in database

        If the Endpoint object has an id it means it is already stored in database,
        so it is updated. Else it is inserted and the id is set in the object.

        """

        cursor = Db.get().cursor()
        if self.id is not None:
            #If we have an ID, the endpoint is already saved in the database : UPDATE
            cursor.execute(
                '''UPDATE endpoints
                SET
                    ip = ?,
                    port = ?,
                    host = ?,
                    reachable = ?,
                    distance = ?,
                    scope = ?,
                    found = ?
                WHERE id = ?''',
                (self.ip, self.port,
                 self.host.id if self.host is not None else None,
                 self.reachable, self.distance, self.scope,
                 self.found.id if self.found is not None else None, self.id))
        else:
            #The endpoint doesn't exists in database : INSERT
            cursor.execute(
                '''INSERT INTO endpoints(ip, port, host, reachable, distance, scope, found)
                VALUES (?, ?, ?, ?, ?, ?, ?) ''',
                (self.ip, self.port,
                 self.host.id if self.host is not None else None,
                 self.reachable, self.distance, self.scope,
                 self.found.id if self.found is not None else None))
            cursor.close()
            cursor = Db.get().cursor()
            cursor.execute('SELECT id FROM endpoints WHERE ip=? AND port=?',
                           (self.ip, self.port))
            self.id = cursor.fetchone()[0]
        cursor.close()
        Db.get().commit()
Exemplo n.º 26
0
    def closest_endpoint(self):
        """Returns the `Host` 's closest :class:`Endpoint`"""

        cursor = Db.get().cursor()
        cursor.execute(
            'SELECT ip, port FROM endpoints WHERE host=? ORDER BY distance DESC',
            (self.id, ))
        row = cursor.fetchone()
        cursor.close()
        from baboossh import Endpoint
        return Endpoint(row[0], row[1])
Exemplo n.º 27
0
 def __init__(self, src, dst):
     if str(src) == str(dst):
         raise ValueError("Can't create path to self")
     self.src = src
     self.dst = dst
     self.id = None
     cursor = Db.get().cursor()
     cursor.execute('SELECT id FROM paths WHERE src=? AND dst=?', \
             (self.src.id if self.src is not None else 0, self.dst.id))
     saved_path = cursor.fetchone()
     cursor.close()
     if saved_path is not None:
         self.id = saved_path[0]
Exemplo n.º 28
0
    def __init__(self, hostname, uname, issue, machine_id, macs):
        self.hostname = hostname
        self.id = None
        self.uname = uname
        self.issue = issue
        self.machine_id = machine_id
        self.macs = macs
        cursor = Db.get().cursor()
        cursor.execute(
            'SELECT id, name FROM hosts WHERE hostname=? AND uname=? AND issue=? AND machine_id=? AND macs=?',
            (self.hostname, self.uname, self.issue, self.machine_id,
             json.dumps(self.macs)))
        saved_host = cursor.fetchone()
        cursor.close()
        if saved_host is not None:
            self.id = saved_host[0]
            self.name = saved_host[1]
        else:
            if hostname != "":
                name = hostname.split(".")[0]
                if len(name) > 20:
                    name = name[:20]
                incr = 0
            else:
                name = "host"
                incr = 1

            self.name = None
            while self.name is None:
                fullname = name if incr == 0 else name + "_" + str(incr)
                cursor = Db.get().cursor()
                cursor.execute('SELECT id FROM hosts WHERE name=?',
                               (fullname, ))
                if cursor.fetchone() is not None:
                    incr = incr + 1
                else:
                    self.name = fullname
                cursor.close()
Exemplo n.º 29
0
    def find_one(cls, host_id=None, name=None, prev_hop_to=None):
        """Find a `Host` by its id

        Args:
            host_id (int): the desired `Host` 's id
            name (str): the `Host` 's name to match

        Returns:
            A `Host` or `None`
        """

        if prev_hop_to is not None:
            from baboossh import Path
            paths = Path.find_all(dst=prev_hop_to)
            smallest_distance = None
            closest = None
            for path in paths:
                if path.src is None:
                    #Direct path found, we can stop here
                    return None
                if closest is None:
                    closest = path.src
                    smallest_distance = path.src.distance
                    continue
                if path.src.distance < smallest_distance:
                    closest = path.src
                    smallest_distance = path.src.distance
                    continue
            if closest is None:
                raise NoPathError
            return closest

        cursor = Db.get().cursor()
        if host_id is not None:
            cursor.execute(
                '''SELECT hostname, uname, issue, machine_id, macs FROM hosts WHERE id=?''',
                (host_id, ))
        elif name is not None:
            cursor.execute(
                '''SELECT hostname, uname, issue, machine_id, macs FROM hosts WHERE name=?''',
                (name, ))
        else:
            cursor.close()
            return None

        row = cursor.fetchone()
        cursor.close()
        if row is None:
            return None
        return Host(row[0], row[1], row[2], row[3], json.loads(row[4]))
Exemplo n.º 30
0
 def __init__(self, name):
     if name == "":
         raise ValueError("Cannot use workspace with empty name")
     if re.match(r'^[\w_\.-]+$', name) is None:
         print('Invalid characters in workspace name. \
                 Allowed characters are letters, numbers and ._-')
         raise ValueError
     self.workspace_folder = os.path.join(WORKSPACES_DIR, name)
     if not os.path.exists(self.workspace_folder):
         raise ValueError("Workspace "+name+" does not exist")
     try:
         with open(os.path.join(self.workspace_folder, "workspace.version"), "r") as f:
             self.version = f.read()
     except FileNotFoundError:
         self.version = "1.0.x"
     if not is_workspace_compat(self.version):
         raise WorkspaceVersionError(BABOOSSH_VERSION, self.version)
     Db.connect(name)
     self.name = name
     self.tunnels = {}
     self.options = {
         "endpoint":None,
         "user":None,
         "creds":None,
         "payload":None,
         "params":None,
             }
     type(self).active = self
     self.store = {
         "Connection": {},
         "Creds": {},
         "Endpoint": {},
         "Host": {},
         "Path": {},
         "User": {},
             }