#!/bin/bash

# read rc file if exists
if [ -e ~/.thruk  ]; then
    . ~/.thruk
fi
if [ -e ~/.profile  ]; then
    . ~/.profile
fi

if [ ! -z $OMD_ROOT ]; then
    export PERL5LIB=$OMD_ROOT/share/thruk/lib:$PERL5LIB
    export CATALYST_CONFIG=$OMD_ROOT/etc/thruk
fi

eval 'exec /usr/bin/perl -x $0 ${1+"$@"} ;'
    if 0;

#! -*- perl -*-
# vim: expandtab:ts=4:sw=4:syntax=perl

use warnings;
use strict;
use File::Slurp;
use Thruk::Config;
use Thruk::Utils::CookieAuth;

$|            = 1;
my $prefix    = '';
my $urlprefix = "thruk";
if(defined $ENV{'OMD_SITE'}) {
    $prefix    = $ENV{'OMD_SITE'}.'/';
    $urlprefix = "[^/]+/thruk";
}

##########################################################
my $config              = Thruk::Config::get_config();
my $spath               = $config->{'tmp_path'}."/sessions";
my $loginurl            = $config->{'cookie_auth_login_url'}             || $prefix."thruk/cgi-bin/login.cgi";
my $sessiontimeout      = $config->{'cookie_auth_session_timeout'}       || 86400;
my $sessioncachetimeout = $config->{'cookie_auth_session_cache_timeout'} || 5;
my $sessioncache        = {};
$loginurl               = "/redirect/".$loginurl;
my $line_regex          = qr|^/(.*?)/(.*?)/____/(.*)$|mx;
my $pass_regex          = qr#^$urlprefix/(startup\.html|themes|javascript|cgi\-bin/(login|remote|restricted)\.cgi)#mx;
my $cookie_regex        = qr/thruk_auth=(\w+)/mx;
my $session_split       = qr/~~~/mx;
my $last_cache_clean    = time();

##########################################################
while (<STDIN>) {
    chomp(my $in = $_);

    if($in =~ $line_regex) {
        my($cookies, $remote, $path) = ($1, $2, $3);

        # some urls must pass
        if($path =~ $pass_regex) {
            print "/pass/$path\n";
            next;
        }

        # did we get a cookie
        if($cookies eq '' or $cookies !~ $cookie_regex) {
            print $loginurl."?".$path."\n";
            next;
        }
        my $auth = $1;

        # use session cache for a few seconds
        my $now = time();
        if(defined $sessioncache->{$auth} and $sessioncache->{$auth}->{'time'} > $now - $sessioncachetimeout) {
            print "/loginok/", $sessioncache->{$auth}->{'login'} ,"/",$path,"\n";
            next;
        }

        # does our sessionfile exist?
        my $sessionfile = $spath.'/'.$auth;
        if(!-f $sessionfile) {
            delete $sessioncache->{$auth} if defined $sessioncache->{$auth};
            print $loginurl."?expired&".$path."\n";
            next;
        }

        # session timeout reached?
        if(defined $sessioncache->{$auth} and $sessioncache->{$auth}->{'time'} < $now - $sessiontimeout) {
            unlink($sessionfile);
            delete $sessioncache->{$auth};
            print $loginurl, "?expired&", $path, "\n";
            next;
        }

        chomp(my $cont = read_file($sessionfile));
        my($basicauth, $ip, $user) = split($session_split, $cont, 3);

        # won't work in omds own apache mode
        #if($ip ne $remote) {
        #    print $loginurl, "?", $path, "\n";
        #    next;
        #}

        # validate session data
        if(!Thruk::Utils::CookieAuth::verify_basic_auth($config, $basicauth, $user)) {
            unlink($sessionfile);
            delete $sessioncache->{$auth};
            print $loginurl, "?invalid&", $path, "\n";
            next;
        }

        # clean old session cache
        clean_session_cache($sessioncache) if($last_cache_clean < $now - 3600);

        # grant access
        $sessioncache->{$auth} = {
                'login' => $user,
                'time'  => $now,
        };
        print "/loginok/", $user, "/", $path, "\n";
        next;
    }

    # everything else redirects to login
    print $loginurl, "\n";
}

##########################################################
sub clean_session_cache {
    my($sessioncache) = @_;
    my $clean_before = time() - $sessiontimeout - $sessioncachetimeout;
    for my $key (keys %{$sessioncache}) {
        delete $sessioncache->{$key} if $sessioncache->{$key}->{'time'} < $clean_before;
    }
    return;
}
