package SeMeet; use Mojo::Base 'Mojolicious', -signatures; use Mojo::Pg; use Mojo::Redis; use Mojolicious::Plugin::Authentication; use Mojolicious::Plugin::I18N; use Net::OAuth2::Profile::WebServer; use File::Find; use Path::Tiny qw( path ); use SeMeet::Schema; use SeMeet::Model::IAPI; use constant SECRETS => '/run/secrets'; sub startup( $self ) { # Nacteni konfigurace my $cfg = $self->plugin('Config' => { file => 'semeet.conf'} ); # env z docker secrets find(sub { $ENV{$_} = path(SECRETS . "/$_")->slurp_utf8 }, SECRETS); # Konfigurace z ENV ma prednost KEY: foreach my $key ( keys %ENV ) { if ( $key =~ /^CFG_(.+)/i ) { $cfg->{lc($1)} = $ENV{$key}; } } $self->helper( cfg => sub { return $cfg; } ); # Podpis pro cookies $self->secrets([$cfg->{session_secret}]); # Delka session $self->sessions->default_expiration($cfg->{session_lifetime} // 24 * 3600); $self->plugin('SeMeet::Helpers::Core'); $self->plugin('SeMeet::Helpers::OIDC'); # migrace schematu my $pg = Mojo::Pg->new ->dsn($cfg->{database}{dsn}) ->username($cfg->{database}{user}) ->password($cfg->{database}{password}) ; $pg->migrations->from_file($self->home . '/sql/migrations.sql'); $pg->migrations->migrate(); $self->helper( pg => sub { return $pg; } ); # Spojeni s databazi my $schema = SeMeet::Schema->connect($cfg->{database}); $self->helper( schema => sub { return $schema; } ); # Redis my $iapi = SeMeet::Model::IAPI->new( $cfg->{iapi} ); $self->helper( iapi => sub { return $iapi; } ); # Redis my $redis = Mojo::Redis->new( $cfg->{redis} ); $self->helper( redis => sub { return $redis; } ); # i18n $self->plugin( I18N => { namespace => 'SeMeet::I18N', default => 'cs', }); $self->plugin('authentication', { autoload_user => 1, load_user => sub($c, $uid) { return $c->session->{user}; }, validate_user => sub($c, $user, $pass, $extradata) { return $c->session->{user} ? 1 : undef; }, }); $self->plugin("OpenAPI" => { url => $self->home->rel_file("openapi.yaml"), schema => 'v3', plugins => [qw(+Cors +Security)], render_specification => 0, render_specification_for_paths => 0, default_response_codes => [400, 401, 403, 404, 500, 501], security => { Bearer => sub ($c, $definition, $scopes, $cb ){ # my ($c, $definition, $scopes, $cb ) = @_; my $token = $c->req->headers->authorization || $c->req->param('auth_token'); return $c->$cb('Authorization header not present') if ! $token; return $c->$cb('Unsupported authorization type') if $token !~ s/Bearer\s+//i; my $jwt = $c->jwt_token( $token ); return $c->$cb($jwt) if ! ref $jwt; my $user = $schema->resultset('User')->find({ id => $jwt->{id} } ); return $c->$cb('Invalid user') if ! $user; $c->stash->{user} = $user; $c->stash->{groups} = $jwt->{groups}; $c->stash->{permissions} = $jwt->{permissions}; return $c->$cb(); } } }); # defautni globalni promenne ve stash $self->defaults( openapi_cors_allowed_origins => ['*'], ); $self->hook( before_render => sub($c, $args) { if ( $c->req->method eq 'OPTIONS' && exists $args->{json} ) { delete $args->{json}; $args->{status} = 204; $args->{text} = ''; } }); # vypnuti cache templatu pri vyvoji $self->renderer->cache->max_keys(0) if $cfg->{dev_mode}; # router my $r = $self->routes; $r->get('/login')->to('Auth#callback'); $r->get('/logout')->to('Auth#do_logout'); $r->get('/')->requires(authenticated => 1)->to(cb => sub { shift->render('meets'); }); $r->get('/')->to(cb => sub { shift->render('index'); }); $r->get('/meets/:id')->requires(authenticated => 1)->to('Meets#meet'); $r->get('/meets/:id')->to(cb => sub { my $c = shift; $c->session->{id} = $c->stash->{id}; $c->render('index'); }); $r->get('/guest/:token')->to('Invites#meet'); $r->websocket('/ws')->to('Websockets#main'); } 1;