Example #1
0
    def unassign(self, assign):
        """
        Unassign a TLS certificate from a website or service.

        :param dict assign: ``Assign`` object to unassign
        :returns: self
        """
        signals.emit("certificates", "pre_unassign", (self, assign))
        nginx_reload = False
        if assign["type"] == "website":
            websites.get(assign["id"]).ssl_disable()
            self.assigns.remove(assign)
            nginx_reload = True
        elif assign["type"] == "genesis":
            config.set("genesis", "cert_file", "")
            config.set("genesis", "cert_key", "")
            config.set("genesis", "ssl", False)
            config.save()
            self.assigns.remove(assign)
        else:
            applications.get(assign["aid"]).ssl_disable(assign["sid"])
            self.assigns.remove(assign)
        if nginx_reload:
            websites.nginx_reload()
        signals.emit("certificates", "post_unassign", (self, assign))
        return None
Example #2
0
 def get(self, id):
     websites.get()
     svcs = tracked_services.get(id)
     if id and not svcs:
         abort(404)
     if type(svcs) == list:
         return jsonify(policies=[x.as_dict() for x in svcs])
     else:
         return jsonify(policy=svcs.as_dict())
Example #3
0
def list_sites():
    """List all websites"""
    try:
        adata = [x.serialized for x in websites.get()]
        _list_websites(adata)
    except Exception as e:
        raise CLIException(str(e))
Example #4
0
File: backup.py Project: ns408/core
def create(id, data=True, nthread=NotificationThread()):
    """
    Convenience function to create a backup.

    :param str id: ID of associated app (or website) to backup
    :param bool data: Backup app data also?
    :returns: Backup info
    :rtype: Backup
    """
    controller = None
    if id == "arkOS":
        controller = arkOSBackupCfg("arkOS", "setting",
                                    version=arkos_version)
        return controller.backup()
    app = applications.get(id)
    if app and app.type != "website" and hasattr(app, "_backup"):
        controller = app._backup(app.id, app.icon, version=app.version)
    else:
        sites = websites.get()
        for x in sites:
            if x.id == id:
                controller = x.backup
                break
    if not controller:
        raise errors.InvalidConfigError("No backup controller found")
    return controller.backup(data=data, nthread=nthread)
Example #5
0
 def put(self, id):
     data = request.get_json()["website"]
     site = websites.get(id)
     if not site:
         abort(404)
     if data.get("operation") == "enable":
         site.nginx_enable()
     elif data.get("operation") == "disable":
         site.nginx_disable()
     elif data.get("operation") == "enable_ssl":
         cert = certificates.get(data["cert"])
         cert.assign("website", site.id)
     elif data.get("operation") == "disable_ssl":
         site.cert.unassign("website", site.id)
     elif data.get("operation") == "update":
         id = as_job(self._put, site)
         return job_response(
             id,
             data={"website": site.serialized.update({"is_ready": False})})
     else:
         site.domain = data["domain"]
         site.port = data["port"]
         site.edit(data.get("new_name"))
     if data.get("new_name"):
         remove_record("website", id)
         push_record("website", site.serialized)
     return jsonify(website=site.serialized)
Example #6
0
File: backup.py Project: ns408/core
def restore(backup, data=True, nthread=NotificationThread()):
    """
    Convenience function to restore a backup.

    :param Backup backup: Backup to restore
    :param bool data: Restore included data files as well?
    :returns: Backup info
    :rtype: Backup
    """
    controller = None
    if backup["type"] == "site":
        sites = websites.get()
        for x in sites:
            if x.id == backup["pid"]:
                controller = x.backup
                break
        else:
            app = applications.get(backup["site_type"])
            controller = app._backup(backup["pid"], backup["icon"], True)
    else:
        app = applications.get(backup["pid"])
        controller = app._backup()
    if not controller:
        raise errors.InvalidConfigError("No backup controller found")
    b = controller.restore(backup, data, nthread)
    return b
