Beispiel #1
0
    def run(cls, command, args, settings, options):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)
        mount_point = cmdline['<mount_point>']
        archive = cmdline['--archive']
        date = cmdline['--date']
        mount_all = cmdline['--all']
        include_external_archives = cmdline['--include-external']

        # get the desired archive
        if not archive:
            if date:
                archive = get_name_of_nearest_archive(settings, date)
            elif not mount_all:
                archive = get_name_of_latest_archive(settings)

        # create mount point if it does not exist
        try:
            mkdir(mount_point)
        except OSError as e:
            raise Error(os_error(e))

        # run borg
        borg = settings.run_borg(
            cmd='mount',
            args=[settings.destination(archive), mount_point],
            emborg_opts=options,
            strip_prefix=include_external_archives,
        )
        out = borg.stdout
        if out:
            output(out.rstrip())
Beispiel #2
0
def test_wring():
    with messenger() as (msg, stdout, stderr, logfile):
        output('hey now!', flush=True)
        codicil('baby', 'bird', sep='\n')
        msg.flush_logfile()
        expected = dedent('''
            hey now!
            baby
            bird
        ''').strip()

        assert msg.errors_accrued() == 0
        assert errors_accrued() == 0
        assert strip(stdout) == expected
        assert strip(stderr) == ''
        assert log_strip(logfile) == dedent('''
            ack: invoked as: <exe>
            ack: invoked on: <date>
            {expected}
        ''').strip().format(expected=expected)

        try:
            terminate_if_errors()
            assert True
        except SystemExit:
            assert False
Beispiel #3
0
    def run(cls, command, args, settings, options):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)
        archive = cmdline["<archive>"]
        check_all = cmdline["--all"]
        include_external_archives = cmdline["--include-external"]
        verify = ["--verify-data"] if cmdline["--verify-data"] else []
        repair = ['--repair'] if cmdline['--repair'] else []
        if repair:
            require_env_var('BORG_CHECK_I_KNOW_WHAT_I_AM_DOING', repair,
                            command, args)

        # identify archive or archives to check
        if check_all:
            archive = None
        elif not archive:
            archive = get_name_of_latest_archive(settings)

        # run borg
        borg = settings.run_borg(
            cmd="check",
            args=verify + repair + [settings.destination(archive)],
            emborg_opts=options,
            strip_prefix=include_external_archives,
        )
        out = borg.stdout
        if out:
            output(out.rstrip())
Beispiel #4
0
def list_plugins(config):
    # Work out the width of each column:
    stages = 'archive', 'publish', 'auth'
    defaults = {'auth': ['getpass']}
    max_on = 2
    max_type = max(len(x) for x in stages)
    max_name = max(len(k) for stage in stages for k in load_plugins(stage))
    max_width = get_terminal_size().columns - 1
    max_desc = max_width - max_on - max_type - max_name - 3 * 2

    row = "{:%ds}  {:%ds}  {:%ds}  {:%ds}" % (max_on, max_type, max_name,
                                              max_desc)
    header = row.format("On", "Stage", "Name", "Description")
    rule = '─' * max_width

    output(rule)
    output(header)
    output(rule)

    for stage in stages:
        installed = load_plugins(stage).values()
        enabled = select_plugins(config, stage, defaults.get(stage))
        plugins = enabled + [x for x in installed if x not in enabled]

        for i, plugin in enumerate(plugins):
            summary = (plugin.__doc__ or "No summary").strip().split('\n')[0]
            output(
                row.format(
                    '*' if plugin in enabled else '',
                    stage if i == 0 else '',
                    plugin.name,
                    shorten(summary, width=max_desc, placeholder='...'),
                ))

        output(rule)
