Introduce autorotating secrets for security

Change-Id: I25a4c44841e13ee1d151c87cdaaeedc5ab704765
diff --git a/.gitignore b/.gitignore
index 90ca657..84cb25a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
 /cache
-/kalamar.secret
+/kalamar.secret*
 /start-test
 /todo.org
 /fixtures.txt
diff --git a/Changes b/Changes
index 85fa8b5..e348e74 100755
--- a/Changes
+++ b/Changes
@@ -18,9 +18,16 @@
         - List tokens of a client.
         - Upgrade Mojolicious dependency to 9.19.
         - Added query reference API.
+        - Use AutoSecrets plugin to improve security.
 
         WARNING: Upgrading to Mojolicious 9.19 will
           invalidate all sessions. This is a security update.
+        
+        WARNING: Even testing this distribution will rewrite your
+          kalamar.secret file to migrate to kalamar.secret.json.
+          It will keep kalamar.secret - but you'll advise to
+          delete the file after checking the integrity with
+          kalamar.secret.json.
 
 0.41 2021-03-01
         - Introduce CORS headers to the proxy.
diff --git a/Makefile.PL b/Makefile.PL
index 40de23c..2ed9908 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -25,6 +25,7 @@
     'Mojolicious::Plugin::Util::RandomString' => 0.09,
     'Mojolicious::Plugin::CHI' => 0.20,
     'Mojolicious::Plugin::ClientIP' => 0.02,
+    'Mojolicious::Plugin::AutoSecrets' => 0.006,
     'Cache::FastMmap' => 1.56,
     'Data::Serializer' => 0.65,
     'Mojo::JWT' => 0.09,
diff --git a/README.md b/README.md
index 04ff442..5cfa713 100644
--- a/README.md
+++ b/README.md
@@ -153,9 +153,10 @@
 
 ### Secret file
 
-Kalamar uses [rotating secrets](https://mojolicious.org/perldoc/Mojolicious#secrets)
-to sign cookies. Put a file called `kalamar.secret` in the root of the application
-with one secret per line.
+Kalamar uses auto rotating secrets. Allow access to a file called
+`kalamar.secret.json` in the home directory of kalamar. It will
+automatically be created, if it doesn't exist.
+(`kalamar.secret` is deprecated.)
 
 ### Localization
 
diff --git a/lib/Kalamar.pm b/lib/Kalamar.pm
index a4893ad..4f619a6 100644
--- a/lib/Kalamar.pm
+++ b/lib/Kalamar.pm
@@ -3,12 +3,12 @@
 use Mojo::ByteStream 'b';
 use Mojo::URL;
 use Mojo::File;
-use Mojo::JSON 'decode_json';
+use Mojo::JSON qw/decode_json encode_json/;
 use Mojo::Util qw/url_escape deprecated slugify/;
 use List::Util 'none';
 
 # Minor version - may be patched from package.json
-our $VERSION = '0.41';
+our $VERSION = '0.42';
 
 # Supported version of Backend API
 our $API_VERSION = '1.0';
@@ -38,19 +38,41 @@
   push(@{$self->plugins->namespaces}, __PACKAGE__ . '::Plugin');
 
   # Set secrets for signed cookies
-  if (-e (my $secret = $self->home->child('kalamar.secret'))) {
+  my $secret_file = $self->home->rel_file('kalamar.secret.json');
+
+  # Support old secrets file
+  # This is deprecated 2021-03-05
+  if (-e (my $old_secret = $self->home->child('kalamar.secret'))) {
 
     # Load file and split lines for multiple secrets
-    $self->secrets([b($secret->slurp)->split("\n")]);
+    my $secrets = [b($old_secret->slurp)->split("\n")];
+    $self->secrets($secrets);
+
+    eval {
+      $secret_file->spurt(encode_json(@$secrets));
+      $secret_file->chmod(0600);
+      if (-w $secret_file) {
+        $self->log->warn(
+          "Please delete $old_secret file " .
+            "- $secret_file was created instead"
+          );
+      }
+    };
+    if ($@) {
+      $self->log->error("Please make $secret_file accessible");
+    };
   }
 
   # File not found ...
   # Kalamar needs secrets in a file to be easily deployable
   # and publishable at the same time.
   else {
-    $self->log->warn('Please create a kalamar.secret file');
+    $self->plugin(AutoSecrets => {
+      path => $secret_file
+    });
   };
 
+
   # Configuration framework
   $self->plugin('Config');
 
diff --git a/t/base.t b/t/base.t
new file mode 100644
index 0000000..f7f2e53
--- /dev/null
+++ b/t/base.t
@@ -0,0 +1,17 @@
+use Mojo::Base -strict;
+use Test::More;
+use Test::Mojo;
+use Mojo::JSON qw'decode_json';
+
+my $t = Test::Mojo->new('Kalamar');
+
+ok(my $file = $t->app->home->rel_file('kalamar.secret.json'));
+ok(-e $file, 'File exists');
+
+my $secrets = decode_json($file->slurp);
+ok(@$secrets >= 1);
+ok(length $secrets->[0] >= 5);
+
+ok($file->lstat->mode & 0600);
+
+done_testing;