Skip to content

Commit

Permalink
added multi_signed_cookie method
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Oct 7, 2014
1 parent 193541f commit 45a65a6
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 74 deletions.
10 changes: 5 additions & 5 deletions lib/Mojolicious.pm
Expand Up @@ -158,11 +158,11 @@ sub new {
my $r = $self->routes->namespaces(["@{[ref $self]}::Controller", ref $self]);

# Hide controller attributes/methods and "handler"
$r->hide(qw(app continue cookie finish flash handler helpers match on));
$r->hide(qw(param redirect_to render render_exception render_later));
$r->hide(qw(render_maybe render_not_found render_to_string rendered req));
$r->hide(qw(res respond_to send session signed_cookie stash tx url_for));
$r->hide(qw(validation write write_chunk));
$r->hide(qw(app continue cookie finish flash handler helpers match));
$r->hide(qw(multi_signed_cookie on param redirect_to render));
$r->hide(qw(render_exception render_later render_maybe render_not_found));
$r->hide(qw(render_to_string rendered req res respond_to send session));
$r->hide(qw(signed_cookie stash tx url_for validation write write_chunk));

# DEPRECATED in Tiger Face!
$r->hide('render_static');
Expand Down
67 changes: 40 additions & 27 deletions lib/Mojolicious/Controller.pm
Expand Up @@ -94,6 +94,8 @@ sub flash {

sub helpers { $_[0]->app->renderer->get_helper('')->($_[0]) }

sub multi_signed_cookie { _signed_cookie(@_) }

sub on {
my ($self, $name, $cb) = @_;
my $tx = $self->tx;
Expand Down Expand Up @@ -285,31 +287,7 @@ sub signed_cookie {
"$value--" . Mojo::Util::hmac_sha1_sum($value, $secrets->[0]), $options)
if defined $value;

# Request cookies
my @results;
for my $value ($self->cookie($name)) {

# Check signature with rotating secrets
if ($value =~ s/--([^\-]+)$//) {
my $signature = $1;

my $valid;
for my $secret (@$secrets) {
my $check = Mojo::Util::hmac_sha1_sum($value, $secret);
++$valid and last if Mojo::Util::secure_compare($signature, $check);
}
if ($valid) { push @results, $value }

else {
$self->app->log->debug(
qq{Bad signed cookie "$name", possible hacking attempt.});
}
}

else { $self->app->log->debug(qq{Cookie "$name" not signed.}) }
}

return wantarray ? @results : $results[0];
return _signed_cookie($self, $name)->[0];
}

sub stash { Mojo::Util::_stash(stash => @_) }
Expand Down Expand Up @@ -384,6 +362,36 @@ sub write_chunk {
return $self->rendered;
}

sub _signed_cookie {
my ($self, $name) = @_;

my $secrets = $self->stash->{'mojo.secrets'};
my @results;
for my $value ($self->cookie($name)) {

# Check signature with rotating secrets
if ($value =~ s/--([^\-]+)$//) {
my $signature = $1;

my $valid;
for my $secret (@$secrets) {
my $check = Mojo::Util::hmac_sha1_sum($value, $secret);
++$valid and last if Mojo::Util::secure_compare($signature, $check);
}
if ($valid) { push @results, $value }

else {
$self->app->log->debug(
qq{Bad signed cookie "$name", possible hacking attempt.});
}
}

else { $self->app->log->debug(qq{Cookie "$name" not signed.}) }
}

return \@results;
}

1;

=encoding utf8
Expand Down Expand Up @@ -521,6 +529,12 @@ L<Mojolicious::Plugin::DefaultHelpers> and L<Mojolicious::Plugin::TagHelpers>.
# Make sure to use the "title" helper and not the controller method
$c->helpers->title('Welcome!');
=head2 multi_signed_cookie
my $values = $c->multi_signed_cookie('foo');
Access multiple signed request cookie values with the same name.
=head2 on
my $cb = $c->on(finish => sub {...});
Expand Down Expand Up @@ -839,8 +853,7 @@ on browser.
=head2 signed_cookie
my $foo = $c->signed_cookie('foo');
my @foo = $c->signed_cookie('foo');
my $value = $c->signed_cookie('foo');
my ($foo, $bar) = $c->signed_cookie(['foo', 'bar']);
$c = $c->signed_cookie(foo => 'bar');
$c = $c->signed_cookie(foo => 'bar', {path => '/'});
Expand Down
79 changes: 40 additions & 39 deletions t/mojolicious/app.t
Expand Up @@ -93,45 +93,46 @@ like $@, qr/^Undefined subroutine &Mojolicious::Route::missing called/,
# Hidden controller attributes and methods
$t->app->routes->hide('bar');
ok !$t->app->routes->is_hidden('foo'), 'not hidden';
ok $t->app->routes->is_hidden('bar'), 'is hidden';
ok $t->app->routes->is_hidden('_foo'), 'is hidden';
ok $t->app->routes->is_hidden('AUTOLOAD'), 'is hidden';
ok $t->app->routes->is_hidden('DESTROY'), 'is hidden';
ok $t->app->routes->is_hidden('FOO_BAR'), 'is hidden';
ok $t->app->routes->is_hidden('app'), 'is hidden';
ok $t->app->routes->is_hidden('attr'), 'is hidden';
ok $t->app->routes->is_hidden('continue'), 'is hidden';
ok $t->app->routes->is_hidden('cookie'), 'is hidden';
ok $t->app->routes->is_hidden('finish'), 'is hidden';
ok $t->app->routes->is_hidden('flash'), 'is hidden';
ok $t->app->routes->is_hidden('handler'), 'is hidden';
ok $t->app->routes->is_hidden('has'), 'is hidden';
ok $t->app->routes->is_hidden('helpers'), 'is hidden';
ok $t->app->routes->is_hidden('match'), 'is hidden';
ok $t->app->routes->is_hidden('new'), 'is hidden';
ok $t->app->routes->is_hidden('on'), 'is hidden';
ok $t->app->routes->is_hidden('param'), 'is hidden';
ok $t->app->routes->is_hidden('redirect_to'), 'is hidden';
ok $t->app->routes->is_hidden('render'), 'is hidden';
ok $t->app->routes->is_hidden('render_exception'), 'is hidden';
ok $t->app->routes->is_hidden('render_later'), 'is hidden';
ok $t->app->routes->is_hidden('render_maybe'), 'is hidden';
ok $t->app->routes->is_hidden('render_not_found'), 'is hidden';
ok $t->app->routes->is_hidden('render_to_string'), 'is hidden';
ok $t->app->routes->is_hidden('rendered'), 'is hidden';
ok $t->app->routes->is_hidden('req'), 'is hidden';
ok $t->app->routes->is_hidden('res'), 'is hidden';
ok $t->app->routes->is_hidden('respond_to'), 'is hidden';
ok $t->app->routes->is_hidden('send'), 'is hidden';
ok $t->app->routes->is_hidden('session'), 'is hidden';
ok $t->app->routes->is_hidden('signed_cookie'), 'is hidden';
ok $t->app->routes->is_hidden('stash'), 'is hidden';
ok $t->app->routes->is_hidden('tap'), 'is hidden';
ok $t->app->routes->is_hidden('tx'), 'is hidden';
ok $t->app->routes->is_hidden('url_for'), 'is hidden';
ok $t->app->routes->is_hidden('validation'), 'is hidden';
ok $t->app->routes->is_hidden('write'), 'is hidden';
ok $t->app->routes->is_hidden('write_chunk'), 'is hidden';
ok $t->app->routes->is_hidden('bar'), 'is hidden';
ok $t->app->routes->is_hidden('_foo'), 'is hidden';
ok $t->app->routes->is_hidden('AUTOLOAD'), 'is hidden';
ok $t->app->routes->is_hidden('DESTROY'), 'is hidden';
ok $t->app->routes->is_hidden('FOO_BAR'), 'is hidden';
ok $t->app->routes->is_hidden('app'), 'is hidden';
ok $t->app->routes->is_hidden('attr'), 'is hidden';
ok $t->app->routes->is_hidden('continue'), 'is hidden';
ok $t->app->routes->is_hidden('cookie'), 'is hidden';
ok $t->app->routes->is_hidden('finish'), 'is hidden';
ok $t->app->routes->is_hidden('flash'), 'is hidden';
ok $t->app->routes->is_hidden('handler'), 'is hidden';
ok $t->app->routes->is_hidden('has'), 'is hidden';
ok $t->app->routes->is_hidden('helpers'), 'is hidden';
ok $t->app->routes->is_hidden('match'), 'is hidden';
ok $t->app->routes->is_hidden('multi_signed_cookie'), 'is hidden';
ok $t->app->routes->is_hidden('new'), 'is hidden';
ok $t->app->routes->is_hidden('on'), 'is hidden';
ok $t->app->routes->is_hidden('param'), 'is hidden';
ok $t->app->routes->is_hidden('redirect_to'), 'is hidden';
ok $t->app->routes->is_hidden('render'), 'is hidden';
ok $t->app->routes->is_hidden('render_exception'), 'is hidden';
ok $t->app->routes->is_hidden('render_later'), 'is hidden';
ok $t->app->routes->is_hidden('render_maybe'), 'is hidden';
ok $t->app->routes->is_hidden('render_not_found'), 'is hidden';
ok $t->app->routes->is_hidden('render_to_string'), 'is hidden';
ok $t->app->routes->is_hidden('rendered'), 'is hidden';
ok $t->app->routes->is_hidden('req'), 'is hidden';
ok $t->app->routes->is_hidden('res'), 'is hidden';
ok $t->app->routes->is_hidden('respond_to'), 'is hidden';
ok $t->app->routes->is_hidden('send'), 'is hidden';
ok $t->app->routes->is_hidden('session'), 'is hidden';
ok $t->app->routes->is_hidden('signed_cookie'), 'is hidden';
ok $t->app->routes->is_hidden('stash'), 'is hidden';
ok $t->app->routes->is_hidden('tap'), 'is hidden';
ok $t->app->routes->is_hidden('tx'), 'is hidden';
ok $t->app->routes->is_hidden('url_for'), 'is hidden';
ok $t->app->routes->is_hidden('validation'), 'is hidden';
ok $t->app->routes->is_hidden('write'), 'is hidden';
ok $t->app->routes->is_hidden('write_chunk'), 'is hidden';

# Unknown hooks
ok !$t->app->plugins->emit_chain('does_not_exist'), 'hook has been emitted';
Expand Down
6 changes: 3 additions & 3 deletions t/mojolicious/group_lite_app.t
Expand Up @@ -480,9 +480,9 @@ Oops!
% my ($four, $six) = $c->signed_cookie([qw(signed1 signed2)]);
%= $four // ''
%= $six // '';
% my @signed1 = $c->signed_cookie('signed1');
%= $signed1[0] // ''
%= $signed1[1] // ''
% my $signed1 = $c->multi_signed_cookie('signed1');
%= $signed1->[0] // ''
%= $signed1->[1] // ''
@@ param_auth.html.epl
Bender!
Expand Down

0 comments on commit 45a65a6

Please sign in to comment.