Beispiel #5
0
def main():
    try:
        # read config file
        read_config()

        # read command line
        cmdline = docopt(
            __doc__.format(commands=Command.summarize()),
            version='avendesora {} ({})'.format(__version__, __released__),
            options_first=True,
        )

        # start logging
        logfile = BufferedFile(get_setting('log_file'), True)
        Inform(logfile=logfile,
               hanging_indent=False,
               stream_policy='header',
               notify_if_no_tty=True)
        shlib.set_prefs(use_inform=True, log_cmd=True)

        # run the requested command
        Command.execute(cmdline['<command>'], cmdline['<args>'])
        done()
    except KeyboardInterrupt:
        output('\nTerminated by user.')
        terminate()
    except (PasswordError, Error) as e:
        e.terminate()
    except OSError as e:
        fatal(os_error(e))
    done()
Beispiel #6
0
    def run(cls, command, args):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)

        # output the version
        from .__init__ import __version__
        output('Avendesora version: %s' % __version__)
Beispiel #7
0
    def run(cls, command, args, settings, options):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)
        archive = cmdline['<archive>']
        check_all = cmdline['--all']
        verify = ['--verify-data'] if cmdline['--verify-data'] else []
        # repair = ['--repair'] if cmdline['--repair'] else []
        repair = []
        # repair has been deleted because it requires the user to
        # interactively respond to a query, and emborg does not support that
        # yet.
        include_external_archives = cmdline['--include-external']

        # identify archive or archives to check
        if check_all:
            archive = None
        elif not archive:
            archive = get_name_of_latest_archive(settings)

        # run borg
        borg = settings.run_borg(
            cmd='check',
            args=verify + repair + [settings.destination(archive)],
            emborg_opts=options,
            strip_prefix=include_external_archives,
        )
        out = borg.stdout
        if out:
            output(out.rstrip())
Beispiel #8
0
    def run(cls, command, args, settings, options):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)
        paths = cmdline['<path>']
        archive = cmdline['--archive']
        date = cmdline['--date']

        # add cwd to paths
        paths = [to_path(cwd(), p) for p in paths]

        # assure that paths correspond to src_dirs
        src_dirs = settings.src_dirs
        unknown_path = False
        # get the desired archive
        if date and not archive:
            archive = get_name_of_nearest_archive(settings, date)
        if not archive:
            archive = get_name_of_latest_archive(settings)
        output('Archive:', archive)

        # run borg
        borg = settings.run_borg(
            cmd='extract',
            args=[settings.destination(archive)] + paths,
            emborg_opts=options,
        )
        out = borg.stdout
        if out:
            output(out.rstrip())
Beispiel #9
0
    def run(cls, command, args, settings, options):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)
        include_external_archives = cmdline["--include-external"]
        show_stats = cmdline["--stats"] or settings.show_stats

        # checking the settings
        intervals = "within last minutely hourly daily weekly monthly yearly"
        prune_settings = [("keep_" + s) for s in intervals.split()]
        if not any(settings.value(s) for s in prune_settings):
            prune_settings = conjoin(prune_settings, ", or ")
            raise Error(
                "No prune settings available",
                codicil=f"At least one of {prune_settings} must be specified.",
            )

        # run borg
        borg = settings.run_borg(
            cmd="prune",
            args=[settings.destination()],
            emborg_opts=options,
            strip_prefix=include_external_archives,
            show_borg_output=show_stats,
        )
        out = borg.stdout
        if out:
            output(out.rstrip())
Beispiel #10
0
    def run(cls, command, args, settings, options):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)
        mount_point = cmdline['<mount_point>']
        archive = cmdline['--archive']
        date = cmdline['--date']

        # get the desired archive
        if date and not archive:
            archive = get_nearest_archive(settings, date)
            if not archive:
                raise Error('archive not available.', culprit=date)

        # create mount point if it does not exist
        try:
            mkdir(mount_point)
        except OSError as e:
            raise Error(os_error(e))

        # run borg
        borg = settings.run_borg(
            cmd='mount',
            args=[settings.destination(archive), mount_point],
            emborg_opts=options,
        )
        out = borg.stdout
        if out:
            output(out.rstrip())