Example #7
0
def assigns():
    """List all apps/sites that can use certificates."""
    click.echo("Apps/Sites that can use certificates:")
    try:
        assigns = []
        assigns.append({
            "type": "genesis",
            "id": "genesis",
            "name": "arkOS Genesis/API"
        })
        for x in websites.get():
            assigns.append({
                "type": "website",
                "id": x.id,
                "name": x.id if x.app else x.name
            })
        for x in applications.get(installed=True):
            if x.type == "app" and x.uses_ssl:
                for y in x.get_ssl_able():
                    assigns.append(y)
        for x in assigns:
            imsg = click.style("(" + x["type"].capitalize() + ")", fg="green")
            click.echo(
                click.style(x["name"], fg="white", bold=True) + " " + imsg)
    except Exception as e:
        raise CLIException(str(e))
Example #8
0
    def assign(self, assign):
        """
        Assign a TLS certificate to a website or service.

        :param dict assign: ``Assign`` object to assign
        :returns: self
        """
        signals.emit("certificates", "pre_assign", (self, assign))
        nginx_reload = False
        if assign["type"] == "genesis":
            config.set("genesis", "cert_file", self.cert_path)
            config.set("genesis", "cert_key", self.key_path)
            config.set("genesis", "ssl", True)
            config.save()
            self.assigns.append(assign)
        elif assign["type"] == "website":
            w = websites.get(assign["id"])
            w.cert = self
            w.ssl_enable()
            self.assigns.append(assign)
            nginx_reload = True
        else:
            d = applications.get(assign["aid"]).ssl_enable(self, assign["sid"])
            self.assigns.append(d)
        if nginx_reload:
            websites.nginx_reload()
        signals.emit("certificates", "post_assign", (self, assign))
        return self
Example #9
0
def disable(id):
    """Disable a website"""
    try:
        site = websites.get(id)
        site.nginx_disable()
        logger.success('ctl:site:disable', 'Disabled {0}'.format(id))
    except Exception as e:
        raise CLIException(str(e))
Example #10
0
def is_installed():
    # Verify the different components of the server setup
    if not os.path.exists('/etc/radicale/config') or not os.path.isdir('/usr/lib/radicale') \
            or not os.path.exists('/etc/radicale/radicale.wsgi') \
            or not websites.get('radicale'):
        return False
    else:
        return True
Example #11
0
def my_url():
    url = "http"
    w = websites.get('radicale')
    if not w: return ""
    url += "s://" if w.cert else "://"
    url += w.addr
    url += (":" + str(w.port)) if w.port not in [80, 443] else ""
    return url
Example #12
0
def delete(id):
    """Remove a website"""
    try:
        site = websites.get(id)
        site.remove()
        logger.success('ctl:site:delete', 'Removed {0}'.format(id))
    except Exception as e:
        raise CLIException(str(e))
def is_installed():
    # Verify the different components of the server setup
    if not os.path.exists('/etc/radicale/config') or not os.path.isdir('/usr/lib/radicale') \
            or not os.path.exists('/etc/radicale/radicale.wsgi') \
            or not websites.get('radicale'):
        return False
    else:
        return True
Example #14
0
def update(id):
    """Update a website"""
    try:
        site = websites.get(id)
        site.update()
        logger.success('ctl:site:update', 'Updated {0}'.format(id))
    except Exception as e:
        raise CLIException(str(e))
