App-MechaCPAN
view release on metacpan or search on metacpan
lib/App/MechaCPAN.pm view on Meta::CPAN
}
$idx++;
# Don't bother with fancy line movements if we are verbose
if ($VERBOSE)
{
print STDERR "$color$line$RESET\n";
return;
}
# We use some ANSI escape codes, so they are:
# \e[.F - Move up from current line, which is always the end of the list
# \e[K - Clear the line
# $color - Colorize the text
# $line - Print the text
# $RESET - Reset the colorize
# \e[.E - Move down from the current line, back to the end of the list
print STDERR "\e[${idx}F";
print STDERR "\e[K";
print STDERR "$color$line$RESET\n";
print STDERR "\e[" . ( $idx - 1 ) . "E"
lib/App/MechaCPAN.pm view on Meta::CPAN
my $tar = Archive::Tar->new;
$tar->error(1);
my $ret = $tar->read( "$src", 1, { extract => 1 } );
die $tar->error
unless $ret;
},
);
sub _path_escapes_dir
{
my $path = shift;
return 0
if !defined $path;
return 0
if !length $path;
return 1
if File::Spec->file_name_is_absolute($path);
lib/App/MechaCPAN.pm view on Meta::CPAN
for my $part ( File::Spec->splitdir($path) )
{
return 1
if $part eq '..';
}
return 0;
}
# Inspect a tar archive's header entries (no extraction). Returns a
# human-readable reason if any entry would escape the destination dir
# (absolute paths, '..' traversal in names, or symlink/hardlink targets
# pointing outside). Returns undef if the archive is safe.
sub _validate_archive_is_safe
{
my $src = shift;
require Archive::Tar;
# Create a tar iterator. The magic 1 tells it to decompress
my $iter = Archive::Tar->iter( "$src", 1 );
return "could not read archive: $src"
if !defined $iter;
while ( my $entry = $iter->() )
{
my $name = $entry->full_path;
return "unsafe entry name: '$name'"
if _path_escapes_dir($name);
if ( $entry->is_symlink || $entry->is_hardlink )
{
my $linkname = $entry->linkname;
return "unsafe link target: '$name' -> '$linkname'"
if _path_escapes_dir($linkname);
}
}
return;
}
sub inflate_archive
{
my $src = shift;
my $dir = shift;
lib/App/MechaCPAN/Install.pm view on Meta::CPAN
(?: authors/id/ )?
(?: \w / \w\w /)?
( \w{2,} )
/
( .+ )
$
]xms;
sub _escape
{
my $str = shift;
$str =~ s/ ([^A-Za-z0-9\-\._~]) / sprintf("%%%02X", ord($1)) /xmsge;
return $str;
}
my $ident_re = qr/^ \p{ID_Start} (?: :: | \p{ID_Continue} )* $/xms;
sub _src_normalize
{
lib/App/MechaCPAN/Install.pm view on Meta::CPAN
{
my $src = shift;
my $constraint = shift // '';
state %seen;
return $seen{$src}->{$constraint}
if exists $seen{$src}->{$constraint};
# TODO mirrors
my $dnld = 'https://fastapi.metacpan.org/download_url/' . _escape($src);
if ( $constraint )
{
$dnld .= '?version=' . _escape($constraint);
}
my $json_info = '';
fetch_file( $dnld => \$json_info );
my $result = JSON::PP::decode_json($json_info);
$seen{$src}->{$constraint} = $result;
return $result;
}
test_dists/build-ShadyTars.pl view on Meta::CPAN
$tar->add_data(@$file);
}
$tar->write( $path, COMPRESS_GZIP );
print "wrote $path\n";
}
# .. traversal in name
gen_tar 'traversal.tar.gz' => (
[
'../escape.txt' => 'traversal payload',
{ %attrs, type => FILE }
]
);
# absolute path
gen_tar 'absolute_path.tar.gz' => (
[
'/tmp/escape.txt' => 'absolute payload',
{ %attrs, type => FILE }
]
);
# absolute symlink destination
gen_tar 'symlink_absolute.tar.gz' => (
[
'link' => '',
{ %attrs, type => SYMLINK, linkname => '/tmp' }
],
test_dists/build-ShadyTars.pl view on Meta::CPAN
'hardlink' => '',
{ %attrs, type => HARDLINK, linkname => '/tmp/etc/passwd' }
]
);
# symlink write-through
# first entry creates a symlink pointing outside, then the second entry write
# through to a target file
gen_tar 'symlink_writethrough.tar.gz' => (
[
'escape' => '',
{ %attrs, type => SYMLINK, linkname => '/tmp' }
],
[
'escape/payload.txt' => 'wrote through symlink',
{ %attrs, type => FILE }
],
);
# benign control tar
my $mfpl = "use ExtUtils::MakeMaker;\nWriteMakefile(NAME => 'Foo');\n";
my $lib = "package Foo;\nour \$VERSION = '1.0';\n1;\n";
gen_tar 'benign.tar.gz' => (
[
'dist-1.0/Makefile.PL' => $mfpl,
( run in 1.221 second using v1.01-cache-2.11-cpan-364913b4093 )