Beispiel #11
0
    def run(cls, command, args, settings, options):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)
        archive = cmdline['--archive']
        date = cmdline['--date']
        filenames_only = cmdline['--name']

        # get the desired archive
        if date and not archive:
            archive = get_nearest_archive(settings, date)
            if not archive:
                raise Error('archive not available.', culprit=date)
        if not archive:
            archives = get_available_archives(settings)
            if not archives:
                raise Error('no archives are available.')
            archive = archives[-1]['name']
        output('Archive:', archive)

        # run borg
        list_opts = ['--short'] if filenames_only else []
        borg = settings.run_borg(
            cmd='list',
            args=list_opts + [settings.destination(archive)],
            emborg_opts=options,
        )
        out = borg.stdout
        if out:
            output(out.rstrip())
Beispiel #12
0
    def generate(self, field_name, field_key, account):
        try:
            if self.secret:
                return
        except AttributeError:
            pass
        account_name = account.get_name()
        account_seed = account.get_seed()
        if self.master is None:
            master = account.get_field("master", default=None)
            master_source = account.get_field("_master_source", default=None)
        else:
            master = self.master
            master_source = "secret"
        if not master:
            master = get_setting("user_key")
            master_source = "user_key"
        if not master:
            try:
                try:
                    master = getpass.getpass("master password for %s: " % account_name)
                    master_source = "user"
                except EOFError:
                    output()
                if not master:
                    warn("master password is empty.")
            except (EOFError, KeyboardInterrupt):
                terminate()
        log("Generating secret, source of master seed:", master_source)
        field_key = self.get_key(field_key)
        if self.version:
            version = self.version
        else:
            version = account.get_field("version", default="")

        if account.request_seed():
            try:
                try:
                    interactive_seed = getpass.getpass("seed for %s: " % account_name)
                except EOFError:
                    output()
                if not interactive_seed:
                    warn("seed is empty.")
            except (EOFError, KeyboardInterrupt):
                terminate()
        else:
            interactive_seed = ""

        seeds = [master, account_seed, field_name, field_key, version, interactive_seed]
        key = " ".join([str(seed) for seed in seeds])

        # Convert the key into 512 bit number
        digest = hashlib.sha512((key).encode("utf-8")).digest()
        bits_per_byte = 8
        radix = 1 << bits_per_byte
        bits = 0
        for byte in digest:
            bits = radix * bits + byte
        self.pool = bits
Beispiel #13
0
def query_user(msg):
    highlight_color = get_setting('_highlight_color')
    msg = highlight_color(msg)

    try:
        return input(msg + ' ').strip()
    except EOFError:
        output()
Beispiel #14
0
    def help(cls, desc):
        if desc:
            output(desc.strip() + "\n")

        output("Available commands:")
        output(Command.summarize())

        output("\nAvailable topics:")
        output(cls.summarize())
Beispiel #15
0
def query_user(msg):
    msg = HighlightColor(msg)
    try:
        if sys.version_info.major < 3:
            return raw_input(msg + ' ').strip()
        else:
            return input(msg + ' ').strip()
    except EOFError:
        output()
Beispiel #16
0
    def help(cls, desc):
        if desc:
            output(desc.strip() + '\n')

        output('Available commands:')
        output(Command.summarize())

        output('\nAvailable topics:')
        output(cls.summarize())
Beispiel #17
0
    def run(cls, command, args, settings, options):
        # read command line
        docopt(cls.USAGE, argv=[command] + args)

        configurations = Collection(settings.configurations)
        if configurations:
            output('Available Configurations:', *configurations, sep='\n    ')
        else:
            output('No configurations available.')
Beispiel #18
0
    def run(cls, command, args, settings, options):
        # read command line
        docopt(cls.USAGE, argv=[command] + args)

        try:
            prev_log = settings.prev_logfile.read_text()
            output(prev_log)
        except FileNotFoundError as e:
            narrate(os_error(e))
Beispiel #19
0
    def run(cls, command, args, settings, options):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)
        highlight = Color('yellow')
        normal = Color('cyan')

        for k, v in settings:
            key = f'{k:>22s}'
            key = normal(key) if k in KNOWN_SETTINGS else highlight(key)
            output(f'{key}: {render(v, level=6)}')
