From 14b6298d7781fe5697e39988d79a2887f42c629a Mon Sep 17 00:00:00 2001
From: Daniel Berteaud
Date: Mon, 29 Jun 2015 19:09:28 +0200
Subject: [PATCH] Automatically handle cookie signing keys Which will get
renewed every 24 hours. Remove the now useless cookie section of the config
---
conf/settings.ini.dist | 6 -----
docs/database/schema.mysql | 10 ++++++-
lib/Vroom/Conf.pm | 2 --
lib/Vroom/Constants.pm | 2 +-
scripts/db_upgrade.pl | 21 +++++++++++++++
templates/default/documentation.html.ep | 11 --------
vroom.pl | 48 +++++++++++++++++++++++++++++----
7 files changed, 74 insertions(+), 26 deletions(-)
diff --git a/conf/settings.ini.dist b/conf/settings.ini.dist
index 3f84e4e..34cee68 100644
--- a/conf/settings.ini.dist
+++ b/conf/settings.ini.dist
@@ -51,12 +51,6 @@ credentials = 'rest'
; Default to 0
;demo = 0
-[cookie]
-; Secret passphrase used to sign cookies. You must set this
-;secret = '1zEewX24ZD%2RvtF%e'
-; Cookie name, You shouldn't have to change this
-;name = 'vroom'
-
[rooms]
; After this amount of time in minutes, rooms without any activity will be purged
;inactivity_timeout = '60'
diff --git a/docs/database/schema.mysql b/docs/database/schema.mysql
index e103968..cbfc7b5 100644
--- a/docs/database/schema.mysql
+++ b/docs/database/schema.mysql
@@ -6,7 +6,15 @@ CREATE TABLE `config` (
UNIQUE (`key`)
) ENGINE INNODB DEFAULT CHARSET=utf8;
INSERT INTO `config` (`key`,`value`)
- VALUES ('schema_version', '6');
+ VALUES ('schema_version', '7');
+
+CREATE TABLE `session_keys` (
+ `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
+ `key` VARCHAR(160) NOT NULL,
+ `date` DATETIME NOT NULL DEFAULT 0,
+ PRIMARY KEY (`id`),
+ INDEX (`date`)
+) ENGINE INNODB DEFAULT CHARSET=utf8;
CREATE TABLE `rooms` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
diff --git a/lib/Vroom/Conf.pm b/lib/Vroom/Conf.pm
index a4b6e0a..d282692 100644
--- a/lib/Vroom/Conf.pm
+++ b/lib/Vroom/Conf.pm
@@ -32,8 +32,6 @@ sub get_conf(){
$config->{'interface.template'} ||= 'default';
$config->{'interface.chrome_extension_id'} ||= 'ecicdpoejfllflombfanbhfpgcimjddn';
$config->{'interface.chrome_extension_id'} ||= 0;
- $config->{'cookie.secret'} ||= 'secret';
- $config->{'cookie.name'} ||= 'vroom';
$config->{'rooms.inactivity_timeout'} ||= 60;
$config->{'rooms.reserved_inactivity_timeout'} ||= 86400;
$config->{'rooms.common_names'} ||= '';
diff --git a/lib/Vroom/Constants.pm b/lib/Vroom/Constants.pm
index 10c5cd2..a63b15d 100644
--- a/lib/Vroom/Constants.pm
+++ b/lib/Vroom/Constants.pm
@@ -7,7 +7,7 @@ use base 'Exporter';
our @EXPORT = qw/DB_VERSION COMPONENTS MOH JS_STRINGS API_ACTIONS/;
# Database version
-use constant DB_VERSION => 6;
+use constant DB_VERSION => 7;
# Components used to generate the credits part
use constant COMPONENTS => {
diff --git a/scripts/db_upgrade.pl b/scripts/db_upgrade.pl
index 4a3fd26..d647697 100644
--- a/scripts/db_upgrade.pl
+++ b/scripts/db_upgrade.pl
@@ -145,3 +145,24 @@ if ($cur_ver < 6){
print "Successfully upgraded to schema version 6\n";
}
+if ($cur_ver < 7){
+ print "Upgrading the schema to version 7\n";
+ eval {
+ $dbh->begin_work;
+ $dbh->do(qq{ CREATE TABLE `session_keys` (`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
+ `key` VARCHAR(160) NOT NULL,
+ `date` DATETIME NOT NULL DEFAULT 0,
+ PRIMARY KEY (`id`),
+ INDEX (`date`))
+ ENGINE INNODB DEFAULT CHARSET=utf8; });
+ $dbh->do(qq{ UPDATE `config` SET `value`='7' WHERE `key`='schema_version' });
+ $dbh->commit;
+ };
+ if ($@){
+ print "An error occurred: " . $dbh->errstr . "\n";
+ local $dbh->{RaiseError} = 0;
+ $dbh->rollback;
+ exit 255;
+ };
+ print "Successfully upgraded to schema version 7\n";
+}
diff --git a/templates/default/documentation.html.ep b/templates/default/documentation.html.ep
index 6f62c87..a7b489b 100644
--- a/templates/default/documentation.html.ep
+++ b/templates/default/documentation.html.ep
@@ -358,17 +358,6 @@ cp /opt/vroom/conf/settings.ini.dist /opt/vroom/conf/settings.ini
-
- cookie
-
-
- This section controls the cookie used for VROOM sessions. The available settings are
-
- - secret: A secret passphrase to sign cookies. Must be changed !!!
-
- name: The name of the cookie. Default is vroom
-
-
-
rooms
diff --git a/vroom.pl b/vroom.pl
index 1b737be..8663f43 100755
--- a/vroom.pl
+++ b/vroom.pl
@@ -143,6 +143,39 @@ helper check_db_version => sub {
return ($ver eq Vroom::Constants::DB_VERSION) ? '1' : '0';
};
+# Generate and manage rotation of session keys
+# used to sign cookies
+helper update_session_keys => sub {
+ my $self = shift;
+ # First, delete obsolete session keys
+ my $sth = eval {
+ $self->db->prepare('DELETE FROM `session_keys`
+ WHERE `date` < DATE_SUB(CONVERT_TZ(NOW(), @@session.time_zone, \'+00:00\'), INTERVAL 72 HOUR)');
+ };
+ $sth->execute;
+ # Now, retrieve all remaining keys, to check if we have enough of them
+ $sth = eval {
+ $self->db->prepare('SELECT `key` FROM `session_keys`
+ ORDER BY `date` DESC');
+ };
+ $sth->execute;
+ my $keys = $sth->fetchall_hashref('key');
+ my @keys = keys %$keys;
+ if (scalar @keys < 3){
+ $self->app->log->debug("Generating a new key to sign session cookies");
+ my $new_key = Session::Token->new(alphabet => ['a'..'z', 'A'..'Z', '0'..'9', '.:;,/!%$#~{([-_)]}=+*|'], entropy => 512)->get;
+ unshift @keys, $new_key;
+ $self->app->log->info("new key: $new_key");
+ $sth = eval {
+ $self->db->prepare('INSERT INTO `session_keys` (`key`,`date`)
+ VALUES (?,NOW())');
+ };
+ $sth->execute($new_key);
+ }
+ $self->app->secrets(\@keys);
+ return 1;
+};
+
# Return human readable username if it exists, or just the session ID
helper get_name => sub {
my $self = shift;
@@ -1231,6 +1264,11 @@ Mojo::IOLoop->recurring( 900 => sub {
app->purge_invitations;
});
+# Check every 24h if session keys needs updating
+Mojo::IOLoop->recurring( 86400 => sub {
+ app->update_session_keys;
+});
+
# Route / to the index page
get '/' => sub {
my $self = shift;
@@ -2070,10 +2108,12 @@ get '/:room' => sub {
# use the templates defined in the config
push @{app->renderer->paths}, 'templates/'.$config->{'interface.template'};
-# Set the secret used to sign cookies
-app->secrets([$config->{'cookie.secret'}]);
+
+app->update_session_keys;
+# Set log level
+app->log->level($config->{'daemon.log_level'});
app->sessions->secure(1);
-app->sessions->cookie_name($config->{'cookie.name'});
+app->sessions->cookie_name('vroom');
app->hook(before_dispatch => sub {
my $self = shift;
# Switch to the desired language
@@ -2109,8 +2149,6 @@ app->config(
}
);
-# Set log level
-app->log->level($config->{'daemon.log_level'});
app->log->info('Starting VROOM daemon');
# And start, lets VROOM !!
app->start;