Skip to content

Instantly share code, notes, and snippets.

@s1037989
Created February 4, 2019 20:07
Show Gist options
  • Save s1037989/84a365f4afb6ebd987557802a5482a57 to your computer and use it in GitHub Desktop.
Save s1037989/84a365f4afb6ebd987557802a5482a57 to your computer and use it in GitHub Desktop.
Mojolicious::Sessions-like Cookies
package Mojolicious::MyCookie;
use Mojo::Base -base;
use Mojo::JSON;
use Mojo::Util qw(b64_decode b64_encode);
has [qw(cookie_domain secure)];
has cookie_name => 'mycookie';
has cookie_path => '/';
has default_expiration => 3600;
has deserialize => sub { \&Mojo::JSON::j };
has samesite => 'Lax';
has serialize => sub { \&Mojo::JSON::encode_json };
sub load {
my ($self, $c) = @_;
return unless my $value = $c->signed_cookie($self->cookie_name);
$value =~ y/-/=/;
return unless my $mycookie = $self->deserialize->(b64_decode $value);
# "expiration" value is inherited
my $expiration = $mycookie->{expiration} // $self->default_expiration;
return if !(my $expires = delete $mycookie->{expires}) && $expiration;
return if defined $expires && $expires <= time;
my $stash = $c->stash;
return unless $stash->{'mycookie.active_session'} = keys %$mycookie;
$stash->{'mycookie.session'} = $mycookie;
$mycookie->{flash} = delete $mycookie->{new_flash} if $mycookie->{new_flash};
}
sub store {
my ($self, $c) = @_;
# Make sure mycookie was active
my $stash = $c->stash;
return unless my $mycookie = $stash->{'mycookie.session'};
return unless keys %$mycookie || $stash->{'mycookie.active_session'};
# Don't reset flash for static files
my $old = delete $mycookie->{flash};
$mycookie->{new_flash} = $old if $stash->{'mycookie.static'};
delete $mycookie->{new_flash} unless keys %{$mycookie->{new_flash}};
# Generate "expires" value from "expiration" if necessary
my $expiration = $mycookie->{expiration} // $self->default_expiration;
my $default = delete $mycookie->{expires};
$mycookie->{expires} = $default || time + $expiration
if $expiration || $default;
my $value = b64_encode $self->serialize->($mycookie), '';
$value =~ y/=/-/;
my $options = {
domain => $self->cookie_domain,
expires => $mycookie->{expires},
httponly => 1,
path => $self->cookie_path,
samesite => $self->samesite,
secure => $self->secure
};
$c->signed_cookie($self->cookie_name, $value, $options);
}
package main;
#!/usr/bin/env perl
use Mojolicious::Lite;
hook after_dispatch => sub {
my $self = shift;
$self->mycookies->store($self);
};
helper mycookies => sub { Mojolicious::MyCookie->new };
helper mycookie => sub {
my $c = shift;
my $stash = $c->stash;
$c->app->mycookies->load($c)
unless exists $stash->{'mycookie.active_session'};
# Hash
my $mycookie = $stash->{'mycookie.session'} ||= {};
return $mycookie unless @_;
# Get
return $mycookie->{$_[0]} unless @_ > 1 || ref $_[0];
# Set
my $values = ref $_[0] ? $_[0] : {@_};
@$mycookie{keys %$values} = values %$values;
return $c;
};
get '/' => sub {
my $c = shift;
$c->mycookie(key => 'value');
$c->redirect_to('page');
};
get '/page' => sub {
my $c = shift;
$c->render(text => $c->mycookie('key') || 'no key');
};
app->start;
$ perl mycookie get -r /
[2019-02-04 13:50:38.39889] [1486] [debug] GET "/" (e1c498f4)
[2019-02-04 13:50:38.39930] [1486] [debug] Routing to a callback
[2019-02-04 13:50:38.39944] [1486] [debug] Your secret passphrase needs to be changed
[2019-02-04 13:50:38.39974] [1486] [debug] 302 Found (0.000847s, 1180.638/s)
[2019-02-04 13:50:38.40178] [1486] [debug] GET "/page" (5dc92e34)
[2019-02-04 13:50:38.40201] [1486] [debug] Routing to a callback
[2019-02-04 13:50:38.40240] [1486] [debug] 200 OK (0.000608s, 1644.737/s)
value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment