Ejemplo n.º 1
0
def backup_database():
    """
    Backups entire database contents to a YAML file which is encrypted using the password
    from a specified mapped password in the database.
    """
    try:
        dir_mode = int(config.get("backups.dir_mode", "0700"), 8)
        file_mode = int(config.get("backups.file_mode", "0600"), 8)

        # Before we do anything, validate the configuration.
        if not os.path.exists(config["backups.path"]):
            # Attempt to make the directories.
            os.makedirs(config["backups.path"], mode=dir_mode)

        if not config.get("backups.encryption.password_id"):
            raise exc.ConfigurationError(
                "Cannot backup without configured password_id (backups.encryption.password_id)"
            )

        try:
            pw = passwords.get(config["backups.encryption.password_id"])
        except exc.NoSuchEntity as x:
            raise exc.ConfigurationError(
                "Configured backups.encryption.password_id does not exist in database: {0}".format(x)
            )

        backup_fname = datetime.now().strftime("backup-%Y-%m-%d-%H-%M.gpg")

        msg = "Backing up database to {fname}, secured by password id={pw.id}, resource={resource.name}[{resource.id}]"
        log.info(msg.format(fname=backup_fname, pw=pw, resource=pw.resource))

        exporter = GpgYamlExporter(passphrase=pw.password_decrypted, use_tags=True, include_key_metadata=True)

        encrypted_stream = BytesIO()
        exporter.export(stream=encrypted_stream)
        encrypted_stream.seek(0)  # Just to ensure it's rewound

        backup_file = os.path.join(config["backups.path"], backup_fname)
        with open(backup_file, "w") as fp:
            fp.write(encrypted_stream.read())

        os.chmod(backup_file, file_mode)
    except:
        log.critical("Error backing up database.", exc_info=True)
        raise
Ejemplo n.º 2
0
 def export(self, group_id=None, **kwargs):
     form = ExportForm(request_params(), group_id=group_id)
     form.group_id.choices = [(g.id, g.name) for g in groups.list()]
     
     exporter_choices = [('yaml', 'YAML (GPG/PGP-encrypted)')]
     if config['export.keepass.enabled']:
         if not os.path.exists(config['export.keepass.exe_path']):
             log.error("KeePass export enabled, but specified converter script does not exist: {0}".format(config.get('export.keepass.exe_path')))
         else:
             exporter_choices.append(('kdb', 'KeePass 1.x'))
     form.format.choices = exporter_choices
     
     if cherrypy.request.method == 'POST':
         if form.validate():
             group = groups.get(form.group_id.data)
             
             if form.format.data == 'yaml':
                 exporter = GpgYamlExporter(use_tags=False,
                                            passphrase=form.passphrase.data,
                                            resource_filters=[model.GroupResource.group_id==group.id]) # @UndefinedVariable
                 encrypted_stream = BytesIO()
                 exporter.export(stream=encrypted_stream)
                 encrypted_stream.seek(0) # Just to ensure it's rewound
                 
                 return serve_fileobj(encrypted_stream, content_type='application/pgp-encrypted', disposition='attachment',
                                      name='group-{0}-export.pgp'.format(re.sub('[^\w\-\.]', '_', group.name)))
                 
             elif form.format.data == 'kdb':
                 exporter = KeepassExporter(passphrase=form.passphrase.data,
                                            resource_filters=[model.GroupResource.group_id==group.id]) # @UndefinedVariable
                 encrypted_stream = BytesIO()
                 exporter.export(stream=encrypted_stream)
                 encrypted_stream.seek(0) # Just to ensure it's rewound
                 
                 return serve_fileobj(encrypted_stream, content_type='application/x-keepass-database', disposition='attachment',
                                      name='group-{0}-export.kdb'.format(re.sub('[^\w\-\.]', '_', group.name)))
                     
             else:
                 # I don't think we can get here in normal business.
                 raise RuntimeError("Unhandled format specified: {0}".format(form.format.data))
                 
         else: # does not validate
             return render("group/export.html", {'form': form})
     else: # request method is GET
         return render("group/export.html", {'form': form})
Ejemplo n.º 3
0
def export_data(options):
    """
    Interactive target to export GPG-encrypted YAML file(s) for specified group(s).
    """
    try:
        dirpath = options.export_data.dir
    except AttributeError:
        dirpath = None
    
    try:
        singlefile = options.export_data.file
    except AttributeError:
        singlefile = None
    
    if dirpath is None and singlefile is None:
        raise BuildFailure('One of --dir/-d or --file/-f is required.')
    elif dirpath is not None and singlefile is not None:
        raise BuildFailure('The --dir/-d or --file/-f are mutually exclusive')
    
    try:
        grouplist = options.export_data.groups
    except AttributeError:
        grouplist = None
        
    try:
        groupfile = options.export_data.groupfile
    except AttributeError:
        groupfile = None
    
    if groupfile is None and grouplist is None:
        raise BuildFailure("One of --groupfile/-G or --groups/-g options must be specified.")
    elif groupfile is not None and grouplist is not None:
        raise BuildFailure("The --groupfile/-G and --groups/-g options are mutually exclusive.")
    
    # First read in the groups by either comma-separating the list or by
    if grouplist: 
        group_names = re.split(r'\s*,\s*', grouplist)
    else:
        with open(groupfile, 'r') as fp:
            group_names = [l.strip() for l in fp if l.strip() != '' and not l.strip().startswith('#')]
            
    # Check these against the database.  Fail fast.
    groups = [groups_dao.get_by_name(gn, assert_exists=True) for gn in group_names]
    
    passphrase = raw_input("GPG Passphrase for export file(s): ")
    
    if singlefile:
        group_ids = [g.id for g in groups]
        print "Exporting groups {0!r} to file: {1}".format(group_names, singlefile)
        exporter = GpgYamlExporter(use_tags=False, passphrase=passphrase,
                                   resource_filters=[model.GroupResource.group_id.in_(group_ids)]) # @UndefinedVariable
        with open(singlefile, 'w') as output_file:
            exporter.export(stream=output_file)
    else:
        # Iterate over the groups.  Export file per group.
        for g in groups:
            exporter = GpgYamlExporter(use_tags=False, passphrase=passphrase,
                                       resource_filters=[model.GroupResource.group_id==g.id]) # @UndefinedVariable
            fn='group-{0}-export.pgp'.format(re.sub('[^\w\-\.]', '_', g.name))
            print "Exporting group '{0}' to file: {1}".format(g.name, fn)
            with open(os.path.join(dirpath, fn), 'w') as output_file:
                exporter.export(stream=output_file)