Beispiel #20
0
    def run(cls, command, args, settings, options):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args, options_first=True)
        borg_args = cmdline['<borg_args>']

        # run borg
        borg = settings.run_borg_raw(borg_args)
        out = borg.stdout
        if out:
            output(out.rstrip())
Beispiel #21
0
    def write_summary(cls, all=False, sort=False):
        # present all account values that are not explicitly secret to the user
        label_color = get_setting('_label_color')
        highlight_color = get_setting('_highlight_color')

        def fmt_field(name, value='', key=None, level=0):
            hl = False

            # resolve values
            if isinstance(value, Script):
                hl = True
                value = value.script
            elif cls.is_secret(name, key):
                reveal = "reveal with: {}".format(
                    highlight_color(
                        join('avendesora', 'value', cls.get_name(),
                             cls.combine_field(name, key))))
                value = ', '.join(cull([value.get_description(), reveal]))
            elif isinstance(value, (GeneratedSecret, ObscuredSecret)):
                v = cls.get_scalar(name, key)
                value = ', '.join(cull([value.get_description(), str(v)]))
            else:
                value = str(value)

            # format values
            if '\n' in value:
                value = indent(dedent(value),
                               get_setting('indent')).strip('\n')
                sep = '\n'
            elif value:
                sep = ' '
            else:
                sep = ''
            if hl:
                value = highlight_color(value)
            name = str(name).replace('_', ' ')
            leader = level * get_setting('indent')
            return indent(
                label_color((name if key is None else str(key)) + ':') + sep +
                value, leader)

        # preload list with the names associated with this account
        names = [cls.get_name()] + getattr(cls, 'aliases', [])
        lines = [fmt_field('names', ', '.join(names))]

        for key, value in cls.items(all=all, sort=sort):
            if is_collection(value):
                lines.append(fmt_field(key))
                for k, v in Collection(value).items():
                    lines.append(fmt_field(key, v, k, level=1))
            else:
                lines.append(fmt_field(key, value))

        output(*lines, sep='\n')
Beispiel #22
0
def pager(text):
    program = get_setting('use_pager')
    if not is_str(program):
        program = os.environ.get('PAGER', 'less')
    if program:
        try:
            Run([program], stdin=text, modes='WoEs')
            return
        except Error as e:
            e.report(culprit=program)
    output(text)
Beispiel #23
0
    def run(cls, command, args):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)

        # get the text
        text = cmdline['<text>']
        if not text:
            output('Enter the obscured text, type ctrl-d to terminate.')
            text = sys.stdin.read()

        # transform and output the string
        output(Obscure.show(text))
Beispiel #24
0
    def run(cls, command, args):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)

        # get the text
        text = cmdline['<text>']
        symmetric = cmdline['--symmetric']
        if not text:
            output('Enter text to obscure, type ctrl-d to terminate.')
            text = sys.stdin.read()[:-1]

        # transform and output the string
        output(Obscure.hide(text, cmdline['--encoding'], True, symmetric))
Beispiel #25
0
    def run(cls, command, args, settings, options):
        # read command line
        docopt(cls.USAGE, argv=[command] + args)

        # run borg
        borg = settings.run_borg(
            cmd='init',
            args=[settings.destination()],
            emborg_opts=options,
        )
        out = borg.stdout
        if out:
            output(out.rstrip())
Beispiel #26
0
    def run(cls, command, args, settings, options):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)
        archive = cmdline['<archive>']

        # run borg
        borg = settings.run_borg(
            cmd='delete',
            args=[settings.destination(archive)],
            emborg_opts=options,
        )
        out = borg.stdout
        if out:
            output(out.rstrip())
