aboutsummaryrefslogtreecommitdiff
path: root/t
diff options
context:
space:
mode:
authorSimon McVittie <smcv@debian.org>2019-02-10 16:30:07 +0000
committerSimon McVittie <smcv@debian.org>2019-02-26 21:44:07 +0000
commit67543ce1d62161fdef9dca198289d7dd7dceacc0 (patch)
treec38827ad186714a95d8cc27d2636a2fe031949ab /t
parente7b0d4a0fff8ed45a90c2efe8ef294bdf7c9bdac (diff)
downloadikiwiki-67543ce1d62161fdef9dca198289d7dd7dceacc0.tar
ikiwiki-67543ce1d62161fdef9dca198289d7dd7dceacc0.tar.gz
useragent: Don't allow non-HTTP protocols to be used
This prevents the aggregate plugin from being used to read the contents of local files via file:/// URLs. Signed-off-by: Simon McVittie <smcv@debian.org>
Diffstat (limited to 't')
-rwxr-xr-xt/aggregate-file.t173
-rw-r--r--t/noparanoia/LWPx/ParanoidAgent.pm2
-rw-r--r--t/secret.rss11
3 files changed, 186 insertions, 0 deletions
diff --git a/t/aggregate-file.t b/t/aggregate-file.t
new file mode 100755
index 000000000..f00743dac
--- /dev/null
+++ b/t/aggregate-file.t
@@ -0,0 +1,173 @@
+#!/usr/bin/perl
+use utf8;
+use warnings;
+use strict;
+
+use Encode;
+use Test::More;
+
+BEGIN {
+ plan(skip_all => "CGI not available")
+ unless eval q{
+ use CGI qw();
+ 1;
+ };
+
+ plan(skip_all => "IPC::Run not available")
+ unless eval q{
+ use IPC::Run qw(run);
+ 1;
+ };
+
+ use_ok('IkiWiki');
+ use_ok('YAML::XS');
+}
+
+# We check for English error messages
+$ENV{LC_ALL} = 'C';
+
+use Cwd qw(getcwd);
+use Errno qw(ENOENT);
+
+my $installed = $ENV{INSTALLED_TESTS};
+
+my @command;
+if ($installed) {
+ @command = qw(ikiwiki --plugin inline);
+}
+else {
+ ok(! system("make -s ikiwiki.out"));
+ @command = ("perl", "-I".getcwd."/blib/lib", './ikiwiki.out',
+ '--underlaydir='.getcwd.'/underlays/basewiki',
+ '--set', 'underlaydirbase='.getcwd.'/underlays',
+ '--templatedir='.getcwd.'/templates');
+}
+
+sub write_old_file {
+ my $name = shift;
+ my $dir = shift;
+ my $content = shift;
+ writefile($name, $dir, $content);
+ ok(utime(333333333, 333333333, "$dir/$name"));
+}
+
+sub write_setup_file {
+ my %params = @_;
+ my %setup = (
+ wikiname => 'this is the name of my wiki',
+ srcdir => getcwd.'/t/tmp/in',
+ destdir => getcwd.'/t/tmp/out',
+ url => 'http://example.com',
+ cgiurl => 'http://example.com/cgi-bin/ikiwiki.cgi',
+ cgi_wrapper => getcwd.'/t/tmp/ikiwiki.cgi',
+ cgi_wrappermode => '0751',
+ add_plugins => [qw(aggregate)],
+ disable_plugins => [qw(emailauth openid passwordauth)],
+ aggregate_webtrigger => 1,
+ );
+ if ($params{without_paranoia}) {
+ $setup{libdirs} = [getcwd.'/t/noparanoia'];
+ }
+ unless ($installed) {
+ $setup{ENV} = { 'PERL5LIB' => getcwd.'/blib/lib' };
+ }
+ writefile("test.setup", "t/tmp",
+ "# IkiWiki::Setup::Yaml - YAML formatted setup file\n" .
+ Dump(\%setup));
+}
+
+sub thoroughly_rebuild {
+ ok(unlink("t/tmp/ikiwiki.cgi") || $!{ENOENT});
+ ok(! system(@command, qw(--setup t/tmp/test.setup --rebuild --wrappers)));
+}
+
+sub run_cgi {
+ my (%args) = @_;
+ my ($in, $out);
+ my $method = $args{method} || 'GET';
+ my $environ = $args{environ} || {};
+ my $params = $args{params} || { do => 'prefs' };
+
+ my %defaults = (
+ SCRIPT_NAME => '/cgi-bin/ikiwiki.cgi',
+ HTTP_HOST => 'example.com',
+ );
+
+ my $cgi = CGI->new($args{params});
+ my $query_string = $cgi->query_string();
+ diag $query_string;
+
+ if ($method eq 'POST') {
+ $defaults{REQUEST_METHOD} = 'POST';
+ $in = $query_string;
+ $defaults{CONTENT_LENGTH} = length $in;
+ } else {
+ $defaults{REQUEST_METHOD} = 'GET';
+ $defaults{QUERY_STRING} = $query_string;
+ }
+
+ my %envvars = (
+ %defaults,
+ %$environ,
+ );
+ run(["./t/tmp/ikiwiki.cgi"], \$in, \$out, init => sub {
+ map {
+ $ENV{$_} = $envvars{$_}
+ } keys(%envvars);
+ });
+
+ return decode_utf8($out);
+}
+
+sub test {
+ my $content;
+
+ ok(! system(qw(rm -rf t/tmp)));
+ ok(! system(qw(mkdir t/tmp)));
+
+ write_old_file('aggregator.mdwn', 't/tmp/in',
+ '[[!aggregate name="ssrf" url="file://'.getcwd.'/t/secret.rss"]]'
+ .'[[!inline pages="internal(aggregator/*)"]]');
+
+ write_setup_file();
+ thoroughly_rebuild();
+
+ $content = run_cgi(
+ method => 'GET',
+ params => {
+ do => 'aggregate_webtrigger',
+ },
+ );
+ unlike($content, qr{creating new page});
+ unlike($content, qr{Secrets});
+ ok(! -e 't/tmp/in/.ikiwiki/transient/aggregator/ssrf');
+ ok(! -e 't/tmp/in/.ikiwiki/transient/aggregator/ssrf/Secrets_go_here._aggregated');
+
+ thoroughly_rebuild();
+ $content = readfile('t/tmp/out/aggregator/index.html');
+ unlike($content, qr{Secrets});
+
+ diag('Trying test again with LWPx::ParanoidAgent disabled');
+
+ write_setup_file(without_paranoia => 1);
+ thoroughly_rebuild();
+
+ $content = run_cgi(
+ method => 'GET',
+ params => {
+ do => 'aggregate_webtrigger',
+ },
+ );
+ unlike($content, qr{creating new page});
+ unlike($content, qr{Secrets});
+ ok(! -e 't/tmp/in/.ikiwiki/transient/aggregator/ssrf');
+ ok(! -e 't/tmp/in/.ikiwiki/transient/aggregator/ssrf/Secrets_go_here._aggregated');
+
+ thoroughly_rebuild();
+ $content = readfile('t/tmp/out/aggregator/index.html');
+ unlike($content, qr{Secrets});
+}
+
+test();
+
+done_testing();
diff --git a/t/noparanoia/LWPx/ParanoidAgent.pm b/t/noparanoia/LWPx/ParanoidAgent.pm
new file mode 100644
index 000000000..751e80ce6
--- /dev/null
+++ b/t/noparanoia/LWPx/ParanoidAgent.pm
@@ -0,0 +1,2 @@
+# make import fail
+0;
diff --git a/t/secret.rss b/t/secret.rss
new file mode 100644
index 000000000..11202e9ed
--- /dev/null
+++ b/t/secret.rss
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<rss version="2.0">
+<channel>
+<title>Secrets go here</title>
+<description>Secrets go here</description>
+<item>
+ <title>Secrets go here</title>
+ <description>Secrets go here</description>
+</item>
+</channel>
+</rss>