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
2023-09-11 18:55:32 +02:00
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
2023-09-08 22:05:21 +02:00
# 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
2023-09-11 18:55:32 +02:00
# GNU Affero General Public License for more details.
2023-09-08 22:05:21 +02:00
2023-09-11 18:55:32 +02:00
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
2023-09-08 22:05:21 +02:00
package frontend_routes ;
use lib "." ;
use frontend_session ;
2023-09-12 10:19:46 +02:00
use logger ;
2023-09-08 22:05:21 +02:00
use Digest::SHA ;
2023-09-14 18:13:02 +02:00
use threads::shared ;
2023-09-08 22:05:21 +02:00
use feature qw( switch ) ;
use strict ;
use warnings ;
2023-09-15 21:01:26 +02:00
sub verifyRequestPrivileges {
my $ aRequest = $ _ [ 0 ] ;
my $ aClient = $ _ [ 1 ] ;
my $ aPrivileges = $ _ [ 2 ] ;
my $ aConnection = $ _ [ 3 ] ;
if ( ! defined ( $ aRequest - > { "cookies" } { "session" } ) || ! frontend_session:: isValidSession ( $ aRequest - > { "cookies" } { "session" } ) ) {
frontend:: redirect ( $ aClient , "/" ) ;
return 0 ;
}
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 0 ;
}
if ( ! defined ( $ aRequest - > { "content" } ) ) {
frontend:: sendBadRequest ( $ aClient , "Request content required" ) ;
return 0 ;
}
my $ session = $ frontend_session:: sessions { $ aRequest - > { "cookies" } { "session" } } ;
my $ query = $ aConnection - > prepare ( qq( select privileges from users where name=?; ) ) ;
$ query - > execute ( $ session - > { "username" } ) ;
my @ row = $ query - > fetchrow_array ( ) ;
if ( $ row [ 0 ] < $ aPrivileges ) {
frontend:: sendForbidden ( $ aClient , "Insufficient permissions to perform this operation" ) ;
return 0 ;
}
return 1 ;
}
2023-09-12 20:21:15 +02:00
sub verifyChannelAccess {
my $ aRequest = $ _ [ 0 ] ;
my $ aClient = $ _ [ 1 ] ;
my $ aConnection = $ _ [ 2 ] ;
my $ aChannelID = $ _ [ 3 ] ;
if ( ! defined ( $ aRequest - > { "cookies" } { "session" } ) || ! frontend_session:: isValidSession ( $ aRequest - > { "cookies" } { "session" } ) ) {
frontend:: sendUnauthorized ( $ aClient , "You need to log in to view this resource" ) ;
return 0 ;
}
my $ session = $ frontend_session:: sessions { $ aRequest - > { "cookies" } { "session" } } ;
my $ query = $ aConnection - > prepare ( qq( select id, privileges from users where name=?; ) ) ;
$ query - > execute ( $ session - > { "username" } ) ;
my @ row = $ query - > fetchrow_array ( ) ;
my $ userID = $ row [ 0 ] ;
my $ privileges = $ row [ 1 ] ;
if ( $ privileges > 0 ) {
return 1 ;
}
$ query = $ aConnection - > prepare ( qq( select user_id from accessors where channel_id=$aChannelID and user_id=$userID; ) ) ;
2023-09-18 16:35:22 +02:00
$ query - > execute ( ) ;
2023-09-12 20:21:15 +02:00
@ row = $ query - > fetchrow_array ( ) ;
if ( scalar ( @ row ) == 0 ) {
frontend:: sendForbidden ( $ aClient , "You don't have access to this channel logs" ) ;
return 0 ;
}
return 1 ;
}
2023-09-08 22:05:21 +02:00
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" } ;
2023-09-11 10:12:37 +02:00
$ userbar = "<a href=\"panel\">$username</a> | " ;
2023-09-08 22:05:21 +02:00
$ 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 ] ;
2023-09-12 20:28:06 +02:00
$ channelName =~ s/%23/#/ ;
2023-09-08 22:05:21 +02:00
$ table . = "<tr><td><a href=\"view_logs?channel=$channelID\">$channelName</a></td><td>$serverName</td></tr>" ;
}
2023-09-11 10:12:37 +02:00
my $ privateChannels = "" ;
if ( $ logged ) {
2023-09-12 20:28:06 +02:00
$ query = $ aConnection - > prepare ( qq( select id, privileges from users where name=?; ) ) ;
2023-09-11 10:12:37 +02:00
$ query - > execute ( $ frontend_session:: sessions { $ aRequest - > { "cookies" } { "session" } } { "username" } ) ;
my @ row = $ query - > fetchrow_array ( ) ;
my $ id = $ row [ 0 ] ;
2023-09-12 20:28:06 +02:00
my $ privileges = $ row [ 1 ] ;
if ( $ privileges > 0 ) {
$ query = $ aConnection - > prepare ( qq( select id from channels where public=0; ) ) ;
$ query - > execute ( ) ;
}
else {
$ query = $ aConnection - > prepare ( qq( select channel_id from accessors where user_id=?; ) ) ;
$ query - > execute ( $ id ) ;
}
2023-09-11 10:12:37 +02:00
while ( @ row = $ query - > fetchrow_array ( ) ) {
my $ channelID = $ row [ 0 ] ;
my $ channelQuery = $ aConnection - > prepare ( qq( select channels.name, servers.name from channels inner join servers on channels.server_id=servers.id where channels.id=$channelID; ) ) ;
$ channelQuery - > execute ( ) ;
@ row = $ channelQuery - > fetchrow_array ( ) ;
my $ channelName = $ row [ 0 ] ;
2023-09-12 20:28:06 +02:00
$ channelName =~ s/%23/#/ ;
2023-09-11 10:12:37 +02:00
my $ serverName = $ row [ 1 ] ;
$ privateChannels . = "<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 , "privateChannels" = > $ privateChannels } ) ;
2023-09-08 22:05:21 +02:00
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' } ;
2023-09-11 10:08:12 +02:00
my $ hashedPassword = Digest::SHA:: sha256_hex ( $ parameters { "password" } ) ;
2023-09-08 22:05:21 +02:00
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-10 14:30:40 +02:00
when ( "/panel" ) {
if ( ! defined ( $ aRequest - > { "cookies" } { "session" } ) || ! frontend_session:: isValidSession ( $ aRequest - > { "cookies" } { "session" } ) ) {
frontend:: redirect ( $ aClient , "/" ) ;
return 1 ;
}
my $ session = $ frontend_session:: sessions { $ aRequest - > { "cookies" } { "session" } } ;
my $ query = $ aConnection - > prepare ( qq( select privileges from users where name=?; ) ) ;
$ query - > execute ( $ session - > { "username" } ) ;
my @ row = $ query - > fetchrow_array ( ) ;
my $ privileges = $ row [ 0 ] ;
my $ manageChannelAccess = "" ;
2023-09-14 18:22:14 +02:00
my $ addUser = "" ;
2023-09-10 14:30:40 +02:00
if ( $ privileges >= 1 ) { # moderator
$ manageChannelAccess . = "<h3>Manage channel access</h3>" ;
$ manageChannelAccess . = "<form action=\"manage_access_action\" method=\"POST\">" ;
$ manageChannelAccess . = "<select name=\"user\">" ;
$ query = $ aConnection - > prepare ( qq( select id, name from users; ) ) ;
$ query - > execute ( ) ;
while ( @ row = $ query - > fetchrow_array ( ) ) {
my $ id = $ row [ 0 ] ;
my $ name = $ row [ 1 ] ;
if ( $ name eq $ session - > { "username" } ) {
next ;
}
$ manageChannelAccess . = "<option value=\"$id\">$name</option>" ;
}
$ manageChannelAccess . = "</select>" ;
$ manageChannelAccess . = "<select name=\"channel\">" ;
$ query = $ aConnection - > prepare ( qq( select channels.id, channels.name, servers.name from channels inner join servers on channels.server_id=servers.id; ) ) ;
$ query - > execute ( ) ;
while ( @ row = $ query - > fetchrow_array ( ) ) {
my $ channelID = $ row [ 0 ] ;
my $ channel = $ row [ 1 ] ;
my $ server = $ row [ 2 ] ;
$ manageChannelAccess . = "<option value=\"$channelID\">$channel at $server</option>" ;
}
$ manageChannelAccess . = "</select><br />" ;
$ manageChannelAccess . = "<input name=\"grant\" type=\"submit\" value=\"Grant access\" /> " ;
$ manageChannelAccess . = "<input name=\"revoke\" type=\"submit\" value=\"Revoke access\" />" ;
$ manageChannelAccess . = "</form>" ;
2023-09-14 18:22:14 +02:00
$ addUser . = "<h3>Add user</h3>" ;
$ addUser . = "<form action=\"add_user_action\" method=\"POST\">" ;
$ addUser . = "<input name=\"name\" type=\"text\" placeholder=\"Username\" /><br />" ;
$ addUser . = "<input name=\"password\" type=\"password\" placeholder=\"Password\" /><br />" ;
$ addUser . = "<input name=\"confirmPassword\" type=\"password\" placeholder=\"Confirm password\" /><br />" ;
$ addUser . = "<input name=\"operator\" type=\"checkbox\" />Operator<br />" ;
$ addUser . = "<input type=\"submit\" value=\"Add\" />" ;
$ addUser . = "</form>" ;
2023-09-10 14:30:40 +02:00
}
2023-09-14 18:22:14 +02:00
my $ addServer = "" ;
2023-09-10 14:30:40 +02:00
if ( $ privileges == 2 ) {
2023-09-14 18:22:14 +02:00
$ addServer . = "<h3>Add server</h3>" ;
$ addServer . = "<form action=\"add_server_action\" method=\"POST\">" ;
$ addServer . = "<input name=\"name\" type=\"text\" placeholder=\"Server name\" /><br />" ;
$ addServer . = "<input name=\"address\" type=\"text\" placeholder=\"Server address\" /> " ;
$ addServer . = "<input name=\"port\" type=\"number\" placeholder=\"Server port (optional)\" /><br />" ;
$ addServer . = "<input type=\"submit\" value=\"Add\" />" ;
$ addServer . = "</form>" ;
2023-09-10 14:30:40 +02:00
}
2023-09-14 18:22:14 +02:00
my $ addChannel = "" ;
2023-09-10 14:30:40 +02:00
if ( $ privileges == 2 ) {
2023-09-14 18:22:14 +02:00
$ addChannel . = "<h3>Add channel</h3>" ;
$ addChannel . = "<form action=\"add_channel_action\" method=\"POST\">" ;
$ addChannel . = "<input name=\"channel\" type=\"text\" placeholder=\"Channel\" /> at " ;
$ addChannel . = "<select name=\"server\">" ;
2023-09-10 14:30:40 +02:00
$ query = $ aConnection - > prepare ( qq( select id, name from servers; ) ) ;
$ query - > execute ( ) ;
while ( @ row = $ query - > fetchrow_array ( ) ) {
my $ id = $ row [ 0 ] ;
my $ name = $ row [ 1 ] ;
2023-09-14 18:22:14 +02:00
$ addChannel . = "<option value=\"$id\">$name</option>" ;
2023-09-10 14:30:40 +02:00
}
2023-09-14 18:22:14 +02:00
$ addChannel . = "</select><br />" ;
2023-09-18 10:15:02 +02:00
$ addChannel . = "<input name=\"public\" type=\"checkbox\" />Public<br />" ;
2023-09-14 18:22:14 +02:00
$ addChannel . = "<input type=\"submit\" value=\"Add\" />" ;
$ addChannel . = "</form>" ;
2023-09-10 14:30:40 +02:00
}
2023-09-14 18:22:14 +02:00
frontend:: sendTemplate ( "templates/panel.html" , $ aClient , { "username" = > $ session - > { "username" } , "manageChannelAccess" = > $ manageChannelAccess , "addUser" = > $ addUser , "addServer" = > $ addServer , "addChannel" = > $ addChannel } ) ;
2023-09-10 14:30:40 +02:00
return 1 ;
}
2023-09-10 18:57:44 +02:00
when ( "/change_password_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 $ session = $ frontend_session:: sessions { $ aRequest - > { "cookies" } { "session" } } ;
my % parameters = frontend:: parsePathParameters ( $ aRequest - > { "content" } ) ;
if ( ! defined ( $ parameters { "currentPassword" } ) ) {
frontend:: sendBadRequest ( $ aClient , "Current password parameter required" ) ;
return 1 ;
}
if ( ! defined ( $ parameters { "newPassword" } ) ) {
frontend:: sendBadRequest ( $ aClient , "New password parameter required" ) ;
return 1 ;
}
my $ query = $ aConnection - > prepare ( qq( select password from users where name=?; ) ) ;
$ query - > execute ( $ session - > { "username" } ) ;
my @ row = $ query - > fetchrow_array ( ) ;
my $ password = $ row [ 0 ] ;
2023-09-12 11:38:11 +02:00
if ( $ password ne Digest::SHA:: sha256_hex ( $ parameters { "currentPassword" } ) ) {
2023-09-10 18:57:44 +02:00
frontend:: sendBadRequest ( $ aClient , "Wrong password" ) ;
return 1 ;
}
if ( $ parameters { "newPassword" } eq $ password ) {
frontend:: sendBadRequest ( $ aClient , "New password and current password match" ) ;
return 1 ;
}
$ query = $ aConnection - > prepare ( qq( update users set password=? where name=?; ) ) ;
2023-09-11 10:08:12 +02:00
$ query - > execute ( Digest::SHA:: sha256_hex ( $ parameters { "newPassword" } ) , $ session - > { "username" } ) ;
2023-09-10 18:57:44 +02:00
frontend:: redirect ( $ aClient , "/password_changed.html" ) ;
return 1 ;
}
2023-09-16 17:06:10 +02:00
when ( "/manage_access_action" ) {
if ( ! verifyRequestPrivileges ( $ aRequest , $ aClient , 1 , $ aConnection ) ) {
return 1 ;
}
my % parameters = frontend:: parsePathParameters ( $ aRequest - > { "content" } ) ;
if ( ! defined ( $ parameters { "user" } ) || length ( $ parameters { "user" } ) == 0 ) {
frontend:: sendBadRequest ( $ aClient , "User required" ) ;
return 1 ;
}
if ( ! defined ( $ parameters { "channel" } ) || length ( $ parameters { "channel" } ) == 0 ) {
frontend:: sendBadRequest ( $ aClient , "Channel required" ) ;
return 1 ;
}
if ( defined ( $ parameters { "grant" } ) ) {
my $ query = $ aConnection - > prepare ( qq( select id from channels where id=?; ) ) ;
$ query - > execute ( $ parameters { "channel" } ) ;
my @ row = $ query - > fetchrow_array ( ) ;
if ( scalar ( @ row ) == 0 ) {
frontend:: sendBadRequest ( $ aClient , "Channel with ID $parameters{'channel'} doesn't exist" ) ;
return 1 ;
}
if ( $ row [ 0 ] == 1 ) {
frontend:: sendBadRequest ( $ aClient , "Channel with ID $parameters{'channel'} is public" ) ;
return 1 ;
}
$ query = $ aConnection - > prepare ( qq( select id from users where id=?; ) ) ;
$ query - > execute ( $ parameters { "user" } ) ;
@ row = $ query - > fetchrow_array ( ) ;
if ( scalar ( @ row ) == 0 ) {
frontend:: sendBadRequest ( $ aClient , "User with ID $parameters{'user'} doesn't exist" ) ;
return 1 ;
}
$ query = $ aConnection - > prepare ( qq( select user_id from accessors where user_id=? and channel_id=?; ) ) ;
$ query - > execute ( $ parameters { "user" } , $ parameters { "channel" } ) ;
@ row = $ query - > fetchrow_array ( ) ;
if ( scalar ( @ row ) > 0 ) {
frontend:: sendBadRequest ( $ aClient , "User with ID $parameters{'user'} already has access to channel with ID $parameters{'channel'}" ) ;
return 1 ;
}
$ query = $ aConnection - > prepare ( qq( insert into accessors values ( ?, ? ) ; ) ) ;
$ query - > execute ( $ parameters { "user" } , $ parameters { "channel" } ) ;
frontend:: redirect ( $ aClient , "/channel_access_granted.html" ) ;
}
elsif ( defined ( $ parameters { "revoke" } ) ) {
my $ query = $ aConnection - > prepare ( qq( select id from channels where id=?; ) ) ;
$ query - > execute ( $ parameters { "channel" } ) ;
my @ row = $ query - > fetchrow_array ( ) ;
if ( scalar ( @ row ) == 0 ) {
frontend:: sendBadRequest ( $ aClient , "Channel with ID $parameters{'channel'} doesn't exist" ) ;
return 1 ;
}
$ query = $ aConnection - > prepare ( qq( select id from users where id=?; ) ) ;
$ query - > execute ( $ parameters { "user" } ) ;
@ row = $ query - > fetchrow_array ( ) ;
if ( scalar ( @ row ) == 0 ) {
frontend:: sendBadRequest ( $ aClient , "User with ID $parameters{'user'} doesn't exist" ) ;
return 1 ;
}
$ query = $ aConnection - > prepare ( qq( select user_id from accessors where user_id=? and channel_id=?; ) ) ;
$ query - > execute ( $ parameters { "user" } , $ parameters { "channel" } ) ;
@ row = $ query - > fetchrow_array ( ) ;
if ( scalar ( @ row ) == 0 ) {
frontend:: sendBadRequest ( $ aClient , "User with ID $parameters{'user'} doesn't have access to channel with ID $parameters{'channel'}" ) ;
return 1 ;
}
$ query = $ aConnection - > prepare ( qq( delete from accessors where user_id=? and channel_id=?; ) ) ;
$ query - > execute ( $ parameters { "user" } , $ parameters { "channel" } ) ;
frontend:: redirect ( $ aClient , "/channel_access_revoked.html" ) ;
}
else {
frontend:: sendBadRequest ( $ aClient , "Action (grant or revoke) required" ) ;
}
return 1 ;
}
2023-09-15 21:01:26 +02:00
when ( "/add_user_action" ) {
if ( ! verifyRequestPrivileges ( $ aRequest , $ aClient , 1 , $ aConnection ) ) {
2023-09-12 10:19:46 +02:00
return 1 ;
}
2023-09-15 21:01:26 +02:00
my % parameters = frontend:: parsePathParameters ( $ aRequest - > { "content" } ) ;
if ( ! defined ( $ parameters { "name" } ) || length ( $ parameters { "name" } ) == 0 ) {
frontend:: sendBadRequest ( $ aClient , "Username required" ) ;
2023-09-12 10:19:46 +02:00
return 1 ;
}
2023-09-15 21:01:26 +02:00
if ( ! defined ( $ parameters { "password" } ) || length ( $ parameters { "password" } ) == 0 ) {
frontend:: sendBadRequest ( $ aClient , "Password required" ) ;
2023-09-12 10:19:46 +02:00
return 1 ;
}
2023-09-15 21:01:26 +02:00
if ( ! defined ( $ parameters { "confirmPassword" } ) || length ( $ parameters { "confirmPassword" } ) == 0 ) {
frontend:: sendBadRequest ( $ aClient , "Confirm password required" ) ;
return 1 ;
}
if ( $ parameters { "password" } ne $ parameters { "confirmPassword" } ) {
frontend:: sendBadRequest ( $ aClient , "Password and confirm password don't match" ) ;
return 1 ;
}
my $ query = $ aConnection - > prepare ( qq( select id from users where name=?; ) ) ;
$ query - > execute ( $ parameters { "name" } ) ;
2023-09-12 10:19:46 +02:00
my @ row = $ query - > fetchrow_array ( ) ;
2023-09-15 21:01:26 +02:00
if ( scalar ( @ row ) > 0 ) {
frontend:: sendConflict ( $ aClient , "User $parameters{'name'} already exists" ) ;
return 1 ;
}
frontend:: createUser ( $ parameters { "name" } , $ parameters { "password" } , defined ( $ parameters { "operator" } ) , $ aConnection ) ;
frontend:: redirect ( $ aClient , "/user_added.html" ) ;
return 1 ;
}
when ( "/add_server_action" ) {
if ( ! verifyRequestPrivileges ( $ aRequest , $ aClient , 2 , $ aConnection ) ) {
2023-09-12 10:19:46 +02:00
return 1 ;
}
my % parameters = frontend:: parsePathParameters ( $ aRequest - > { "content" } ) ;
2023-09-15 21:01:26 +02:00
if ( ! defined ( $ parameters { "name" } ) || length ( $ parameters { "name" } ) == 0 ) {
2023-09-12 10:19:46 +02:00
frontend:: sendBadRequest ( $ aClient , "Server name required" ) ;
return 1 ;
}
2023-09-15 21:01:26 +02:00
if ( ! defined ( $ parameters { "address" } ) || length ( $ parameters { "address" } ) == 0 ) {
2023-09-12 10:19:46 +02:00
frontend:: sendBadRequest ( $ aClient , "Server address required" ) ;
return 1 ;
}
my $ port = 6667 ;
if ( defined ( $ parameters { "port" } ) && length ( $ parameters { "port" } ) > 0 ) {
$ port = $ parameters { "port" } ;
}
2023-09-15 21:01:26 +02:00
my $ query = $ aConnection - > prepare ( qq( select id from servers where name=?; ) ) ;
2023-09-12 10:19:46 +02:00
$ query - > execute ( $ parameters { "name" } ) ;
2023-09-15 21:01:26 +02:00
my @ row = $ query - > fetchrow_array ( ) ;
2023-09-12 10:19:46 +02:00
if ( scalar ( @ row ) > 0 ) {
frontend:: sendConflict ( $ aClient , "Server with name $parameters{'name'} already exists" ) ;
return 1 ;
}
$ query = $ aConnection - > prepare ( qq( select id from servers order by rowid desc limit 1; ) ) ;
$ query - > execute ( ) ;
@ row = $ query - > fetchrow_array ( ) ;
my $ lastID = 0 ;
if ( scalar ( @ row ) > 0 ) {
$ lastID = $ row [ 0 ] + 1 ;
}
$ query = $ aConnection - > prepare ( qq( insert into servers values ( $lastID, ?, ?, ? ) ; ) ) ;
$ query - > execute ( $ parameters { "name" } , $ parameters { "address" } , $ port ) ;
frontend:: redirect ( $ aClient , "/server_added.html" ) ;
logger:: createLogger ( $ parameters { "name" } , $ parameters { "address" } , $ port , ( ) ) ;
return 1 ;
}
2023-09-14 18:22:14 +02:00
when ( "/add_channel_action" ) {
2023-09-15 21:01:26 +02:00
if ( ! verifyRequestPrivileges ( $ aRequest , $ aClient , 2 , $ aConnection ) ) {
2023-09-14 18:13:02 +02:00
return 1 ;
}
my % parameters = frontend:: parsePathParameters ( $ aRequest - > { "content" } ) ;
2023-09-16 17:06:10 +02:00
if ( ! defined ( $ parameters { "channel" } ) || length ( $ parameters { "channel" } ) == 0 ) {
2023-09-14 18:13:02 +02:00
frontend:: sendBadRequest ( $ aClient , "Channel name required" ) ;
return 1 ;
}
2023-09-15 21:01:26 +02:00
if ( ! defined ( $ parameters { "server" } ) || length ( $ parameters { "server" } ) == 0 ) {
2023-09-14 18:13:02 +02:00
frontend:: sendBadRequest ( $ aClient , "Server ID required" ) ;
return 1 ;
}
2023-09-18 10:15:02 +02:00
if ( ! defined ( $ parameters { "public" } ) || length ( $ parameters { "public" } ) == 0 ) {
frontend:: sendBadRequest ( $ aClient , "Public required" ) ;
return 1 ;
}
2023-09-14 18:13:02 +02:00
2023-09-15 21:01:26 +02:00
my $ query = $ aConnection - > prepare ( qq( select name from servers where id=?; ) ) ;
2023-09-14 18:13:02 +02:00
$ query - > execute ( $ parameters { "server" } ) ;
2023-09-15 21:01:26 +02:00
my @ row = $ query - > fetchrow_array ( ) ;
2023-09-14 18:13:02 +02:00
if ( scalar ( @ row ) == 0 ) {
frontend:: sendBadRequest ( $ aClient , "Invalid server ID" ) ;
return 1 ;
}
my $ serverName = $ row [ 0 ] ;
$ query = $ aConnection - > prepare ( qq( select id from channels where name=? and server_id=?; ) ) ;
$ query - > execute ( $ parameters { "channel" } , $ parameters { "server" } ) ;
@ row = $ query - > fetchrow_array ( ) ;
$ parameters { "channel" } =~ s/%23/#/ ;
if ( scalar ( @ row ) > 0 ) {
frontend:: sendConflict ( $ aClient , "Channel $parameters{'channel'} already exists on server $serverName" ) ;
return 1 ;
}
$ query = $ aConnection - > prepare ( qq( select id from channels order by rowid desc limit 1; ) ) ;
$ query - > execute ( ) ;
@ row = $ query - > fetchrow_array ( ) ;
my $ lastID = 0 ;
if ( scalar ( @ row ) > 0 ) {
$ lastID = $ row [ 0 ] + 1 ;
}
2023-09-18 10:15:02 +02:00
$ query = $ aConnection - > prepare ( qq( insert into channels values ( $lastID, ?, ?, ? ) ; ) ) ;
$ query - > execute ( $ parameters { "server" } , $ parameters { "channel" } , $ parameters { "public" } ) ;
2023-09-14 18:13:02 +02:00
my $ actionQueue = logger:: getActionQueueByServerName ( $ serverName ) ;
push ( @$ actionQueue , "JOIN" , $ parameters { "channel" } ) ;
frontend:: redirect ( $ aClient , "/channel_added.html" ) ;
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 ;
}
2023-09-12 20:21:15 +02:00
my $ query = $ aConnection - > prepare ( qq( select channels.name, channels.public, servers.name from channels inner join servers on channels.server_id=servers.id where channels.id=?; ) ) ;
2023-09-08 22:05:21 +02:00
$ 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 ] ;
2023-09-12 20:21:15 +02:00
$ channelName =~ s/%23/#/ ;
my $ channelPublic = $ row [ 1 ] ;
if ( ! $ channelPublic && ! verifyChannelAccess ( $ aRequest , $ aClient , $ aConnection , $ channelID ) ) {
return 1 ;
}
my $ serverName = $ row [ 2 ] ;
2023-09-08 22:05:21 +02:00
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 ;
}
2023-09-12 20:21:15 +02:00
my $ query = $ aConnection - > prepare ( qq( select channels.name, channels.public, servers.name from channels inner join servers on channels.server_id=servers.id where channels.id=?; ) ) ;
2023-09-08 22:05:21 +02:00
$ 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 ] ;
2023-09-12 20:21:15 +02:00
$ channelName =~ s/%23/#/ ;
my $ channelPublic = $ row [ 1 ] ;
if ( ! $ channelPublic && ! verifyChannelAccess ( $ aRequest , $ aClient , $ aConnection , $ channelID ) ) {
return 1 ;
}
my $ serverName = $ row [ 2 ] ;
2023-09-08 22:05:21 +02:00
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 ;