Example #15
0
    def restore(self, data):
        signals.emit("backups", "pre_restore", self)
        # Trigger pre-restore hook for the app/site
        self.pre_restore()

        # Extract all files in archive
        sitename = ""
        with tarfile.open(data["path"], "r:gz") as t:
            for x in t.getnames():
                if x.startswith("etc/nginx/sites-available"):
                    sitename = os.path.basename(x)
            t.extractall("/")

        # If it's a website that had a database, restore DB via SQL file too
        dbpasswd = ""
        if self.ctype == "site" and sitename:
            self.site = websites.get(sitename)
            if not self.site:
                websites.scan()
                self.site = websites.get(sitename)
            meta = ConfigParser.SafeConfigParser()
            meta.read(os.path.join(self.site.path, ".arkos"))
            if meta.get("website", "dbengine", None) and os.path.exists("/%s.sql"%sitename):
                dbmgr = databases.get_managers(meta.get("website", "dbengine"))
                if databases.get(sitename):
                    databases.get(sitename).remove()
                db = dbmgr.add_db(sitename)
                with open("/%s.sql"%sitename, "r") as f:
                    db.execute(f.read())
                os.unlink("/%s.sql"%sitename)
                if dbmgr.meta.database_multiuser:
                    dbpasswd = random_string()[0:16]
                    if databases.get_user(sitename):
                        databases.get_user(sitename).remove()
                    db_user = dbmgr.add_user(sitename, dbpasswd)
                    db_user.chperm("grant", db)

        # Trigger post-restore hook for the app/site
        if self.ctype == "site":
            self.post_restore(self.site, dbpasswd)
            self.site.nginx_enable()
        else:
            self.post_restore()
        signals.emit("backups", "post_restore", self)
        data["is_ready"] = True
        return data
def my_url():
    url = "http"
    w = websites.get('radicale')
    if not w: return ""
    url += "s://" if w.cert else "://"
    url += w.addr
    url += (":"+str(w.port)) if w.port not in [80, 443] else ""
    return url
Example #17
0
def setup(addr, port):
    # Make sure Radicale is installed and ready
    if not python.is_installed('Radicale'):
        python.install('radicale')
    # due to packaging bugs, make extra sure perms are readable
    st = os.stat('/usr/lib/python2.7/site-packages/radicale')
    for r, d, f in os.walk('/usr/lib/python2.7/site-packages/radicale'):
        for x in d:
            os.chmod(os.path.join(r, x),
                     st.st_mode | stat.S_IROTH | stat.S_IRGRP)
        for x in f:
            os.chmod(os.path.join(r, x),
                     st.st_mode | stat.S_IROTH | stat.S_IRGRP)
    if not os.path.exists('/etc/radicale/config'):
        if not os.path.isdir('/etc/radicale'):
            os.mkdir('/etc/radicale')
        with open('/etc/radicale/config', 'w') as f:
            f.write(default_config)
    if not os.path.isdir('/usr/lib/radicale'):
        os.mkdir('/usr/lib/radicale')
    # Add the site process
    u = users.SystemUser("radicale")
    u.add()
    g = groups.SystemGroup("radicale", users=["radicale"])
    g.add()
    wsgi_file = 'import radicale\n'
    wsgi_file += 'radicale.log.start()\n'
    wsgi_file += 'application = radicale.Application()\n'
    with open('/etc/radicale/radicale.wsgi', 'w') as f:
        f.write(wsgi_file)
    os.chmod('/etc/radicale/radicale.wsgi', 0766)
    cfg = {
        'directory': '/etc/radicale',
        'user': '******',
        'command':
        'uwsgi -s /tmp/radicale.sock -C --plugin python2 --wsgi-file radicale.wsgi',
        'stdout_logfile': '/var/log/radicale.log',
        'stderr_logfile': '/var/log/radicale.log'
    }
    s = services.Service("radicale", "supervisor", cfg=cfg)
    s.add()
    block = [
        nginx.Location(
            '/',
            nginx.Key('include', 'uwsgi_params'),
            nginx.Key('uwsgi_pass', 'unix:///tmp/radicale.sock'),
        )
    ]
    s = websites.get("radicale")
    if s: s.remove()
    s = websites.ReverseProxy(id="radicale",
                              name="Calendar/Contacts",
                              addr=addr,
                              port=port,
                              base_path="/usr/lib/radicale",
                              block=block)
    s.install()
Example #18
0
 def get(self, id):
     if request.args.get("rescan", None):
         websites.scan()
     sites = websites.get(id)
     if id and not sites:
         abort(404)
     if type(sites) == list:
         return jsonify(websites=[x.as_dict() for x in sites])
     else:
         return jsonify(website=sites.as_dict())