Beispiel #27
0
    def display_field(self, account, field):
        # get string to display
        value, is_secret, name, desc = tuple(account.get_value(field))
        label = '%s (%s)' % (name, desc) if desc else name
        value = dedent(str(value)).strip()
        label_color = get_setting('_label_color')

        # indent multiline outputs
        sep = ' '
        if '\n' in value:
            if is_secret:
                warn('secret contains newlines, will not be fully concealed.')
            value = indent(value, get_setting('indent')).strip('\n')
            sep = '\n'

        if label:
            if label[0] == '_':
                # hidden field
                label = '!' + label[1:]
            text = label_color(label.replace('_', ' ') + ':') + sep + value
        else:
            text = value
            label = field
        log('Writing to TTY:', label)

        if is_secret:
            if Color.isTTY():
                # Write only if output is a TTY. This is a security feature.
                # The ideas is that when the TTY writer is called it is because
                # the user is expecting the output to go to the tty. This
                # eliminates the chance that the output can be intercepted and
                # recorded by replacing Avendesora with an alias or shell
                # script. If the user really want the output to go to something
                # other than the TTY, the user should use the --stdout option.
                try:
                    cursor.write(text)
                    cursor.conceal()
                    sleep(get_setting('display_time'))
                except KeyboardInterrupt:
                    pass
                cursor.reveal()
                cursor.clear()
            else:
                error('output is not a TTY.')
                codicil(
                    'Use --stdout option if you want to send secret',
                    'to a file or a pipe.'
                )
        else:
            output(text)
Beispiel #28
0
    def run(cls, command, args, settings, options):

        # get the Python version
        python = "Python %s.%s.%s" % (
            sys.version_info.major,
            sys.version_info.minor,
            sys.version_info.micro,
        )

        # output the SSHconfig version along with the Python version
        from .__init__ import __version__, __released__

        output("sshconfig version: %s (%s) [%s]." %
               (__version__, __released__, python))
Beispiel #29
0
    def run(cls, command, args, settings, options):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)
        verify = ['--verify-data'] if cmdline['--verify-data'] else []

        # run borg
        borg = settings.run_borg(
            cmd='check',
            args=verify + [settings.destination()],
            emborg_opts=options,
        )
        out = borg.stdout
        if out:
            output(out.rstrip())
Beispiel #30
0
    def run_script(self, script, dryrun=False):
        out = []
        scrubbed = []
        sleep(INITIAL_AUTOTYPE_DELAY)
        ms_per_char = None
        for cmd, val in script.components(True):
            if cmd in ['tab', 'return', 'text', 'value']:
                out.append(val)
                scrubbed.append(val)
            elif cmd.startswith('sleep '):
                scrubbed.append('<%s>' % cmd)
                try:
                    kw, seconds = cmd.split()
                    assert kw == 'sleep'
                    if out:
                        # drain the buffer before sleeping
                        if not dryrun:
                            self._autotype(''.join(out), ms_per_char)
                        out = []
                    sleep(float(seconds))
                except (TypeError, ValueError):
                    raise PasswordError('syntax error in keyboard script.',
                                        culprit=cmd)
            elif cmd.startswith('rate '):
                scrubbed.append('<%s>' % cmd)
                try:
                    kw, rate = cmd.split()
                    assert kw == 'rate'
                    if out:
                        # drain the buffer before changing rate
                        if not dryrun:
                            self._autotype(''.join(out), ms_per_char)
                        out = []
                    ms_per_char = int(rate)
                except (TypeError, ValueError):
                    raise PasswordError('syntax error in keyboard script.',
                                        culprit=cmd)
            elif cmd.startswith('remind '):
                notify(cmd[7:])
            else:
                out.append(val)
                scrubbed.append('<%s>' % cmd)

        scrubbed = ''.join(scrubbed).replace('\t', '→').replace('\n', '↲')
        log('Autotyping "%s"%s.' % (scrubbed, ' -- dry run' if dryrun else ''))
        if dryrun:
            output(script.account.get_name(), scrubbed, sep=': ')
        else:
            self._autotype(''.join(out), ms_per_char)
