2023-09-08 22:05:21 +02:00
# irclogger_web
# Copyright (C) 2023 mrkubax10 <mrkubax10@onet.pl>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
package frontend_routes ;
use lib "." ;
use frontend_session ;
use Digest::SHA ;
use feature qw( switch ) ;
use strict ;
use warnings ;
sub handlePath {
my $ aClient = $ _ [ 0 ] ;
my $ aPath = $ _ [ 1 ] ;
my $ aRequest = $ _ [ 2 ] ;
my $ aConnection = $ _ [ 3 ] ;
given ( $ aPath ) {
when ( "/" ) {
my $ userbar ;
my $ logged = 0 ;
if ( defined ( $ aRequest - > { "cookies" } ) && defined ( $ aRequest - > { "cookies" } { "session" } ) ) {
my $ session = $ aRequest - > { "cookies" } { "session" } ;
if ( frontend_session:: isValidSession ( $ session ) && defined ( $ frontend_session:: sessions { $ session } { "username" } ) && $ frontend_session:: sessions { $ session } { "logged" } ) {
my $ username = $ frontend_session:: sessions { $ session } { "username" } ;
$ userbar = "<a href=\"panel\">$username</a>" ;
$ userbar . = "<a href=\"logout_action\">Log out</a>" ;
$ logged = 1 ;
}
}
if ( ! $ logged ) {
$ userbar = "<form action=\"login_action\" method=\"POST\">" ;
$ userbar . = "<input name=\"username\" type=\"text\" placeholder=\"Username\" /> " ;
$ userbar . = "<input name=\"password\" type=\"password\" placeholder=\"Password\" /> " ;
$ userbar . = "<input name=\"login\" type=\"submit\" value=\"Login\" />" ;
$ userbar . = "</form>" ;
}
my $ query = $ aConnection - > prepare ( qq( select channels.id, channels.name, servers.name from channels inner join servers on channels.server_id=servers.id where channels.public=1; ) ) ;
$ query - > execute ( ) ;
my $ table = "" ;
while ( my @ row = $ query - > fetchrow_array ( ) ) {
my $ channelID = $ row [ 0 ] ;
my $ channelName = $ row [ 1 ] ;
my $ serverName = $ row [ 2 ] ;
$ table . = "<tr><td><a href=\"view_logs?channel=$channelID\">$channelName</a></td><td>$serverName</td></tr>" ;
}
frontend:: sendTemplate ( "templates/index.html" , $ aClient , { "userbar" = > $ userbar , "publicChannels" = > $ table } ) ;
return 1 ;
}
when ( "/login_action" ) {
if ( defined ( $ aRequest - > { "cookies" } { "session" } ) && frontend_session:: isValidSession ( $ aRequest - > { "cookies" } { "session" } ) ) {
frontend:: redirect ( $ aClient , "/" ) ;
return 1 ;
}
if ( defined ( $ aRequest - > { "headers" } { "Content-Type" } ) && $ aRequest - > { "headers" } { "Content-Type" } ne "application/x-www-form-urlencoded" ) {
frontend:: sendBadRequest ( $ aClient , "Unsupported form Content-Type (application/x-www-form-urlencoded required)" ) ;
return 1 ;
}
if ( ! defined ( $ aRequest - > { "content" } ) ) {
frontend:: sendBadRequest ( $ aClient , "Request content required" ) ;
return 1 ;
}
my % parameters = frontend:: parsePathParameters ( $ aRequest - > { "content" } ) ;
if ( ! defined ( $ parameters { "username" } ) ) {
frontend:: sendBadRequest ( $ aClient , "Username parameter required" ) ;
return 1 ;
}
if ( ! defined ( $ parameters { "password" } ) ) {
frontend:: sendBadRequest ( $ aClient , "Password parameter required" ) ;
return 1 ;
}
my $ username = $ parameters { 'username' } ;
#my $hashedPassword = Digest::SHA::sha256_hex($parameters{"password"});
my $ hashedPassword = $ parameters { "password" } ;
my $ query = $ aConnection - > prepare ( qq( select name, password from users where name=?; ) ) ;
$ query - > execute ( $ username ) ;
my @ row = $ query - > fetchrow_array ( ) ;
if ( scalar ( @ row ) == 0 ) {
frontend:: sendBadRequest ( $ aClient , "Unknown user $username" ) ;
return 1 ;
}
if ( $ row [ 1 ] ne $ hashedPassword ) {
frontend:: sendBadRequest ( $ aClient , "Wrong password" ) ;
return 1 ;
}
2023-09-09 10:52:28 +02:00
my $ token = frontend_session:: newSessionToken ( ) ;
2023-09-08 22:05:21 +02:00
$ frontend_session:: sessions { $ token } { "username" } = $ username ;
$ frontend_session:: sessions { $ token } { "logged" } = 1 ;
my $ response = frontend:: getBaseResponse ( 301 , "OK" ) ;
$ response . = "Location: /\r\n" ;
$ response . = "Content-Length: 0\r\n" ;
$ response . = "Set-Cookie: session=$token\r\n\r\n" ;
$ aClient - > send ( $ response ) ;
return 1 ;
}
2023-09-09 10:58:26 +02:00
when ( "/logout_action" ) {
if ( defined ( $ aRequest - > { "cookies" } { "session" } ) ) {
frontend_session:: deleteSession ( $ aRequest - > { "cookies" } { "session" } ) ;
}
frontend:: redirect ( $ aClient , "/" ) ;
return 1 ;
}
2023-09-08 22:05:21 +02:00
when ( "/view_logs" ) {
my $ channelID = $ aRequest - > { "path" } { "parameters" } { "channel" } ;
if ( ! defined ( $ channelID ) ) {
frontend:: sendBadRequest ( $ aClient , "view_logs requires channel URL parameter" ) ;
return 1 ;
}
my $ query = $ aConnection - > prepare ( qq( select channels.name, servers.name from channels inner join servers on channels.server_id=servers.id where channels.id=?; ) ) ;
$ query - > execute ( $ channelID ) ;
my @ row = $ query - > fetchrow_array ( ) ;
if ( scalar ( @ row ) == 0 ) {
frontend:: sendBadRequest ( $ aClient , "Unknown channel with ID $channelID" ) ;
return 1 ;
}
my $ channelName = $ row [ 0 ] ;
my $ serverName = $ row [ 1 ] ;
my $ logsPath = "logs/" . $ serverName . "/" . $ channelName ;
my $ result = opendir ( my $ folder , $ logsPath ) ;
if ( ! $ result ) {
frontend:: sendBadRequest ( $ aClient , "Channel $channelName on $serverName doesn't have any logs" ) ;
return 1 ;
}
my @ entries = grep ( ! /^\.\.?$/ , readdir ( $ folder ) ) ;
my $ table = "" ;
foreach my $ entry ( @ entries ) {
$ table . = "<tr><td><a href=\"view_log?channel=$channelID&file=$entry\">$entry</a></td></tr>" ;
}
frontend:: sendTemplate ( "templates/view_logs.html" , $ aClient , { "channel" = > $ channelName , "server" = > $ serverName , "logs" = > $ table } ) ;
return 1 ;
}
when ( "/view_log" ) {
my $ channelID = $ aRequest - > { "path" } { "parameters" } { "channel" } ;
if ( ! defined ( $ channelID ) ) {
frontend:: sendBadRequest ( $ aClient , "view_log requires channel URL parameter" ) ;
return 1 ;
}
my $ logFile = $ aRequest - > { "path" } { "parameters" } { "file" } ;
if ( ! defined ( $ channelID ) ) {
frontend:: sendBadRequest ( $ aClient , "view_log requires file URL parameter" ) ;
return 1 ;
}
my $ query = $ aConnection - > prepare ( qq( select channels.name, servers.name from channels inner join servers on channels.server_id=servers.id where channels.id=?; ) ) ;
$ query - > execute ( $ channelID ) ;
my @ row = $ query - > fetchrow_array ( ) ;
if ( scalar ( @ row ) == 0 ) {
frontend:: sendBadRequest ( $ aClient , "Unknown channel with ID $channelID" ) ;
return 1 ;
}
my $ channelName = $ row [ 0 ] ;
my $ serverName = $ row [ 1 ] ;
my $ logFilePath = "logs/" . $ serverName . "/" . $ channelName . "/" . $ logFile ;
my $ result = open ( my $ file , "<" , $ logFilePath ) ;
if ( ! $ result ) {
frontend:: sendBadRequest ( $ aClient , "No log file $logFile for channel $channelName at $serverName" ) ;
return 1 ;
}
my $ content = frontend:: readFullFile ( $ file ) ;
close ( $ file ) ;
my $ response = frontend:: getBaseResponse ( 200 , "OK" ) ;
$ response . = "Content-Type: text/plain;charset=utf-8\r\n" ;
$ response . = "Content-Length: " . length ( $ content ) . "\r\n\r\n" ;
$ response . = $ content ;
$ aClient - > send ( $ response ) ;
}
}
return 0 ;
}
1 ;