Example #19
0
 def get(self, id):
     if request.args.get("rescan", None):
         websites.scan()
     sites = websites.get(id)
     if id and not sites:
         abort(404)
     if isinstance(sites, websites.Site):
         return jsonify(website=sites.serialized)
     else:
         return jsonify(websites=[x.serialized for x in sites])
Example #20
0
 def _delete(self, id):
     message = Message()
     site = websites.get(id)
     try:
         site.remove(message)
         message.complete("success", "%s site removed successfully" % site.meta.name)
         remove_record("website", id)
     except Exception, e:
         message.complete("error", "%s could not be removed: %s" % (id, str(e)))
         raise
Example #21
0
def ssl_able():
    assigns = []
    for x in websites.get():
        assigns.append({"type": "website", "id": x.id, 
            "name": x.id if x.meta else x.name})
    for x in applications.get():
        if x.type == "app" and x.uses_ssl:
            for y in x.get_ssl_able():
                assigns.append(y)
    return jsonify(certassigns=assigns)
Example #22
0
def edit(id, address, port, new_name):
    """Edit a website"""
    try:
        site = websites.get(id)
        site.addr = address
        site.port = port
        site.edit(new_name or None)
        logger.success('ctl:site:edit', 'Edited {0}'.format(id))
    except Exception as e:
        raise CLIException(str(e))
Example #23
0
 def unassign(self, assign):
     signals.emit("certificates", "pre_unassign", (self, assign))
     nginx_reload = False
     if assign["type"] == "website":
         websites.get(assign["id"]).ssl_disable()
         self.assigns.remove(assign)
         nginx_reload = True
     elif assign["type"] == "genesis":
         config.set("genesis", "cert_file", "")
         config.set("genesis", "cert_key", "")
         config.set("genesis", "ssl", False)
         config.save()
         self.assigns.remove(assign)
     else:
         applications.get(assign["aid"]).ssl_disable(assign["sid"])
         self.assigns.remove(assign)
     if nginx_reload:
         websites.nginx_reload()
     signals.emit("certificates", "post_unassign", (self, assign))
     return None
Example #24
0
def ssl_able():
    assigns = []
    assigns.append({"type": "genesis", "id": "genesis",
                    "name": "arkOS Genesis/API"})
    for x in websites.get():
        assigns.append({"type": "website", "id": x.id,
                        "name": x.id if x.app else x.name})
    for x in applications.get(installed=True):
        if x.type == "app" and x.uses_ssl:
            for y in x.get_ssl_able():
                assigns.append(y)
    return jsonify(assignments=assigns)
Example #25
0
def perform_action(id, action):
    w = websites.get(id)
    if not w:
        abort(404)
    if not hasattr(w, action):
        abort(422)
    actionfunc = getattr(w, action)
    try:
        actionfunc()
    except Exception, e:
        resp = jsonify(message=str(e))
        resp.status_code = 500
        return resp
Example #26
0
def perform_action(id, action):
    w = websites.get(id)
    if not w:
        abort(404)
    if not hasattr(w, action):
        abort(422)
    actionfunc = getattr(w, action)
    try:
        actionfunc()
    except Exception as e:
        logger.error("Websites", str(e))
        return jsonify(errors={"msg": str(e)}), 500
    finally:
        return Response(status=200)
Example #27
0
def get_able():
    able = []
    for x in applications.get(installed=True):
        if x.type != "website" and hasattr(x, "_backup"):
            able.append({"type": "app", "icon": x.icon, "id": x.id})
    for x in websites.get():
        if not isinstance(x, websites.ReverseProxy):
            able.append({"type": "site", "icon": x.meta.icon, "id": x.id})
    for x in get():
        if not x["pid"] in [y["id"] for y in able]:
            able.append({"type": x["type"], "icon": x["icon"], "id": x["pid"]})
    if not "arkOS" in [x["id"] for x in able]:
        able.append({"type": "app", "icon": "fa fa-cog", "id": "arkOS"})
    return able
