#!/usr/bin/perl

=head1 NAME

parcimonie - privacy-friendly helper to refresh a GnuPG keyring

=head1 VERSION

Version 0.12.0

=head1 SYNOPSIS

B<parcimonie> [options]

=head1 DESCRIPTION

parcimonie is a daemon that slowly refreshes a GnuPG public keyring
from a keyserver.

Its refreshes one key at a time; between every key update, parcimonie
sleeps a random amount of time, long enough for the previously used Tor
circuit to expire.

This process is meant to make it hard for an attacker to correlate the
multiple performed key update operations.

See the design.md document to learn more about the threat and risk
models parcimonie attempts to help coping with.

=head1 USAGE

1. Configure GnuPG to be able to use a keyserver with Tor.

If you already have configured a keyserver and you run Tor
0.3.0.3-alpha-1 or newer from Debian, then parcimonie will probably
work fine and you can skip this step. Otherwise, you will probably
need to replace your keyserver with the one documented below, or to
enable IPv6 traffic in your Tor client (by enabling the IPv6Traffic
flag for your SocksPort).

Add to ~/.gnupg/dirmngr.conf something like:

        keyserver hkp://jirk5u4osbsr34t5.onion

2. Run "parcimonie --verbose".

3. Check the output for misconfiguration or bugs.

4. Once happy, start the daemon without the --verbose option.
   Note: the Debian package automatically starts the daemon with your X session.

=head1 OPTIONS

The following command lists available options:

    parcimonie --help

=head2 Tor configuration vs. --minimum-lapse-time

In case you set the Tor MaxCircuitDirtiness setting yourself, you
probably want to pass parcimonie a matching --minimum-lapse-time
option so that subsequent key fetches use different Tor circuits.

Just make sure this remains true:

        minimum-lapse-time >= Tor MaxCircuitDirtiness

=head2 hkpms://

We recommend using hkpms; see http://web.monkeysphere.info/ for
details. When a hkpms:// keyserver is being used, one needs to do two
additional steps since gpgkeys_hkpms does not work in the torsocks
wrapped environment parcimonie uses by default to run gpg.

=head3 Torify gpgkeys_hkpms

Just add the following line to gpg.conf:

    keyserver-options http-proxy=socks://127.0.0.1:9050

=head3 Hey, parcimonie, gpg is already torified

Pass the --gnupg-already-torified switch to the parcimonie daemon
command-line. parcimonie will then rely on the keyserver-options
previously added to gpg.conf, and won't attempt to torify gpg
connections itself.

=head1 AUTHOR

intrigeri <intrigeri@boum.org>

=head1 COPYRIGHT

Copyright (C) 2010-2020 intrigeri <intrigeri@boum.org>

=head1 LICENSE

Licensed under the same terms as Perl itself.

=head1 BUGS

Please report any bugs or feature requests to
L<https://salsa.debian.org/intrigeri/parcimonie/-/issues>.

=head1 SUPPORT

You can find documentation for parcimonie with the man command.

    man parcimonie


You can also look for information at:

=over 4

=item * parcimonie's homepage

L<https://salsa.debian.org/intrigeri/parcimonie>

=back

=cut

use strict;
use warnings;

our $VERSION = '0.12.0';

use FindBin;
use lib "$FindBin::Bin/../lib";

use Env qw{@PATH};
unshift @PATH, "$FindBin::Bin";

use 5.10.0;

use Carp;
use Try::Tiny;

my $mu;
sub record_memory_usage { 1 }
sub report_memory_usage { 1 }

my @options;

BEGIN {
    if (exists $ENV{REPORT_MEMORY_USAGE}
            && defined $ENV{REPORT_MEMORY_USAGE}
            && $ENV{REPORT_MEMORY_USAGE}) {
        try {
            require Memory::Usage;
        } catch {
            croak "Memory::Usage is needed when REPORT_MEMORY_USAGE is set."
        };
        $mu = Memory::Usage->new();
        no warnings 'redefine';
        *record_memory_usage = sub { $mu->record(shift) };
        *report_memory_usage = sub { $mu->dump() };
        push @options, ('memory_usage' => $mu);
    }
}

$SIG{'INT'}  = $SIG{'TERM'} = sub { report_memory_usage(); exit(0); };
$SIG{'USR1'} = sub { report_memory_usage(); };

record_memory_usage('starting work');
record_memory_usage('before loading App::Parcimonie');
require App::Parcimonie;
App::Parcimonie->import();
record_memory_usage('after loading App::Parcimonie');

record_memory_usage('before loading App::Parcimonie::Daemon');
require App::Parcimonie::Daemon;
App::Parcimonie::Daemon->import();
record_memory_usage('after loading App::Parcimonie::Daemon');

App::Parcimonie::Daemon->new_with_options(@options)->run;

report_memory_usage();
