|
|
@ -4,7 +4,6 @@ |
|
|
|
# released under the MIT licence |
|
|
|
# released under the MIT licence |
|
|
|
# Copyright 2014 Firewall Services |
|
|
|
# Copyright 2014 Firewall Services |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use lib '../lib'; |
|
|
|
use lib '../lib'; |
|
|
|
use Mojolicious::Lite; |
|
|
|
use Mojolicious::Lite; |
|
|
|
use Mojolicious::Plugin::Mailer; |
|
|
|
use Mojolicious::Plugin::Mailer; |
|
|
@ -18,6 +17,7 @@ use Email::Sender::Transport::Sendmail; |
|
|
|
use Encode; |
|
|
|
use Encode; |
|
|
|
use File::stat; |
|
|
|
use File::stat; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# List The different components we rely on. |
|
|
|
# Used to generate thanks on the about template |
|
|
|
# Used to generate thanks on the about template |
|
|
|
our $components = { |
|
|
|
our $components = { |
|
|
|
"SimpleWebRTC" => { |
|
|
|
"SimpleWebRTC" => { |
|
|
@ -59,6 +59,7 @@ our $components = { |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
app->log->level('info'); |
|
|
|
app->log->level('info'); |
|
|
|
|
|
|
|
# Read conf file, and set default values |
|
|
|
our $config = plugin Config => { |
|
|
|
our $config = plugin Config => { |
|
|
|
file => '../conf/vroom.conf', |
|
|
|
file => '../conf/vroom.conf', |
|
|
|
default => { |
|
|
|
default => { |
|
|
@ -81,22 +82,25 @@ our $config = plugin Config => { |
|
|
|
|
|
|
|
|
|
|
|
app->log->level($config->{logLevel}); |
|
|
|
app->log->level($config->{logLevel}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Load I18N, and declare supported languages |
|
|
|
plugin I18N => { |
|
|
|
plugin I18N => { |
|
|
|
namespace => 'Vroom::I18N', |
|
|
|
namespace => 'Vroom::I18N', |
|
|
|
support_url_langs => [qw(en fr)] |
|
|
|
support_url_langs => [qw(en fr)] |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Load mailer plugin with its default values |
|
|
|
plugin Mailer => { |
|
|
|
plugin Mailer => { |
|
|
|
from => $config->{emailFrom}, |
|
|
|
from => $config->{emailFrom}, |
|
|
|
transport => Email::Sender::Transport::Sendmail->new({ sendmail => $config->{sendmail}}), |
|
|
|
transport => Email::Sender::Transport::Sendmail->new({ sendmail => $config->{sendmail}}), |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Wrapper arround DBI |
|
|
|
helper db => sub { |
|
|
|
helper db => sub { |
|
|
|
my $dbh = DBI->connect($config->{dbi}, $config->{dbUser}, $config->{dbPassword}) || die "Could not connect"; |
|
|
|
my $dbh = DBI->connect($config->{dbi}, $config->{dbUser}, $config->{dbPassword}) || die "Could not connect"; |
|
|
|
$dbh |
|
|
|
$dbh |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Create a cookie based session |
|
|
|
helper login => sub { |
|
|
|
helper login => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
return if $self->session('name'); |
|
|
|
return if $self->session('name'); |
|
|
@ -106,23 +110,29 @@ helper login => sub { |
|
|
|
$self->app->log->info($self->session('name') . " logged in from " . $self->tx->remote_address); |
|
|
|
$self->app->log->info($self->session('name') . " logged in from " . $self->tx->remote_address); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Expire the cookie |
|
|
|
helper logout => sub { |
|
|
|
helper logout => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
$self->session( expires => 1 ); |
|
|
|
$self->session( expires => 1 ); |
|
|
|
$self->app->log->info($self->session('name') . " logged out"); |
|
|
|
$self->app->log->info($self->session('name') . " logged out"); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Create a new room in the DB |
|
|
|
|
|
|
|
# Requires two args: the name of the room and the session name of the creator |
|
|
|
helper create_room => sub { |
|
|
|
helper create_room => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
my ($name,$owner) = @_; |
|
|
|
my ($name,$owner) = @_; |
|
|
|
|
|
|
|
# Exit if the name isn't valid or already taken |
|
|
|
return undef if ( $self->get_room($name) || !$self->valid_room_name($name)); |
|
|
|
return undef if ( $self->get_room($name) || !$self->valid_room_name($name)); |
|
|
|
my $sth = eval { $self->db->prepare("INSERT INTO rooms (name,create_timestamp,activity_timestamp,owner,token,realm) VALUES (?,?,?,?,?,?);") } || return undef; |
|
|
|
my $sth = eval { $self->db->prepare("INSERT INTO rooms (name,create_timestamp,activity_timestamp,owner,token,realm) VALUES (?,?,?,?,?,?);") } || return undef; |
|
|
|
|
|
|
|
# Gen a random token. Will be used as a turnPassword |
|
|
|
my $tp = join '' => map{('a'..'z','A'..'Z','0'..'9')[rand 62]} 0..49; |
|
|
|
my $tp = join '' => map{('a'..'z','A'..'Z','0'..'9')[rand 62]} 0..49; |
|
|
|
$sth->execute($name,time(),time(),$owner,$tp,$config->{realm}) || return undef; |
|
|
|
$sth->execute($name,time(),time(),$owner,$tp,$config->{realm}) || return undef; |
|
|
|
$self->app->log->info("room $name created by " . $self->session('name')); |
|
|
|
$self->app->log->info("room $name created by " . $self->session('name')); |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Read room param in the DB and return a perl hash |
|
|
|
helper get_room => sub { |
|
|
|
helper get_room => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
my ($name) = @_; |
|
|
|
my ($name) = @_; |
|
|
@ -131,6 +141,8 @@ helper get_room => sub { |
|
|
|
return $sth->fetchall_hashref('name')->{$name}; |
|
|
|
return $sth->fetchall_hashref('name')->{$name}; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Lock/unlock a room, to prevent new participants |
|
|
|
|
|
|
|
# Takes two arg: room name and 1 for lock, 0 for unlock |
|
|
|
helper lock_room => sub { |
|
|
|
helper lock_room => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
my ($name,$lock) = @_; |
|
|
|
my ($name,$lock) = @_; |
|
|
@ -143,6 +155,8 @@ helper lock_room => sub { |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Add a participant in the database. Used by the signaling server to check |
|
|
|
|
|
|
|
# if user is allowed |
|
|
|
helper add_participant => sub { |
|
|
|
helper add_participant => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
my ($name,$participant) = @_; |
|
|
|
my ($name,$participant) = @_; |
|
|
@ -153,6 +167,7 @@ helper add_participant => sub { |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Remove participant from the DB |
|
|
|
helper remove_participant => sub { |
|
|
|
helper remove_participant => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
my ($name,$participant) = @_; |
|
|
|
my ($name,$participant) = @_; |
|
|
@ -163,6 +178,7 @@ helper remove_participant => sub { |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Get a list of participants of a room |
|
|
|
helper get_participants => sub { |
|
|
|
helper get_participants => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
my ($name) = @_; |
|
|
|
my ($name) = @_; |
|
|
@ -176,6 +192,8 @@ helper get_participants => sub { |
|
|
|
return @res; |
|
|
|
return @res; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Check if a participant has joined a room |
|
|
|
|
|
|
|
# Takes two args: the session name, and the room name |
|
|
|
helper has_joined => sub { |
|
|
|
helper has_joined => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
my ($session,$name) = @_; |
|
|
|
my ($session,$name) = @_; |
|
|
@ -186,6 +204,7 @@ helper has_joined => sub { |
|
|
|
return $ret; |
|
|
|
return $ret; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Purge unused rooms |
|
|
|
helper delete_rooms => sub { |
|
|
|
helper delete_rooms => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
$self->app->log->debug('Removing unused rooms'); |
|
|
|
$self->app->log->debug('Removing unused rooms'); |
|
|
@ -204,6 +223,8 @@ helper delete_rooms => sub { |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Just update the activity timestamp |
|
|
|
|
|
|
|
# so we can detect unused rooms |
|
|
|
helper ping_room => sub { |
|
|
|
helper ping_room => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
my ($name) = @_; |
|
|
|
my ($name) = @_; |
|
|
@ -219,10 +240,9 @@ helper valid_room_name => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
my ($name) = @_; |
|
|
|
my ($name) = @_; |
|
|
|
my $ret = undef; |
|
|
|
my $ret = undef; |
|
|
|
my $len = length $name; |
|
|
|
|
|
|
|
# A few names are reserved |
|
|
|
# A few names are reserved |
|
|
|
my @reserved = qw(about help feedback goodbye admin create localize action missing dies password); |
|
|
|
my @reserved = qw(about help feedback goodbye admin create localize action missing dies password); |
|
|
|
if ($len > 0 && $len < 50 && $name =~ m/^[\w\-]+$/ && !grep { $name eq $_ } @reserved){ |
|
|
|
if ($name =~ m/^[\w\-]{1,49}$/ && !grep { $name eq $_ } @reserved){ |
|
|
|
$ret = 1; |
|
|
|
$ret = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
return $ret; |
|
|
|
return $ret; |
|
|
@ -239,14 +259,19 @@ helper get_random_name => sub { |
|
|
|
return $name; |
|
|
|
return $name; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
# return the mtime of a file |
|
|
|
# Return the mtime of a file |
|
|
|
|
|
|
|
# Used to append the timestamp to JS and CSS files |
|
|
|
|
|
|
|
# So client can get new version immediatly |
|
|
|
helper get_mtime => sub { |
|
|
|
helper get_mtime => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
my ($file) = @_; |
|
|
|
my ($file) = @_; |
|
|
|
return stat($file)->mtime; |
|
|
|
return stat($file)->mtime; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
# password protect a room |
|
|
|
# Password protect a room |
|
|
|
|
|
|
|
# Takes two args: room name and password |
|
|
|
|
|
|
|
# If password is undef: remove the password |
|
|
|
|
|
|
|
# Password is hashed and salted before being stored |
|
|
|
helper set_join_pass => sub { |
|
|
|
helper set_join_pass => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
my ($room,$pass) = @_; |
|
|
|
my ($room,$pass) = @_; |
|
|
@ -263,11 +288,14 @@ helper set_join_pass => sub { |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
# Set owner password |
|
|
|
# Set owner password. Not needed to join a room |
|
|
|
|
|
|
|
# but needed to prove you're the owner, and access the configuration menu |
|
|
|
helper set_owner_pass => sub { |
|
|
|
helper set_owner_pass => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
my ($room,$pass) = @_; |
|
|
|
my ($room,$pass) = @_; |
|
|
|
return undef unless ( %{ $self->get_room($room) }); |
|
|
|
return undef unless ( %{ $self->get_room($room) }); |
|
|
|
|
|
|
|
# For now, setting an owner password makes the room persistant |
|
|
|
|
|
|
|
# Might be separated in the future |
|
|
|
if ($pass){ |
|
|
|
if ($pass){ |
|
|
|
my $sth = eval { $self->db->prepare("UPDATE rooms SET owner_password=?,persistent='1' where name=?;") } || return undef; |
|
|
|
my $sth = eval { $self->db->prepare("UPDATE rooms SET owner_password=?,persistent='1' where name=?;") } || return undef; |
|
|
|
my $pass = Crypt::SaltedHash->new(algorithm => 'SHA-256')->add($pass)->generate; |
|
|
|
my $pass = Crypt::SaltedHash->new(algorithm => 'SHA-256')->add($pass)->generate; |
|
|
@ -281,15 +309,20 @@ helper set_owner_pass => sub { |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Route / to the index page |
|
|
|
any '/' => 'index'; |
|
|
|
any '/' => 'index'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Route for the about page |
|
|
|
get '/about' => sub { |
|
|
|
get '/about' => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
$self->stash( components => $components ); |
|
|
|
$self->stash( components => $components ); |
|
|
|
} => 'about'; |
|
|
|
} => 'about'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Route for the help page |
|
|
|
get '/help' => 'help'; |
|
|
|
get '/help' => 'help'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Routes for feedback. One get to display the form |
|
|
|
|
|
|
|
# and one post to get data from it |
|
|
|
get '/feedback' => 'feedback'; |
|
|
|
get '/feedback' => 'feedback'; |
|
|
|
post '/feedback' => sub { |
|
|
|
post '/feedback' => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
@ -309,8 +342,10 @@ post '/feedback' => sub { |
|
|
|
$self->redirect_to($self->url_for('feedback_thanks')); |
|
|
|
$self->redirect_to($self->url_for('feedback_thanks')); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Route for the thanks after feedback form |
|
|
|
get 'feedback_thanks' => 'feedback_thanks'; |
|
|
|
get 'feedback_thanks' => 'feedback_thanks'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Route for the goodbye page, displayed when someone leaves a room |
|
|
|
get '/goodby/(:room)' => sub { |
|
|
|
get '/goodby/(:room)' => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
my $room = $self->stash('room'); |
|
|
|
my $room = $self->stash('room'); |
|
|
@ -329,8 +364,11 @@ get '/goodby/(:room)' => sub { |
|
|
|
post '/create' => sub { |
|
|
|
post '/create' => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
$self->res->headers->cache_control('max-age=1, no-cache'); |
|
|
|
$self->res->headers->cache_control('max-age=1, no-cache'); |
|
|
|
|
|
|
|
# No name provided ? Lets generate one |
|
|
|
my $name = $self->param('roomName') || $self->get_random_name(); |
|
|
|
my $name = $self->param('roomName') || $self->get_random_name(); |
|
|
|
|
|
|
|
# Create a session for this user, but don't set a role for now |
|
|
|
$self->login; |
|
|
|
$self->login; |
|
|
|
|
|
|
|
# Error if the name is invalid |
|
|
|
unless ($self->valid_room_name($name)){ |
|
|
|
unless ($self->valid_room_name($name)){ |
|
|
|
return $self->render('error', |
|
|
|
return $self->render('error', |
|
|
|
room => $name, |
|
|
|
room => $name, |
|
|
@ -338,14 +376,18 @@ post '/create' => sub { |
|
|
|
err => 'ERROR_NAME_INVALID' |
|
|
|
err => 'ERROR_NAME_INVALID' |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
# Cleanup unused rooms before trying to create it |
|
|
|
$self->delete_rooms; |
|
|
|
$self->delete_rooms; |
|
|
|
unless ($self->create_room($name,$self->session('name'))){ |
|
|
|
unless ($self->create_room($name,$self->session('name'))){ |
|
|
|
|
|
|
|
# If creation failed, it's most likly a name conflict |
|
|
|
return $self->render('error', |
|
|
|
return $self->render('error', |
|
|
|
room => $name, |
|
|
|
room => $name, |
|
|
|
msg => $self->l('ERROR_NAME_CONFLICT'), |
|
|
|
msg => $self->l('ERROR_NAME_CONFLICT'), |
|
|
|
err => 'ERROR_NAME_CONFLICT' |
|
|
|
err => 'ERROR_NAME_CONFLICT' |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
# EVerything went fine, the room is created, lets mark this user owner of the room |
|
|
|
|
|
|
|
# and redirect him on it. |
|
|
|
else{ |
|
|
|
else{ |
|
|
|
$self->session($name => {role => 'owner'}); |
|
|
|
$self->session($name => {role => 'owner'}); |
|
|
|
$self->redirect_to($self->url_for('/') . $name); |
|
|
|
$self->redirect_to($self->url_for('/') . $name); |
|
|
@ -365,6 +407,7 @@ post '/localize' => sub { |
|
|
|
return $self->render(json => $strings); |
|
|
|
return $self->render(json => $strings); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Route for the password page |
|
|
|
get '/password/(:room)' => sub { |
|
|
|
get '/password/(:room)' => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
my $room = $self->stash('room') || ''; |
|
|
|
my $room = $self->stash('room') || ''; |
|
|
@ -379,6 +422,7 @@ get '/password/(:room)' => sub { |
|
|
|
$self->render('password', room => $room); |
|
|
|
$self->render('password', room => $room); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Route for password submiting |
|
|
|
post '/password/(:room)' => sub { |
|
|
|
post '/password/(:room)' => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
my $room = $self->stash('room') || ''; |
|
|
|
my $room = $self->stash('room') || ''; |
|
|
@ -391,14 +435,17 @@ post '/password/(:room)' => sub { |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
my $pass = $self->param('password'); |
|
|
|
my $pass = $self->param('password'); |
|
|
|
|
|
|
|
# First check if we got the owner password, and if so, mark this user as owner |
|
|
|
if ($data->{owner_password} && Crypt::SaltedHash->validate($data->{owner_password}, $pass)){ |
|
|
|
if ($data->{owner_password} && Crypt::SaltedHash->validate($data->{owner_password}, $pass)){ |
|
|
|
$self->session($room => {role => 'owner'}); |
|
|
|
$self->session($room => {role => 'owner'}); |
|
|
|
$self->redirect_to($self->url_for('/') . $room); |
|
|
|
$self->redirect_to($self->url_for('/') . $room); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
# Then, check if it's the join password |
|
|
|
elsif ($data->{join_password} && Crypt::SaltedHash->validate($data->{join_password}, $pass)){ |
|
|
|
elsif ($data->{join_password} && Crypt::SaltedHash->validate($data->{join_password}, $pass)){ |
|
|
|
$self->session($room => {role => 'participant'}); |
|
|
|
$self->session($room => {role => 'participant'}); |
|
|
|
$self->redirect_to($self->url_for('/') . $room); |
|
|
|
$self->redirect_to($self->url_for('/') . $room); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
# Else, it's a wrong password, display an error page |
|
|
|
else{ |
|
|
|
else{ |
|
|
|
$self->render('error', |
|
|
|
$self->render('error', |
|
|
|
err => 'WRONG_PASSWORD', |
|
|
|
err => 'WRONG_PASSWORD', |
|
|
@ -408,6 +455,7 @@ post '/password/(:room)' => sub { |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Catch all route: if nothing else match, it's the name of a room |
|
|
|
get '/(*room)' => sub { |
|
|
|
get '/(*room)' => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
my $room = $self->stash('room'); |
|
|
|
my $room = $self->stash('room'); |
|
|
@ -416,8 +464,6 @@ get '/(*room)' => sub { |
|
|
|
$self->redirect_to($self->url_for('/') . lc $room); |
|
|
|
$self->redirect_to($self->url_for('/') . lc $room); |
|
|
|
} |
|
|
|
} |
|
|
|
$self->delete_rooms; |
|
|
|
$self->delete_rooms; |
|
|
|
# Not auth yet, probably a guest |
|
|
|
|
|
|
|
$self->login; |
|
|
|
|
|
|
|
unless ($self->valid_room_name($room)){ |
|
|
|
unless ($self->valid_room_name($room)){ |
|
|
|
return $self->render('error', |
|
|
|
return $self->render('error', |
|
|
|
msg => $self->l('ERROR_NAME_INVALID'), |
|
|
|
msg => $self->l('ERROR_NAME_INVALID'), |
|
|
@ -433,20 +479,25 @@ get '/(*room)' => sub { |
|
|
|
room => $room |
|
|
|
room => $room |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
if ($data->{'locked'} && (!$self->session($room) || $self->session($room)->{role} ne 'owner')){ |
|
|
|
# Create a session if not already done |
|
|
|
|
|
|
|
$self->login; |
|
|
|
|
|
|
|
# If the room is locked and we're not the owner, we cannot join it ! |
|
|
|
|
|
|
|
if ($data->{'locked'} && $self->session($room)->{role} ne 'owner'){ |
|
|
|
return $self->render('error', |
|
|
|
return $self->render('error', |
|
|
|
msg => sprintf($self->l("ERROR_ROOM_s_LOCKED"), $room), |
|
|
|
msg => sprintf($self->l("ERROR_ROOM_s_LOCKED"), $room), |
|
|
|
err => 'ERROR_ROOM_s_LOCKED', |
|
|
|
err => 'ERROR_ROOM_s_LOCKED', |
|
|
|
room => $room |
|
|
|
room => $room |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
# Now, if the room is password protected and we're not a participant, nor the owner, lets prompt for the password |
|
|
|
if ($data->{join_password} && (!$self->session($room) || $self->session($room)->{role} !~ m/^participant|owner$/)){ |
|
|
|
if ($data->{join_password} && (!$self->session($room) || $self->session($room)->{role} !~ m/^participant|owner$/)){ |
|
|
|
my $url = $self->url_for('/'); |
|
|
|
my $url = $self->url_for('/'); |
|
|
|
$url .= ($url =~ m/\/$/) ? '' : '/'; |
|
|
|
$url .= ($url =~ m/\/$/) ? '' : '/'; |
|
|
|
return $self->redirect_to($url . 'password/' . $room); |
|
|
|
return $self->redirect_to($url . 'password/' . $room); |
|
|
|
} |
|
|
|
} |
|
|
|
# Set this peer as a simple participant if he has no role yet |
|
|
|
# Set this peer as a simple participant if he has no role yet (shouldn't happen) |
|
|
|
$self->session($room => {role => 'participant'}) if (!$self->session($room) || !$self->session($room)->{role}); |
|
|
|
$self->session($room => {role => 'participant'}) if (!$self->session($room) || !$self->session($room)->{role}); |
|
|
|
|
|
|
|
# Short life cookie to negociate a session with the signaling server |
|
|
|
$self->cookie(vroomsession => encode_base64($self->session('name') . ':' . $data->{name} . ':' . $data->{token}, ''), {expires => time + 60}); |
|
|
|
$self->cookie(vroomsession => encode_base64($self->session('name') . ':' . $data->{name} . ':' . $data->{token}, ''), {expires => time + 60}); |
|
|
|
# Add this user to the participants table |
|
|
|
# Add this user to the participants table |
|
|
|
unless($self->add_participant($room,$self->session('name'))){ |
|
|
|
unless($self->add_participant($room,$self->session('name'))){ |
|
|
@ -456,15 +507,19 @@ get '/(*room)' => sub { |
|
|
|
room => $room |
|
|
|
room => $room |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
$self->stash(locked => $data->{locked} ? 'checked':'', |
|
|
|
# Now display the room page |
|
|
|
turnPassword => $data->{token}); |
|
|
|
$self->render('join', |
|
|
|
$self->render('join'); |
|
|
|
locked => $data->{locked} ? 'checked':'', |
|
|
|
|
|
|
|
turnPassword => $data->{token} |
|
|
|
|
|
|
|
); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Route for various room actions |
|
|
|
post '/action' => sub { |
|
|
|
post '/action' => sub { |
|
|
|
my $self = shift; |
|
|
|
my $self = shift; |
|
|
|
my $action = $self->param('action'); |
|
|
|
my $action = $self->param('action'); |
|
|
|
my $room = $self->param('room') || ""; |
|
|
|
my $room = $self->param('room') || ""; |
|
|
|
|
|
|
|
# Refuse any action from non members of the room |
|
|
|
if (!$self->session('name') || !$self->has_joined($self->session('name'), $room) || !$self->session($room) || !$self->session($room)->{role}){ |
|
|
|
if (!$self->session('name') || !$self->has_joined($self->session('name'), $room) || !$self->session($room) || !$self->session($room)->{role}){ |
|
|
|
return $self->render( |
|
|
|
return $self->render( |
|
|
|
json => { |
|
|
|
json => { |
|
|
@ -473,8 +528,18 @@ post '/action' => sub { |
|
|
|
}, |
|
|
|
}, |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
# Sanity check on the room name |
|
|
|
|
|
|
|
return $self->render( |
|
|
|
|
|
|
|
json => { |
|
|
|
|
|
|
|
msg => sprintf ($self->l("ERROR_NAME_INVALID"), $room), |
|
|
|
|
|
|
|
status => 'error' |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
) unless ($self->valid_room_name($room)); |
|
|
|
|
|
|
|
# Push the room name to the stash, just in case |
|
|
|
$self->stash(room => $room); |
|
|
|
$self->stash(room => $room); |
|
|
|
|
|
|
|
# Gather room info from the DB |
|
|
|
my $data = $self->get_room($room); |
|
|
|
my $data = $self->get_room($room); |
|
|
|
|
|
|
|
# Stop here if the room doesn't exist |
|
|
|
return $self->render( |
|
|
|
return $self->render( |
|
|
|
json => { |
|
|
|
json => { |
|
|
|
msg => sprintf ($self->l("ERROR_ROOM_s_DOESNT_EXIST"), $room), |
|
|
|
msg => sprintf ($self->l("ERROR_ROOM_s_DOESNT_EXIST"), $room), |
|
|
@ -482,6 +547,7 @@ post '/action' => sub { |
|
|
|
}, |
|
|
|
}, |
|
|
|
) unless ($data); |
|
|
|
) unless ($data); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Handle email invitation |
|
|
|
if ($action eq 'invite'){ |
|
|
|
if ($action eq 'invite'){ |
|
|
|
my $rcpt = $self->param('recipient'); |
|
|
|
my $rcpt = $self->param('recipient'); |
|
|
|
my $message = $self->param('message'); |
|
|
|
my $message = $self->param('message'); |
|
|
@ -510,10 +576,12 @@ post '/action' => sub { |
|
|
|
} |
|
|
|
} |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
# Handle room lock/unlock |
|
|
|
if ($action =~ m/(un)?lock/){ |
|
|
|
if ($action =~ m/(un)?lock/){ |
|
|
|
my ($lock,$success); |
|
|
|
my ($lock,$success); |
|
|
|
my $msg = 'ERROR_OCCURED'; |
|
|
|
my $msg = 'ERROR_OCCURED'; |
|
|
|
my $status = 'error'; |
|
|
|
my $status = 'error'; |
|
|
|
|
|
|
|
# Only the owner can lock or unlock a room |
|
|
|
if (!$self->session($room) || $self->session($room)->{role} ne 'owner'){ |
|
|
|
if (!$self->session($room) || $self->session($room)->{role} ne 'owner'){ |
|
|
|
$msg = 'NOT_ALLOWED'; |
|
|
|
$msg = 'NOT_ALLOWED'; |
|
|
|
} |
|
|
|
} |
|
|
@ -528,6 +596,7 @@ post '/action' => sub { |
|
|
|
} |
|
|
|
} |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
# Handle activity pings sent every minute by each participant |
|
|
|
elsif ($action eq 'ping'){ |
|
|
|
elsif ($action eq 'ping'){ |
|
|
|
my $status = 'error'; |
|
|
|
my $status = 'error'; |
|
|
|
my $msg = 'ERROR_OCCURED'; |
|
|
|
my $msg = 'ERROR_OCCURED'; |
|
|
@ -547,13 +616,16 @@ post '/action' => sub { |
|
|
|
} |
|
|
|
} |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
# Handle password (join and owner) |
|
|
|
elsif ($action eq 'setPassword'){ |
|
|
|
elsif ($action eq 'setPassword'){ |
|
|
|
my $pass = $self->param('password'); |
|
|
|
my $pass = $self->param('password'); |
|
|
|
my $type = $self->param('type') || 'join'; |
|
|
|
my $type = $self->param('type') || 'join'; |
|
|
|
|
|
|
|
# Empty password is equivalent to no password at all |
|
|
|
$pass = undef if ($pass && $pass eq ''); |
|
|
|
$pass = undef if ($pass && $pass eq ''); |
|
|
|
my $res = undef; |
|
|
|
my $res = undef; |
|
|
|
my $msg = 'ERROR_OCCURED'; |
|
|
|
my $msg = 'ERROR_OCCURED'; |
|
|
|
my $status = 'error'; |
|
|
|
my $status = 'error'; |
|
|
|
|
|
|
|
# Once again, only the owner can do this |
|
|
|
if ($self->session($room)->{role} eq 'owner'){ |
|
|
|
if ($self->session($room)->{role} eq 'owner'){ |
|
|
|
if ($type eq 'owner'){ |
|
|
|
if ($type eq 'owner'){ |
|
|
|
$res = $self->set_owner_pass($room,$pass); |
|
|
|
$res = $self->set_owner_pass($room,$pass); |
|
|
@ -566,6 +638,7 @@ post '/action' => sub { |
|
|
|
$status = 'success'; |
|
|
|
$status = 'success'; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
# Simple participants will get an error |
|
|
|
else{ |
|
|
|
else{ |
|
|
|
$msg = 'NOT_ALLOWED'; |
|
|
|
$msg = 'NOT_ALLOWED'; |
|
|
|
} |
|
|
|
} |
|
|
@ -576,11 +649,13 @@ post '/action' => sub { |
|
|
|
} |
|
|
|
} |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
# A participant is trying to auth as an owner, lets check that |
|
|
|
elsif ($action eq 'authenticate'){ |
|
|
|
elsif ($action eq 'authenticate'){ |
|
|
|
my $pass = $self->param('password'); |
|
|
|
my $pass = $self->param('password'); |
|
|
|
my $res = undef; |
|
|
|
my $res = undef; |
|
|
|
my $msg = 'ERROR_OCCURED'; |
|
|
|
my $msg = 'ERROR_OCCURED'; |
|
|
|
my $status = 'error'; |
|
|
|
my $status = 'error'; |
|
|
|
|
|
|
|
# Auth succeed ? lets promote him to owner of the room |
|
|
|
if ($data->{owner_password} && Crypt::SaltedHash->validate($data->{owner_password}, $pass)){ |
|
|
|
if ($data->{owner_password} && Crypt::SaltedHash->validate($data->{owner_password}, $pass)){ |
|
|
|
$self->session($room, {role => 'owner'}); |
|
|
|
$self->session($room, {role => 'owner'}); |
|
|
|
$msg = 'AUTH_SUCCESS'; |
|
|
|
$msg = 'AUTH_SUCCESS'; |
|
|
@ -589,6 +664,7 @@ post '/action' => sub { |
|
|
|
elsif ($data->{owner_password}){ |
|
|
|
elsif ($data->{owner_password}){ |
|
|
|
$msg = 'WRONG_PASSWORD'; |
|
|
|
$msg = 'WRONG_PASSWORD'; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
# There's no owner password, so you cannot auth |
|
|
|
else{ |
|
|
|
else{ |
|
|
|
$msg = 'NOT_ALLOWED'; |
|
|
|
$msg = 'NOT_ALLOWED'; |
|
|
|
} |
|
|
|
} |
|
|
@ -599,26 +675,26 @@ post '/action' => sub { |
|
|
|
}, |
|
|
|
}, |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
# Return your role and various info about the room |
|
|
|
elsif ($action eq 'getRole'){ |
|
|
|
elsif ($action eq 'getRole'){ |
|
|
|
return $self->render( |
|
|
|
return $self->render( |
|
|
|
json => { |
|
|
|
json => { |
|
|
|
role => $self->session($room)->{role}, |
|
|
|
role => $self->session($room)->{role}, |
|
|
|
owner_auth => ($data->{owner_password}) ? 'yes' : 'no', |
|
|
|
owner_auth => ($data->{owner_password}) ? 'yes' : 'no', |
|
|
|
join_auth => ($data->{join_password}) ? 'yes' : 'no', |
|
|
|
join_auth => ($data->{join_password}) ? 'yes' : 'no', |
|
|
|
|
|
|
|
locked => ($data->{locked}) ? 'yes' : 'no' , |
|
|
|
status => 'success' |
|
|
|
status => 'success' |
|
|
|
}, |
|
|
|
}, |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
# Not found (404) |
|
|
|
# use the templates defined in the config |
|
|
|
get '/missing' => sub { shift->render('does_not_exist') }; |
|
|
|
|
|
|
|
# Exception (500) |
|
|
|
|
|
|
|
get '/dies' => sub { die 'Intentional error' }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
push @{app->renderer->paths}, '../templates/'.$config->{template}; |
|
|
|
push @{app->renderer->paths}, '../templates/'.$config->{template}; |
|
|
|
|
|
|
|
# Set the secret used to sign cookies |
|
|
|
app->secret($config->{secret}); |
|
|
|
app->secret($config->{secret}); |
|
|
|
app->sessions->secure(1); |
|
|
|
app->sessions->secure(1); |
|
|
|
app->sessions->cookie_name('vroom'); |
|
|
|
app->sessions->cookie_name('vroom'); |
|
|
|
|
|
|
|
# And start, lets VROOM !! |
|
|
|
app->start; |
|
|
|
app->start; |
|
|
|
|
|
|
|
|
|
|
|