def setup(addr, port):
    # Make sure Radicale is installed and ready
    if not python.is_installed('Radicale'):
        python.install('radicale')
    # due to packaging bugs, make extra sure perms are readable
    st = os.stat('/usr/lib/python2.7/site-packages/radicale')
    for r, d, f in os.walk('/usr/lib/python2.7/site-packages/radicale'):
        for x in d:
            os.chmod(os.path.join(r, x), st.st_mode | stat.S_IROTH | stat.S_IRGRP)
        for x in f:
            os.chmod(os.path.join(r, x), st.st_mode | stat.S_IROTH | stat.S_IRGRP)
    if not os.path.exists('/etc/radicale/config'):
        if not os.path.isdir('/etc/radicale'):
            os.mkdir('/etc/radicale')
        with open('/etc/radicale/config', 'w') as f:
            f.write(default_config)
    if not os.path.isdir('/usr/lib/radicale'):
        os.mkdir('/usr/lib/radicale')
    # Add the site process
    u = users.SystemUser("radicale")
    u.add()
    g = groups.SystemGroup("radicale", users=["radicale"])
    g.add()
    wsgi_file = 'import radicale\n'
    wsgi_file += 'radicale.log.start()\n'
    wsgi_file += 'application = radicale.Application()\n'
    with open('/etc/radicale/radicale.wsgi', 'w') as f:
        f.write(wsgi_file)
    os.chmod('/etc/radicale/radicale.wsgi', 0766)
    cfg = {
        'directory': '/etc/radicale',
        'user': '******',
        'command': 'uwsgi -s /tmp/radicale.sock -C --plugin python2 --wsgi-file radicale.wsgi',
        'stdout_logfile': '/var/log/radicale.log',
        'stderr_logfile': '/var/log/radicale.log'
    }
    s = services.Service("radicale", "supervisor", cfg=cfg)
    s.add()
    block = [
        nginx.Location('/',
            nginx.Key('include', 'uwsgi_params'),
            nginx.Key('uwsgi_pass', 'unix:///tmp/radicale.sock'),
        )
    ]
    s = websites.get("radicale")
    if s: s.remove()
    s = websites.ReverseProxy(id="radicale", name="Calendar/Contacts", 
        addr=addr, port=port, base_path="/usr/lib/radicale", block=block)
    s.install()
Example #29
0
def create(id, data=True):
    controller = None
    if id == "arkOS":
        controller = arkOSBackupCfg(id="arkOS", icon="fa fa-cog", version=arkos_version)
        return controller.backup()
    app = applications.get(id)
    if app and app.type != "website" and hasattr(app, "_backup"):
        controller = app._backup(app.id, app.icon, version=app.version)
    else:
        sites = websites.get()
        for x in sites:
            if x.id == id:
                controller = x.backup
                break
    if not controller:
        raise Exception("No backup controller found")
    return controller.backup(data=data)
Example #30
0
def restore(backup, data=True):
    controller = None
    if backup["type"] == "site":
        sites = websites.get()
        for x in sites:
            if x.id == backup["pid"]:
                controller = x.backup
                break
        else:
            app = applications.get(backup["site_type"])
            controller = app._backup(backup["pid"], backup["icon"], True)
    else:
        app = applications.get(backup["pid"])
        controller = app._backup()
    if not controller:
        raise Exception("No backup controller found")
    b = controller.restore(backup)
    return b
