#!/usr/bin/perl -w

# This script downloads a torbrowser or mullvadbrowser release, checking
# its signature

use strict;
use English;
use LWP::Simple;
use File::Temp;
use File::Basename qw(fileparse);
use FindBin;
use File::Path qw(make_path);
use File::Copy;
use Path::Tiny;
use Digest::SHA qw(sha256_hex);


sub exit_error {
  print STDERR "Error: ", $_[0], "\n";
  chdir '/';
  exit (exists $_[1] ? $_[1] : 1);
}

sub gpg_verify_file {
  my ($file) = @_;
  if (system('gpg', '--no-default-keyring', '--keyring',
      "$FindBin::Bin/../keyring/torbrowser.gpg", '--verify',
      "$file.asc",
      $file)) {
    exit_error "Error checking gpg signature for file $file";
  }
}

my $progname = fileparse($PROGRAM_NAME);
my ($projectname) = $progname =~ m/^download-(.+)$/;
if (@ARGV != 1) {
  print STDERR "usage: $progname <version>\n";
  exit 1;
}

my $version = $ARGV[0];
my $version_type = $version =~ m/a/ ? 'alpha' : 'release';
my $destdir = "$FindBin::Bin/../$projectname/$version_type/signed/$version";
my $urldir = "https://archive.torproject.org/tor-package-archive/$projectname/$version";

make_path($destdir);
my $tmpdir = File::Temp->newdir(DIR => "$FindBin::Bin/../tmp");

foreach my $file (qw(sha256sums-signed-build.txt sha256sums-signed-build.txt.asc
                     sha256sums-unsigned-build.txt sha256sums-unsigned-build.txt.asc)) {
  if (getstore("$urldir/$file", "$tmpdir/$file") != 200) {
    exit_error "Error downloading $urldir/$file";
  }
}
gpg_verify_file("$tmpdir/sha256sums-signed-build.txt");
move "$tmpdir/sha256sums-signed-build.txt.asc", "$destdir/sha256sums-signed-build.txt.asc";
move "$tmpdir/sha256sums-signed-build.txt", "$destdir/sha256sums-signed-build.txt";
gpg_verify_file("$tmpdir/sha256sums-unsigned-build.txt");
move "$tmpdir/sha256sums-unsigned-build.txt.asc", "$destdir/sha256sums-unsigned-build.txt.asc";
move "$tmpdir/sha256sums-unsigned-build.txt", "$destdir/sha256sums-unsigned-build.txt";

foreach my $file (qw(sha256sums-signed-build.incrementals.txt
                     sha256sums-signed-build.incrementals.txt.asc
                     sha256sums-unsigned-build.incrementals.txt
                     sha256sums-unsigned-build.incrementals.txt.asc)) {
  if (getstore("$urldir/$file", "$tmpdir/$file") != 200) {
    last;
  }
}
if (-f "$tmpdir/sha256sums-signed-build.incrementals.txt.asc") {
  gpg_verify_file("$tmpdir/sha256sums-signed-build.incrementals.txt");
  move "$tmpdir/sha256sums-signed-build.incrementals.txt.asc", "$destdir/sha256sums-signed-build.incrementals.txt.asc";
  move "$tmpdir/sha256sums-signed-build.incrementals.txt", "$destdir/sha256sums-signed-build.incrementals.txt";
}
if (-f "$tmpdir/sha256sums-unsigned-build.incrementals.txt.asc") {
  gpg_verify_file("$tmpdir/sha256sums-unsigned-build.incrementals.txt");
  move "$tmpdir/sha256sums-unsigned-build.incrementals.txt.asc", "$destdir/sha256sums-unsigned-build.incrementals.txt.asc";
  move "$tmpdir/sha256sums-unsigned-build.incrementals.txt", "$destdir/sha256sums-unsigned-build.incrementals.txt";
}

my @sha256_lines = path("$destdir/sha256sums-signed-build.txt")->lines;
push @sha256_lines, path("$destdir/sha256sums-signed-build.incrementals.txt")->lines
    if -f "$destdir/sha256sums-signed-build.incrementals.txt";
my %sums = map { chomp; reverse split '  ', $_ } @sha256_lines;

foreach my $file (sort keys %sums) {
  if (-f "$destdir/$file") {
    print "Not downloading $file (already there)\n";
    next;
  }
  print "Downloading $file\n";
  exit_error "Error downloading $urldir/$file\n"
    unless getstore("$urldir/$file", "$tmpdir/$file") == 200;
  exit_error "Wrong checksum for $file"
    unless $sums{$file} eq sha256_hex(path("$tmpdir/$file")->slurp);
  move "$tmpdir/$file", "$destdir/$file";
}

print "Finished downloading $projectname $version in $destdir\n";
