HTML-OSM
view release on metacpan or search on metacpan
t/edge_cases.t view on Meta::CPAN
dies_ok { $m->add_geojson('{invalid json}') }
'add_geojson("{invalid json}") dies';
};
subtest 'add_geojson: circular reference in data dies in onload_render' => sub {
# encode_json will die when it encounters a cycle; the module does not
# pre-validate GeoJSON structure.
my $m = HTML::OSM->new();
$m->center([$C{LAT_LONDON}, $C{LON_LONDON}]);
my %circ;
$circ{self} = \%circ;
$m->add_geojson(\%circ);
dies_ok { $m->onload_render() }
'circular-reference GeoJSON dies in onload_render (encode_json rejects cycle)';
};
subtest 'add_geojson: return value is always 1' => sub {
my $m = HTML::OSM->new();
returns_ok(
$m->add_geojson({ type => 'FeatureCollection', features => [] }),
{ type => 'integer' }, 'returns integer');
is($m->add_geojson({ type => 'FeatureCollection', features => [] }), 1,
'return value is 1');
};
# ââ Security: </script> injection via encode_json ââââââââââââââââââââââââââ
# encode_json does NOT escape forward slashes by default, so embedding its
# output raw in a <script> block allows an attacker to close the block early.
# The module must escape </ â <\/ in all JSON output destined for <script>.
subtest 'security: GeoJSON style with </script> is escaped in rendered output' => sub {
my $m = HTML::OSM->new();
$m->center([$C{LAT_LONDON}, $C{LON_LONDON}]);
$m->add_geojson(
{ type => 'FeatureCollection', features => [] },
style => { color => $C{SCRIPT_CLOSE} },
);
my (undef, $body) = $m->onload_render();
unlike($body, qr|</script><script>|,
'raw </script><script> absent from rendered body (style injection blocked)');
diag("style segment: " . substr($body, index($body, 'style:'), 120))
if $ENV{TEST_VERBOSE};
};
subtest 'security: GeoJSON feature property with </script> is escaped in rendered output' => sub {
my $m = HTML::OSM->new();
$m->center([$C{LAT_LONDON}, $C{LON_LONDON}]);
$m->add_geojson({
type => 'FeatureCollection',
features => [{
type => 'Feature',
properties => { name => $C{SCRIPT_CLOSE} },
geometry => { type => 'Point', coordinates => [0, 0] },
}],
});
my (undef, $body) = $m->onload_render();
unlike($body, qr|</script><script>|,
'raw </script><script> absent when feature property contains injection');
};
subtest 'security: GeoJSON popup property name with </script> is escaped' => sub {
my $m = HTML::OSM->new();
$m->center([$C{LAT_LONDON}, $C{LON_LONDON}]);
# The popup property name goes through _js_string â test that the data
# path (the whole GeoJSON blob) is also safe.
$m->add_geojson(
{ type => 'FeatureCollection', features => [] },
popup => 'name',
style => { fillOpacity => 0.5 },
);
my (undef, $body) = $m->onload_render();
unlike($body, qr|</script><script>|,
'rendered output does not contain script-close injection');
};
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
# 6. add_heatmap() â hostile inputs and XSS via points JSON
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
subtest 'add_heatmap: undef points croaks' => sub {
my $m = HTML::OSM->new();
throws_ok { $m->add_heatmap(undef) }
qr/add_heatmap: points must be an arrayref/,
'add_heatmap(undef) croaks';
};
subtest 'add_heatmap: hashref points croaks' => sub {
my $m = HTML::OSM->new();
throws_ok { $m->add_heatmap({}) }
qr/add_heatmap: points must be an arrayref/,
'add_heatmap({}) croaks';
};
subtest 'add_heatmap: scalar string croaks' => sub {
my $m = HTML::OSM->new();
throws_ok { $m->add_heatmap('string') }
qr/add_heatmap: points must be an arrayref/,
'add_heatmap("string") croaks';
};
subtest 'add_heatmap: empty arrayref is accepted (renders empty layer)' => sub {
my $m = HTML::OSM->new();
is($m->add_heatmap([]), 1, 'empty arrayref â 1');
$m->center([$C{LAT_LONDON}, $C{LON_LONDON}]);
my (undef, $body) = $m->onload_render();
like($body, qr/L\.heatLayer\(\[\]/, 'empty heatmap rendered as L.heatLayer([])');
};
subtest 'security: heatmap points with </script> in intensity escaped in output' => sub {
# Intensity is a string â encode_json would normally embed it raw.
my $m = HTML::OSM->new();
$m->add_marker([$C{LAT_LONDON}, $C{LON_LONDON}]);
$m->add_heatmap([[$C{LAT_LONDON}, $C{LON_LONDON}, $C{SCRIPT_CLOSE}]]);
my (undef, $body) = $m->onload_render();
unlike($body, qr|</script><script>|,
'raw </script><script> absent when heatmap intensity contains injection');
};
subtest 'add_heatmap: return value is 1' => sub {
my $m = HTML::OSM->new();
returns_ok($m->add_heatmap([[51.5, -0.1]]), { type => 'integer' }, 'returns integer');
is($m->add_heatmap([[51.5, -0.1]]), 1, 'returns 1');
};
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
# 7. add_gpx() â hostile inputs
# âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
( run in 0.757 second using v1.01-cache-2.11-cpan-364913b4093 )