Beispiel #31
0
    def run(cls, command, args, settings, options):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)

        # get the Python version
        python = 'Python %s.%s.%s' % (
            sys.version_info.major,
            sys.version_info.minor,
            sys.version_info.micro,
        )

        # output the Avendesora version along with the Python version
        from .__init__ import __version__, __released__
        output('embalm version: %s (%s) [%s].' %
               (__version__, __released__, python))
Beispiel #32
0
    def run(cls, command, args):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)

        # run the generator
        generator = PasswordGenerator()

        # search for accounts that match search criteria
        to_print = []
        for acct in generator.search_accounts(cmdline['<text>']):
            aliases = ', '.join(Collection(getattr(acct, 'aliases', [])).values())
            aliases = ' (%s)' % (aliases) if aliases else ''
            to_print += [acct.get_name() + aliases]
        output(cmdline['<text>']+ ':')
        output('    ' + ('\n    '.join(sorted(to_print))))
Beispiel #33
0
    def run(cls, command, args, settings, options):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)
        archive1 = cmdline["<archive1>"]
        archive2 = cmdline["<archive2>"]

        # run borg
        borg = settings.run_borg(
            cmd="diff",
            args=[settings.destination(archive1), archive2],
            emborg_opts=options,
        )
        out = borg.stdout
        if out:
            output(out.rstrip())
Beispiel #34
0
    def run(cls, command, args, settings, options):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)
        include_external_archives = cmdline['--include-external']

        # run borg
        borg = settings.run_borg(
            cmd='list',
            args=['--short', settings.destination()],
            emborg_opts=options,
            strip_prefix=include_external_archives,
        )
        out = borg.stdout
        if out:
            output(out.rstrip())
Beispiel #35
0
    def get_seed(cls):
        # need to handle case where stdin/stdout is not available.
        # perhaps write generic password getter that supports both gui and tui.
        # Then have global option that indicates which should be used.
        # Separate name from seed. Only request seed when generating a password.
        import getpass

        try:
            name = getpass.getpass("account name: ")
        except EOFError:
            output()
            name = ""
        if not name:
            warn("null account name.")
        return name
Beispiel #36
0
    def run(cls, command, args, settings, options):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)
        paths = cmdline['<path>']
        archive = cmdline['--archive']
        date = cmdline['--date']

        # make sure source directories are given as absolute paths
        for src_dir in settings.src_dirs:
            if not src_dir.is_absolute():
                raise Error('restore command cannot be used',
                            'with relative source directories',
                            culprit=src_dir)

        # convert to absolute resolved paths
        paths = [to_path(p).resolve() for p in paths]

        # assure that paths correspond to src_dirs
        src_dirs = settings.src_dirs
        unknown_path = False
        for path in paths:
            if not any([str(path).startswith(str(sd)) for sd in src_dirs]):
                unknown_path = True
                warn('unknown path.', culprit=path)
        if unknown_path:
            codicil('Paths should start with:', conjoin(src_dirs,
                                                        conj=', or '))

        # remove leading / from paths
        paths = [str(p).lstrip('/') for p in paths]

        # get the desired archive
        if date and not archive:
            archive = get_name_of_nearest_archive(settings, date)
        if not archive:
            archive = get_name_of_latest_archive(settings)
        output('Archive:', archive)

        # run borg
        cd('/')
        borg = settings.run_borg(
            cmd='extract',
            args=[settings.destination(archive)] + paths,
            emborg_opts=options,
        )
        out = borg.stdout
        if out:
            output(out.rstrip())
