Disable CSP for development purposes

Change-Id: Iff20edb302f9f03e524b7bd8bcb4ce3a9690d3be
diff --git a/Changes b/Changes
index 4b16d51..b7bcfac 100755
--- a/Changes
+++ b/Changes
@@ -1,4 +1,4 @@
-0.43 2021-10-13
+0.43 2021-10-28
         - New menu class that has an entry at the very end,
           similar to the input text prefix,
           that is always available. (lerepp)
@@ -36,6 +36,8 @@
         - Turn "upgradeTo" into an object prototype.
         - Fix QueryParam response to work with Chrome (#149).
         - Added DemoServer plugin.
+        - Support CSP disabling.
+        - Update intro.js (#109; hebasta)
 
 0.42 2021-06-18
         - Added GitHub based CI for perl.
diff --git a/lib/Kalamar/Plugin/CSP.pm b/lib/Kalamar/Plugin/CSP.pm
index c9768aa..59c6c58 100644
--- a/lib/Kalamar/Plugin/CSP.pm
+++ b/lib/Kalamar/Plugin/CSP.pm
@@ -16,6 +16,11 @@
   };
 
   my $with_nonce = delete $param->{-with_nonce};
+  my $disabled   = delete $param->{-disable};
+
+  if ($disabled) {
+    $app->log->warn('CSP DISABLED!','NEVER USE IN PRODUCTION!');
+  };
 
   $app->plugin('Util::RandomString' => {
     nonce => {
@@ -44,19 +49,21 @@
   my $csp = \( generate(%directives) );
 
   # Add csp header
-  $app->hook(
-    before_dispatch => sub {
-      my $c = shift;
-      if ($$csp) {
-        my $line = $$csp;
-        if ($with_nonce) {
-          $c->stash('csp.nonce' => my $nonce = $c->random_string('nonce'));
-          $line =~ s/\'nonce-\{\{nonce_js\}\}\'/\'nonce-$nonce\'/;
+  unless ($disabled) {
+    $app->hook(
+      before_dispatch => sub {
+        my $c = shift;
+        if ($$csp) {
+          my $line = $$csp;
+          if ($with_nonce) {
+            $c->stash('csp.nonce' => my $nonce = $c->random_string('nonce'));
+            $line =~ s/\'nonce-\{\{nonce_js\}\}\'/\'nonce-$nonce\'/;
+          };
+          $c->res->headers->header('Content-Security-Policy' => $line);
         };
-        $c->res->headers->header('Content-Security-Policy' => $line);
-      };
-    }
-  );
+      }
+    );
+  };
 
   # Add csp directives
   $app->helper(
@@ -86,7 +93,7 @@
   $app->helper(
     csp_nonce_tag => sub {
       my $c = shift;
-      unless ($c->content_block_ok('nonce_js')) {
+      if ($disabled || !$c->content_block_ok('nonce_js')) {
         return '';
       };
 
@@ -120,3 +127,117 @@
 };
 
 1;
+
+
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+Kalamar::Plugin::CSP - Define CSP rules per config
+
+=head1 DESCRIPTION
+
+This Mojolicious plugin allows to define CSP directives in
+a configuration file and programmatically. It will add CSP to all
+responses using the C<before_dispatch> hook.
+
+
+=head2 register
+
+  # Mojolicious
+  $app->plugin('Kalamar::Plugin::CSP' => {
+    'script-src' => '*',
+    'img-src' => ['self', 'data:']
+  });
+
+  # Or in the config file
+  {
+    CSP => {
+      'script-src' => '*',
+      'img-src' => ['self', 'data:']
+    }
+  }
+
+Called when registering the plugin.
+
+All L<parameters|/PARAMETERS> can be set either as part of the configuration
+file with the key C<CSP> or on registration
+(that can be overwritten by configuration).
+
+
+=head1 PARAMETERS
+
+L<Kalamar::Plugin::CSP> supports all valid CSP directives as parameters.
+Multiple values can be defined as arrays.
+
+In addition, the following special parameters for
+the C<CSP> configuration section in the Kalamar configuration are supported.
+
+=over 2
+
+=item B<-disable>
+
+Disables all CSP. It's strongly recommended to not use this option
+in a production environment.
+
+=item B<-with_nonce>
+
+Adds I<nonce> support, i.e. inline-support, for JavaScript.
+Allows the use of the L</csp_nonce_tag>.
+
+=back
+
+All parameters can be set as part of the configuration
+file with the key C<CSP> or on registration
+(that can be overwritten by configuration).
+
+
+=head1 HELPERS
+
+=head2 csp_nonce_tag
+
+  # Configure inline JavaScript as a content block:
+  $mojo->content_block(
+    'nonce_js' => {
+      inline => 'console.log("Hallo")'
+    }
+  );
+
+  # Embed inline JavaScript in templates:
+  %= csp_nonce_tag
+
+The nonce tag allows to embed inline JavaScript despite CSP rules.
+It requires the C<-with_nonce> configuration flag.
+The inline JavaScript can be formulated as a
+L<Mojolicious::Plugin::TagHelpers::ContentBlock> with the block name
+C<nonce_js>.
+
+
+=head2 csp.add
+
+  # Mojolicious:
+  $app->csp->add('script-src', '*');
+
+Adds a CSP rule to the configuration. This is B<no> controller helper
+and should be used only before dispatch.
+
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2021, L<IDS Mannheim|http://www.ids-mannheim.de/>
+Author: L<Nils Diewald|https://www.nils-diewald.de/>
+
+Kalamar is developed as part of the L<KorAP|https://korap.ids-mannheim.de/>
+Corpus Analysis Platform at the
+L<Leibniz Institute for the German Language (IDS)|https://ids-mannheim.de/>,
+member of the
+L<Leibniz-Gemeinschaft|http://www.leibniz-gemeinschaft.de>.
+
+Kalamar is free software published under the
+L<BSD-2 License|https://raw.githubusercontent.com/KorAP/Kalamar/master/LICENSE>.
+
+=cut
diff --git a/t/plugin/csp.t b/t/plugin/csp.t
index 1031450..aa6cd70 100644
--- a/t/plugin/csp.t
+++ b/t/plugin/csp.t
@@ -149,6 +149,24 @@
 like($content, qr/nonce-\Q$1\E/);
 
 
+# Disable csp
+$t = Test::Mojo->new(Mojolicious::Lite->new);
+$t->app->plugin('Kalamar::Plugin::CSP' => {
+  '-disable' => 1
+});
+
+$t->app->routes->get('/' => sub {
+  shift->render(text => 'hello world');
+});
+
+$t->app->csp->add('script-src', '*');
+is($t->app->csp_nonce_tag,'');
+
+$t->get_ok('/')
+  ->status_is(200)
+  ->content_is('hello world')
+  ->header_is($csp, undef)
+  ;
 
 done_testing;
 __END__