|
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; |