Beispiel #37
0
    def write_summary(cls):
        # present all account values that are not explicitly secret to the user

        def fmt_field(key, value="", level=0):
            if "\n" in value:
                value = indent(dedent(value), get_setting("indent")).strip("\n")
                sep = "\n"
            elif value:
                sep = " "
            else:
                sep = ""
            key = str(key).replace("_", " ")
            leader = level * get_setting("indent")
            return indent(LabelColor(key + ":") + sep + value, leader)

        def reveal(name, key=None):
            return "<reveal with 'avendesora value %s %s'>" % (cls.get_name(), cls.combine_name(name, key))

        def extract_collection(name, collection):
            lines = [fmt_field(key)]
            for k, v in Collection(collection).items():
                if hasattr(v, "generate"):
                    # is a secret, get description if available
                    try:
                        v = "%s %s" % (v.get_key(), reveal(name, k))
                    except AttributeError:
                        v = reveal(name, k)
                lines.append(fmt_field(k, v, level=1))
            return lines

        # preload list with the names associated with this account
        names = [cls.get_name()]
        if hasattr(cls, "aliases"):
            names += Collection(cls.aliases)
        lines = [fmt_field("names", ", ".join(names))]

        for key, value in cls.items():
            if key in TOOL_FIELDS:
                pass  # is an Avendesora field
            elif is_collection(value):
                lines += extract_collection(key, value)
            elif hasattr(value, "generate"):
                lines.append(fmt_field(key, reveal(key)))
            else:
                lines.append(fmt_field(key, value))
        output(*lines, sep="\n")
Beispiel #38
0
    def display_field(self, account, field):
        name, key = account.split_name(field)
        is_secret = account.is_secret(name, key)
        try:
            value = account.get_field(name, key)
            tvalue = dedent(str(value)).strip()
        except Error as err:
            err.terminate()
        sep = ' '
        if '\n' in tvalue:
            if is_secret:
                warn(
                    'secret contains newlines, will not be fully concealed.',
                    culprit=key
                )
            else:
                tvalue = indent(dedent(tvalue), get_setting('indent')).strip('\n')
                sep = '\n'

        # build output string
        label = account.combine_name(name, key)
        log('Writing to TTY:', label)
        try:
            alt_name = value.get_key()
            if alt_name:
                label += ' (%s)' % alt_name
        except AttributeError:
            pass
        text = LabelColor(label + ':') + sep + tvalue

        if is_secret:
            try:
                cursor.write(text)
                cursor.conceal()
                sleep(get_setting('display_time'))
            except KeyboardInterrupt:
                pass
            cursor.reveal()
            cursor.clear()
        else:
            output(text)
Beispiel #39
0
def main():
    # read config file
    read_config()

    # read command line
    cmdline = docopt(
        __doc__.format(commands=Command.summarize()),
        options_first=True
    )

    # start logging
    logfile = BufferedFile(get_setting('log_file'), True)
    with Inform(logfile=logfile, hanging_indent=False):
        try:
            Command.execute(cmdline['<command>'], cmdline['<args>'])
        except KeyboardInterrupt:
            output('Terminated by user.')
        except Error as err:
            err.terminate()
        except OSError as err:
            fatal(os_error(err))

        terminate()
Beispiel #40
0
    def help(cls):
        output('Available commands:')
        output(Command.summarize())

        output('\nAvailable topics:')
        output(cls.summarize())