Example #31
0
def get_points(id=None, path=None):
    """
    Retrieve points of interest from the system.

    Points of interest are obtained at scan from websites and mounted disks.

    :param str id: If present, filter by point ID
    :param str path: Filter by filesystem path
    :return: Point(s)OfInterest
    :rtype: PointOfInterest or list thereof
    """
    points = []
    from arkos import websites
    for x in get():
        if x.mountpoint and x.mountpoint not in ["/", "/boot"]:
            p = PointOfInterest(x.id, x.mountpoint,
                                "crypt" if x.crypt else "disk", "disk outline")
            points.append(p)
    for x in websites.get():
        if x.app and x.app.type == "website":
            p = PointOfInterest(x.id, x.data_path or x.path, "site",
                                x.app.icon)
            points.append(p)
    for x in sharers.get_shares():
        p = PointOfInterest(x.id, x.path, "share", "open folder")
        points.append(p)
    for x in sharers.get_mounts():
        p = PointOfInterest(x.id, x.path, "mount", "open folder outline")
        points.append(p)
    if id:
        for x in points:
            if x.id == id:
                return x
        return None
    elif path:
        for x in points:
            if x.path == path:
                return x
        return None
    return points
Example #32
0
File: backup.py Project: ns408/core
def get_able():
    """
    Obtain a list of arkOS application instances that support backups.

    This list includes all currently installed websites, apps and also arkOS.

    :returns: Website/app information
    :rtype: dict
    """
    able = []
    for x in applications.get(installed=True):
        if x.type != "website" and hasattr(x, "_backup"):
            able.append({"type": "app", "icon": x.icon, "id": x.id})
    for x in websites.get():
        if not isinstance(x, websites.ReverseProxy):
            able.append({"type": "site", "icon": x.app.icon, "id": x.id})
    for x in get():
        if not x["pid"] in [y["id"] for y in able]:
            able.append({"type": x["type"], "icon": x["icon"], "id": x["pid"]})
    if "arkOS" not in [x["id"] for x in able]:
        able.append({"type": "app", "icon": "setting", "id": "arkOS"})
    return able
Example #33
0
def get_points(id=None, path=None):
    points = []
    from arkos import websites
    for x in get():
        if x.mountpoint and not x.mountpoint in ["/", "/boot"]:
            p = PointOfInterest(x.id, x.mountpoint, "crypt" if x.crypt else "disk", "fa-hdd-o")
            points.append(p)
    for x in websites.get():
        if x.meta:
            p = PointOfInterest(x.id, x.data_path or x.path, "site", x.meta.icon)
            points.append(p)
    if id:
        for x in points:
            if x.id == id:
                return x
        return None
    elif path:
        for x in points:
            if x.path == path:
                return x
        return None
    return points
Example #34
0
 def assign(self, assign):
     signals.emit("certificates", "pre_assign", (self, assign))
     nginx_reload = False
     if assign["type"] == "genesis":
         config.set("genesis", "cert_file", self.cert_path)
         config.set("genesis", "cert_key", self.key_path)
         config.set("genesis", "ssl", True)
         config.save()
         self.assigns.append(assign)
     elif assign["type"] == "website":
         w = websites.get(assign["id"])
         w.cert = self
         w.ssl_enable()
         self.assigns.append(assign)
         nginx_reload = True
     else:
         d = applications.get(assign["aid"]).ssl_enable(self, assign["sid"])
         self.assigns.append(d)
     if nginx_reload:
         websites.nginx_reload()
     signals.emit("certificates", "post_assign", (self, assign))
     return self
Example #35
0
 def put(self, id):
     data = json.loads(request.data)["website"]
     site = websites.get(id)
     if not site:
         abort(404)
     if data.get("operation") == "enable":
         site.nginx_enable()
     elif data.get("operation") == "disable":
         site.nginx_disable()
     elif data.get("operation") == "enable_ssl":
         cert = certificates.get(data["cert"])
         cert.assign("website", site.id)
     elif data.get("operation") == "disable_ssl":
         site.cert.unassign("website", site.id)
     elif data.get("operation") == "update":
         site.update()
     else:
         site.addr = data["addr"]
         site.port = data["port"]
         site.edit(data.get("new_name"))
     push_record("website", site.as_dict())
     remove_record("website", id)
     return jsonify(message="Site edited successfully")
Example #36
0
File: backup.py Project: ns408/core
    def restore(self, backup, data=True, nthread=NotificationThread()):
        """
        Restore an associated arkOS app backup.

        :param Backup backup: backup to restore
        :param bool data: Restore backed up data files too?
        :param NotificationThread nthread: notification thread to use
        :returns: ``Backup``
        :rtype: dict
        """
        nthread.title = "Restoring backup"

        # Trigger pre-restore hook for the app/site
        signals.emit("backups", "pre_restore", self)
        msg = "Running pre-restore for {0}...".format(backup["pid"])
        nthread.update(Notification("info", "Backup", msg))
        self.pre_restore()

        # Extract all files in archive
        sitename = ""
        nthread.update(Notification("info", "Backup", "Extracting files..."))
        with tarfile.open(backup["path"], "r:gz") as t:
            for x in t.getnames():
                if x.startswith("etc/nginx/sites-available"):
                    sitename = os.path.basename(x)
            t.extractall("/")

        # If it's a website that had a database, restore DB via SQL file too
        dbpasswd = ""
        if self.ctype == "site" and sitename:
            self.site = websites.get(sitename)
            if not self.site:
                websites.scan()
                self.site = websites.get(sitename)
            meta = configparser.SafeConfigParser()
            meta.read(os.path.join(self.site.path, ".arkos"))
            sql_path = "/{0}.sql".format(sitename)
            if meta.get("website", "dbengine", fallback=None) \
                    and os.path.exists(sql_path):
                nthread.update(
                    Notification("info", "Backup", "Restoring database..."))
                dbmgr = databases.get_managers(meta.get("website", "dbengine"))
                if databases.get(sitename):
                    databases.get(sitename).remove()
                db = dbmgr.add_db(sitename)
                with open(sql_path, "r") as f:
                    db.execute(f.read())
                os.unlink(sql_path)
                if dbmgr.meta.database_multiuser:
                    dbpasswd = random_string(16)
                    dbuser = databases.get_users(sitename)
                    if dbuser:
                        dbuser.remove()
                    db_user = dbmgr.add_user(sitename, dbpasswd)
                    db_user.chperm("grant", db)

        # Trigger post-restore hook for the app/site
        msg = "Running post-restore for {0}...".format(backup["pid"])
        nthread.update(Notification("info", "Backup", msg))
        if self.ctype == "site":
            self.post_restore(self.site, dbpasswd)
            self.site.nginx_enable()
        else:
            self.post_restore()
        signals.emit("backups", "post_restore", self)
        backup["is_ready"] = True
        msg = "{0} restored successfully.".format(backup["pid"])
        nthread.complete(Notification("info", "Backup", msg))
        return backup
Example #37
0
 def _delete(self, job, id):
     nthread = NotificationThread(id=job.id)
     site = websites.get(id)
     site.remove(nthread)
     remove_record("website", id)
     remove_record("policy", id)