Beispiel #41
0
    def run(cls, command, args):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)

        # read archive file
        archive_path = get_setting('archive_file')
        f = PythonFile(archive_path)
        archive = f.run()
        import arrow
        created = archive.get('CREATED')
        if created:
            created = arrow.get(created).format('YYYY-MM-DD hh:mm:ss A ZZ')
            output('archive created: %s' % created)
        archive_accounts = archive.get('ACCOUNTS')
        if not archive_accounts:
            raise Error(
                'corrupt archive, ACCOUNTS missing.', culprit=archive_path
            )

        # run the generator
        generator = PasswordGenerator()

        # determine the account and open the URL
        current_accounts = {}
        for account in generator.all_accounts:
            entry = account.archive()
            if entry:
                current_accounts[account.get_name()] = entry

        # report any new or missing accounts
        new = current_accounts.keys() - archive_accounts.keys()
        missing = archive_accounts.keys() - current_accounts.keys()
        for each in sorted(new):
            output('new account:', each)
        for each in sorted(missing):
            output('missing account:', each)

        # for the common accounts, report any differences in the fields
        common = archive_accounts.keys() & current_accounts.keys()
        for account_name in sorted(common):
            archive_account = archive_accounts[account_name]
            current_account = current_accounts[account_name]

            # report any new or missing fields
            new = current_account.keys() - archive_account.keys()
            missing = archive_account.keys() - current_account.keys()
            for each in sorted(new):
                output(account_name, 'new field', each, sep=': ')
            for each in sorted(missing):
                output(account_name, 'new field', each, sep=': ')

            # for the common fields, report any differences in the values
            shared = archive_account.keys() & current_account.keys()
            for field_name in sorted(shared):
                try:
                    archive_value = archive_account[field_name]
                    current_value = current_account[field_name]
                    if is_collection(current_value) != is_collection(archive_value):
                        output(account_name, 'field dimension differs', field_name, sep=': ')
                    elif is_collection(current_value):
                        archive_items = Collection(archive_account[field_name]).items()
                        current_items = Collection(current_account[field_name]).items()
                        archive_keys = set(k for k, v in archive_items)
                        current_keys = set(k for k, v in current_items)
                        new = current_keys - archive_keys
                        missing = archive_keys - current_keys
                        for each in sorted(new):
                            output(account_name, field_name, 'new member', each, sep=': ')
                        for each in sorted(missing):
                            output(account_name, field_name, 'missing member', each, sep=': ')
                        for k in sorted(archive_keys & current_keys):
                            if str(archive_value[k]) != str(current_value[k]):
                                output(account_name, 'member differs', '%s[%s]' % (field_name, k), sep=': ')
                    else:
                        if dedent(str(archive_value)) != dedent(str(current_value)):
                            output(account_name, 'field differs', field_name, sep=': ')
                except Exception:
                    error(
                        'unanticipated situation.',
                        culprit=(account_name, field_name)
                    )
                    raise
Beispiel #42
0
    def run(cls, command, args):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)

        try:
            # get the specified template
            templates = get_setting('account_templates')
            if cmdline['<template>']:
                template_name = cmdline['<template>']
            else:
                template_name = get_setting('default_account_template')
            template = dedent(templates[template_name]).strip() + '\n'

            # save template to tmp file and open it in the editor
            from tempfile import mktemp
            tmpfile = GnuPG(mktemp(suffix='_avendesora.gpg'))
            tmpfile.save(template, get_setting('gpg_ids'))
            GenericEditor.open_and_search(tmpfile.path)

            # read the tmp file and determine if it has changed
            new = tmpfile.read()
            tmpfile.remove()
            if new == template:
                return output('Unchanged, and so ignored.')

            # hide the values that should be hidden
            def hide(match):
                return 'Hidden(%r)' % Obscure.hide(match.group(1))
            new = re.sub("<<(.*?)>>", hide, new)

            # determine the accounts file
            prefix = cmdline['--file']
            if prefix:
                candidates = [
                    p
                    for p in get_setting('accounts_files')
                    if p.startswith(prefix)
                ]
                if not candidates:
                    raise Error('not found.', cuplrit=cmdline['--file'])
                if len(candidates) > 1:
                    raise Error(
                        'ambiguous, matches %s.' % conjoin(candidates),
                        cuplrit=prefix
                    )
                filename = candidates[0]
            else:
                filename = get_setting('accounts_files')[0]
            path = to_path(get_setting('settings_dir'), filename)

            # get original contents of accounts file
            orig_accounts_file = PythonFile(path)
            accounts = orig_accounts_file.run()
            gpg_ids = accounts.get('gpg_ids')

            # add new account to the contents
            accounts = orig_accounts_file.code + new + '\n'

            # rename the original file and then save the new version
            orig_accounts_file.rename('.saved')
            new_accounts_file = GnuPG(path)
            new_accounts_file.save(accounts, gpg_ids)
        except OSError as err:
            error(os_error(err))
        except KeyError as err:
            error(
                'unknown account template, choose from %s.' % conjoin(
                    sorted(templates.keys())
                ), culprit=template_name
            )