Example #38
0
def _request_acme_certificate(domain, webroot, nthread):
    nthread.title = "Requesting ACME certificate"
    signals.emit("certificates", "pre_add", id)
    domains = [domain]

    uid = users.get_system("http").uid
    gid = groups.get_system("ssl-cert").gid

    if webroot:
        webroot = os.path.join(webroot, ".well-known", "acme-challenge")

    acme_dir = config.get("certificates", "acme_dir")
    cert_dir = os.path.join(acme_dir, "certs", domain)
    cert_path = os.path.join(cert_dir, "cert.pem")
    key_path = os.path.join(cert_dir, "privkey.pem")

    if not os.path.exists(cert_dir):
        os.makedirs(cert_dir)

    if not webroot:
        sites = websites.get()
        for x in sites:
            if x.port in [80, 443] and x.domain == domain:
                webroot = x.add_acme_challenge()
                break
        else:
            webroot = websites.create_acme_dummy(domain)

    smsg = "Requesting certificate from Let's Encrypt CA..."
    nthread.update(Notification("info", "Certificates", smsg))
    agree_to_tos = None
    has_written_files = False
    while True:
        try:
            leclient.issue_certificate(
                domains,
                acme_dir,
                acme_server=config.get("certificates", "acme_server"),
                certificate_file=cert_path,
                private_key_file=key_path,
                agree_to_tos_url=agree_to_tos)
            break
        except leclient.NeedToAgreeToTOS as e:
            agree_to_tos = e.url
            continue
        except leclient.NeedToTakeAction as e:
            if not has_written_files:
                if not os.path.exists(webroot):
                    os.makedirs(webroot)
                os.chown(webroot, uid, gid)
                for x in e.actions:
                    fn = os.path.join(webroot, x.file_name)
                    with open(fn, 'w') as f:
                        f.write(x.contents)
                    os.chown(fn, uid, gid)
                has_written_files = True
                continue
            else:
                raise errors.InvalidConfigError(
                    "Requesting a certificate failed - it doesn't appear your "
                    "requested domain's DNS is pointing to your server, or "
                    "there was a port problem. Please check these things and "
                    "try again.")
        except leclient.WaitABit as e:
            while e.until_when > datetime.datetime.now():
                until = e.until_when - datetime.datetime.now()
                until_secs = int(round(until.total_seconds())) + 1
                if until_secs > 300:
                    raise errors.InvalidConfigError(
                        "Requesting a certificate failed - LE rate limiting "
                        "detected, for a period of more than five minutes. "
                        "Please try again later."
                    )
                nthread.update(
                    Notification(
                        "warning", "Certificates", "LE rate limiting detected."
                        " Will reattempt in {0} seconds".format(until_secs))
                    )
                time.sleep(until_secs)
            continue
        except leclient.InvalidDomainName:
            raise errors.InvalidConfigError(
                "Requesting a certificate failed - invalid domain name"
            )
        except leclient.RateLimited:
            raise errors.InvalidConfigError(
                "Requesting a certificate failed - LE is refusing to issue "
                "more certificates to you for this domain. Please choose "
                "another domain or try again another time."
            )

    os.chown(cert_path, -1, gid)
    os.chown(key_path, -1, gid)
    os.chmod(cert_path, 0o750)
    os.chmod(key_path, 0o750)

    with open(cert_path, "rb") as f:
        cert = x509.load_pem_x509_certificate(f.read(), default_backend())
    with open(key_path, "rb") as f:
        key = serialization.load_pem_private_key(
            f.read(), password=None, backend=default_backend()
        )
    sha1 = binascii.hexlify(cert.fingerprint(hashes.SHA1())).decode()
    md5 = binascii.hexlify(cert.fingerprint(hashes.MD5())).decode()
    sha1 = ":".join([sha1[i:i+2].upper() for i in range(0, len(sha1), 2)])
    md5 = ":".join([md5[i:i+2].upper() for i in range(0, len(md5), 2)])
    if isinstance(key.public_key(), rsa.RSAPublicKey):
        ktype = "RSA"
    elif isinstance(key.public_key(), dsa.DSAPublicKey):
        ktype = "DSA"
    elif isinstance(key.public_key(), ec.EllipticCurvePublicKey):
        ktype = "EC"
    else:
        ktype = "Unknown"
    ksize = key.key_size
    c = Certificate(domain, domain, cert_path, key_path, ktype, ksize,
                    [], cert.not_valid_after, sha1, md5, is_acme=True)
    storage.certificates[c.id] = c

    with open("/etc/cron.d/arkos-acme-renew", "a") as f:
        f.write("0 4 * * * systemctl reload nginx\n")
        fln = ("30 3 * * * free_tls_certificate {0} {1} {2} {3} {4} "
               ">> /var/log/acme-renew.log\n")
        f.write(fln.format(
            " ".join(domains), key_path, cert_path,
            webroot.split("/.well-known/acme-challenge")[0], acme_dir
        ))

    signals.emit("certificates", "post_add", c)
    msg = "Certificate issued successfully"
    nthread.complete(Notification("success", "Certificates", msg))
    return c