aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xChangelog6
-rwxr-xr-xREADME.md2
-rwxr-xr-xlib/MasterWebInterface/Handler/ErrorPages.pm27
-rwxr-xr-xlib/MasterWebInterface/Handler/Games.pm51
-rwxr-xr-xlib/MasterWebInterface/Handler/Json/JsonServerInfo.pm51
-rwxr-xr-xlib/MasterWebInterface/Handler/Json/JsonServerList.pm81
-rwxr-xr-xlib/MasterWebInterface/Handler/Json/Motd.pm2
-rwxr-xr-xlib/MasterWebInterface/Handler/ServInfo.pm33
-rwxr-xr-xlib/MasterWebInterface/Handler/Servers.pm62
-rwxr-xr-xlib/MasterWebInterface/Util/AddressFormat.pm54
10 files changed, 118 insertions, 251 deletions
diff --git a/Changelog b/Changelog
index cd8e1ee..7d8ac30 100755
--- a/Changelog
+++ b/Changelog
@@ -1,4 +1,10 @@
Changelog:
+
+19-07-2022: simplify address format
+ * narrow address matching regexes
+ * json error handling and error status
+ * remove ipv4/ipv6 format rewriting
+ * only accept clean ipv4/ipv6 addresses, no hybrid/converted formats
19-04-2022: list Star Trek Bridge Commander games
* minor sanity check bypassed because bcommander has hostport 0 by default
diff --git a/README.md b/README.md
index 314e445..fd2bbf7 100755
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ This repository contains software for a web interface to display information obt
* `DBI`
* `DBD::SQLite`
* `TUWF`
- * `JSON`
+ * `JSON:XS`
* `Image::Size` (optional for style generation)
* `AnyEvent` (optional for IP to Country lookup)
* `LWP::Simple` (optional for IP to Country lookup)
diff --git a/lib/MasterWebInterface/Handler/ErrorPages.pm b/lib/MasterWebInterface/Handler/ErrorPages.pm
index 7a74355..8c0b5e9 100755
--- a/lib/MasterWebInterface/Handler/ErrorPages.pm
+++ b/lib/MasterWebInterface/Handler/ErrorPages.pm
@@ -12,9 +12,22 @@ TUWF::register(
qr{500} => sub {die "Process died on purpose, but with a lot of text to test if the whole error is correctly displayed on the screen when debug information is enabled in the website configuration, "},
);
+#
+# 404 page or json status
sub handle404
{
my $self = shift;
+
+ # json error status separately
+ if ( $self->reqPath() =~ m/^\/json/ig)
+ {
+ $self->resHeader("Content-Type", "application/json; charset=UTF-8");
+ $self->resJSON({
+ error => 1,
+ in => "url_format"
+ });
+ return;
+ }
$self->resStatus(404);
$self->htmlHeader(title => '404 - Not Found');
@@ -37,10 +50,24 @@ sub handle404
$self->htmlFooter;
}
+#
+# 500 page or json status
sub handle500
{
my($self, $error) = @_;
+ # json error status separately
+ if ( $self->reqPath() =~ m/^\/json/ig)
+ {
+ $self->resHeader("Content-Type", "application/json; charset=UTF-8");
+ $self->resJSON({
+ error => 1,
+ in => "internal_error",
+ internal => ( $self->debug ? $error : () )
+ });
+ return;
+ }
+
$self->resStatus(500);
$self->htmlHeader(title => '500 - Internal Server Error');
$self->htmlSearchBox(title => "Servers", action => "/s", sel => 's', fq => '');
diff --git a/lib/MasterWebInterface/Handler/Games.pm b/lib/MasterWebInterface/Handler/Games.pm
index 50e1d57..affebf6 100755
--- a/lib/MasterWebInterface/Handler/Games.pm
+++ b/lib/MasterWebInterface/Handler/Games.pm
@@ -2,7 +2,6 @@ package MasterWebInterface::Handler::Games;
use strict;
use utf8;
-
use TUWF ':html';
use Exporter 'import';
@@ -11,46 +10,20 @@ TUWF::register(
qr{g(|/all)} => \&gamelist,
);
-################################################################################
-# LIST GAMES
+#
# Generate a list of games in the database (arg: gamename)
-################################################################################
+#
sub gamelist
{
my ($self, $all) = @_;
# process additional query information, such as order, sorting, page, etc
my $f = $self->formValidate(
- {
- get => 's',
- required => 0,
- default => 'num_total',
- enum => [ qw| label gamename num_total | ]
- },
- {
- get => 'o',
- required => 0,
- default => 'd',
- enum => [ 'a','d' ]
- },
- {
- get => 'p',
- required => 0,
- default => 1,
- template => 'page'
- },
- {
- get => 'q',
- required => 0,
- default => '',
- maxlength => 30
- },
- {
- get => 'r',
- required => 0,
- default => 50,
- template => 'page'
- }
+ { get => 's', required => 0, default => 'num_total', enum => [ qw| label gamename num_total | ] },
+ { get => 'o', required => 0, default => 'd', enum => [ 'a','d' ] },
+ { get => 'p', required => 0, default => 1, template => 'page'},
+ { get => 'r', required => 0, default => 50, template => 'page' },
+ { get => 'q', required => 0, default => '', maxlength => 30 },
);
return $self->resNotFound if $f->{_err};
@@ -64,11 +37,7 @@ sub gamelist
all => $all,
);
-
- #
- # page
- #
-
+
$self->htmlHeader(title => "Browse Games");
$self->htmlSearchBox(title => "Games", action => "/g/all", sel => 'g', fq => $f->{q});
@@ -130,8 +99,8 @@ sub gamelist
}
# number of beacons / servers
- td title => ($l->{num_direct} // 0) . "/" . ($l->{num_total} // 0),
- $l->{num_total} // 0;
+ td title => ($l->{num_direct} // 0) . " / " . ($l->{num_total} // 0),
+ $l->{num_direct} // 0;
end;
},
);
diff --git a/lib/MasterWebInterface/Handler/Json/JsonServerInfo.pm b/lib/MasterWebInterface/Handler/Json/JsonServerInfo.pm
index e6f5b44..5669003 100755
--- a/lib/MasterWebInterface/Handler/Json/JsonServerInfo.pm
+++ b/lib/MasterWebInterface/Handler/Json/JsonServerInfo.pm
@@ -5,21 +5,16 @@ use Exporter 'import';
use JSON;
TUWF::register(
- qr{json/(.[\w]{1,20})/([\:\.\w]{9,35})} => \&json_serverinfo,
+ qr{json/([\w]{1,20})/(\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\w{4}):(\d{1,5})} => \&json_serverinfo, # ipv6
+ qr{json/([\w]{1,20})/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d{1,5})} => \&json_serverinfo, # ipv4
);
-################################################################################
-# Server Info
-# Show server info for an individual server
-# Same as &server_info, but with json output.
-# returns "error:1" if errors occurred
-################################################################################
+#
+# Show server info for an individual server.
+#
sub json_serverinfo
{
- my ($self, $gamename, $s_addr, $s_port) = @_;
-
- # parse from ipv4/6 and soft sanity check
- my ($ip, $port) = $self->from_addr_str($s_addr);
+ my ($self, $gamename, $ip, $port) = @_;
# select server from database
my $info = $self->dbGetServerInfo(
@@ -28,20 +23,16 @@ sub json_serverinfo
limit => 1,
)->[0] if ($ip && $port);
- # display an error in case of an invalid IP or port
+ # return error state on invalid IP/port
unless ($info)
{
- my %err = (error => 1, ip => $ip, port => $port);
- my $e = \%err;
- my $json_data = encode_json $e;
- my $json_data_size = keys %$e;
-
- # return json data as the response
- print { $self->resFd() } $json_data;
-
- # set content type at the end
- $self->resHeader("Access-Control-Allow-Origin", "*");
$self->resHeader("Content-Type", "application/json; charset=UTF-8");
+ $self->resJSON({
+ error => 1,
+ in => "not_in_db",
+ ip => $ip,
+ port => $port,
+ });
return;
}
@@ -54,14 +45,9 @@ sub json_serverinfo
$players{"player_$i"} = $pl_list->[$i];
}
- use Data::Dumper 'Dumper';
- my $str = Dumper $pl_list;
-
- # merge
- #$info = { %$info, %$details } if $details;
+ # merge with rest of info
$info = { %$info, %players } if %players;
-
# find the correct thumbnail, otherwise game default, otherwise 333 default
my $mapname = lc $info->{mapname};
@@ -83,17 +69,10 @@ sub json_serverinfo
# 333networks default
$info->{mapurl} = "/map/default/333networks.jpg";
}
-
- # encode
- my $json_data = encode_json $info;
- my $json_data_size = keys %$info;
# return json data as the response
- print { $self->resFd() } $json_data;
-
- # set content type and allow off-domain access (for example jQuery)
- $self->resHeader("Access-Control-Allow-Origin", "*");
$self->resHeader("Content-Type", "application/json; charset=UTF-8");
+ $self->resJSON($info);
}
1;
diff --git a/lib/MasterWebInterface/Handler/Json/JsonServerList.pm b/lib/MasterWebInterface/Handler/Json/JsonServerList.pm
index 7781d94..702a02e 100755
--- a/lib/MasterWebInterface/Handler/Json/JsonServerList.pm
+++ b/lib/MasterWebInterface/Handler/Json/JsonServerList.pm
@@ -5,15 +5,12 @@ use Exporter 'import';
use JSON;
TUWF::register(
- qr{json/(.[\w]{1,20})} => \&serverlist_json,
- qr{json/(.[\w]{1,20})/(all|[0a-z])} => \&serverlist_json,
+ qr{json/([\w]{1,20})} => \&serverlist_json, # valid list
);
-################################################################################
-# LIST SERVERS
+#
# Generate a list of selected games in the database per game (arg: gamename)
-# Same as &serverlist, but with json output.
-################################################################################
+#
sub serverlist_json
{
my($self, $gamename) = @_;
@@ -21,50 +18,26 @@ sub serverlist_json
# sorting, page
my $f = $self->formValidate(
- {
- get => 's',
- required => 0,
- default => 'gamename',
- enum => [ qw| hostname gamename country added gametype numplayers mapname | ]
- },
- {
- get => 'o',
- required => 0,
- default => 'a',
- enum => [ 'a','d' ]
- },
- {
- get => 'p',
- required => 0,
- default => 1,
- template => 'page',
- },
- {
- get => 'q',
- required => 0,
- default => '',
- maxlength => 90
- },
- {
- get => 'r',
- required => 0,
- default => 100,
- template => 'page'
- },
- {
- get => 'g',
- required => 0,
- default => '',
- maxlength => 90
- },
- {
- get => 'a',
- required => 0,
- default => '',
- maxlength => 200
- },
+ { get => 's', required => 0, default => 'gamename', enum => [qw|hostname gamename country added gametype numplayers mapname|] },
+ { get => 'o', required => 0, default => 'a', enum => ['a','d'] },
+ { get => 'p', required => 0, default => 1, template => 'page' },
+ { get => 'r', required => 0, default => 100, template => 'page' },
+ { get => 'q', required => 0, default => '', maxlength => 90 },
+ { get => 'g', required => 0, default => '', maxlength => 90 },
+ { get => 'a', required => 0, default => '', maxlength => 200 },
);
- return $self->resNotFound if $f->{_err};
+
+ # generate json error data if errors in field
+ if ( $f->{_err} )
+ {
+ $self->resHeader("Content-Type", "application/json; charset=UTF-8");
+ $self->resJSON({
+ error => 1,
+ in => "options",
+ options => $f->{_err}
+ });
+ return;
+ }
# load server list from database
my ( $list, $np, $p ) = $self->dbServerListGet(
@@ -77,7 +50,7 @@ sub serverlist_json
updated => $self->{window_time},
gametype => $f->{g},
- # parse extra request parameters like version, populated, etc
+ # parse extra request parameters for ubrowser.333networks.com
($f->{a} =~ m/popserv/ig) ? (popserv => 1) : (),
($f->{a} =~ m/utdemo/ig) ? (utdemo => 1) : (),
);
@@ -90,14 +63,8 @@ sub serverlist_json
}
# return json data as the response
- my $json_data = encode_json [$list, {total => $p, players => $pl}];
- print {
- $self->resFd()
- } $json_data;
-
- # set content type and allow off-domain access (for example jQuery)
- $self->resHeader("Access-Control-Allow-Origin", "*");
$self->resHeader("Content-Type", "application/json; charset=UTF-8");
+ $self->resJSON( [$list, {total => $p, players => $pl}] );
}
1;
diff --git a/lib/MasterWebInterface/Handler/Json/Motd.pm b/lib/MasterWebInterface/Handler/Json/Motd.pm
index c473f12..869ae5f 100755
--- a/lib/MasterWebInterface/Handler/Json/Motd.pm
+++ b/lib/MasterWebInterface/Handler/Json/Motd.pm
@@ -8,7 +8,7 @@ use Exporter 'import';
our @EXPORT = qw| motd_static |;
TUWF::register(
- qr{json/(.[\w]{1,20})/motd} => \&json_motd,
+ qr{json/([\w]{1,20})/motd} => \&json_motd,
);
# Message of the Day for things like the JSON API or updateserver page
diff --git a/lib/MasterWebInterface/Handler/ServInfo.pm b/lib/MasterWebInterface/Handler/ServInfo.pm
index ef9d2cf..fbe5d35 100755
--- a/lib/MasterWebInterface/Handler/ServInfo.pm
+++ b/lib/MasterWebInterface/Handler/ServInfo.pm
@@ -7,21 +7,17 @@ use POSIX 'strftime';
use Exporter 'import';
TUWF::register(
- qr{(.[\w]{1,20})/([\:\.\w]{9,35})} => \&show_server,
+ qr{([\w]{1,20})/(\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\w{4}):(\d{1,5})} => \&show_server, #ipv6
+ qr{([\w]{1,20})/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d{1,5})} => \&show_server, #ipv4
);
-################################################################################
+#
# Display server information
-# Verify if game and server (ip:hostport) exist. Display as many available
-# values as possible.
-# Display error pages if not found or incorrect.
+#
################################################################################
sub show_server
{
- my ($self, $gamename, $s_addr) = @_;
-
- # parse from ipv4/6 and soft sanity check
- my ($ip, $port) = $self->from_addr_str($s_addr);
+ my ($self, $gamename, $ip, $port) = @_;
# select server from database
my $info = $self->dbGetServerInfo(
@@ -66,7 +62,7 @@ sub show_server
p;
txt "You tried to access ";
- span class => "hilit", $self->to_ipv4_str($s_addr) // "[no ip]";
+ span class => "hilit", $ip // "[no ip]";
txt " in ";
span class => "hilit", $gamename;
txt ".";
@@ -212,7 +208,7 @@ sub show_server
Tr;
td "Address:";
td title => $info->{queryport} // 0;
- txt $self->to_ipv4_str($info->{ip}) // "0.0.0.0";
+ txt $info->{ip} // "0.0.0.0";
txt ":";
txt $info->{hostport} // 0;
end;
@@ -444,7 +440,20 @@ sub show_server
a href => "http://333networks.com/json", title => "For more info, click to go to 333networks.com/json", "Json API";
end;
end;
- td ($self->{site_url} . "/json/" . $gamename . "/" . ( $self->to_ipv4_str($info->{ip}) // "0.0.0.0" ) . ":" . ($info->{hostport} // 0));
+ td;
+ a href => ($self->{site_url} . "/json/" . $gamename . "/" . ($info->{ip} // "0.0.0.0") . ":" . ($info->{hostport} // 0) ),
+ ($self->{site_url} . "/json/" . $gamename . "/" . ($info->{ip} // "0.0.0.0") . ":" . ($info->{hostport} // 0) );
+ end;
+
+ Tr;
+ th;
+ txt "Server Banner:";
+ end;
+ end;
+ td;
+ a href => ($self->{site_url} . "/png/" . $gamename . "/" . ( $info->{ip} // "0.0.0.0" ) . ":" . ($info->{hostport} // 0)),
+ ($self->{site_url} . "/png/" . $gamename . "/" . ( $info->{ip} // "0.0.0.0" ) . ":" . ($info->{hostport} // 0));
+ end;
end;
end; # mainbox details
diff --git a/lib/MasterWebInterface/Handler/Servers.pm b/lib/MasterWebInterface/Handler/Servers.pm
index c360683..98d27df 100755
--- a/lib/MasterWebInterface/Handler/Servers.pm
+++ b/lib/MasterWebInterface/Handler/Servers.pm
@@ -5,15 +5,14 @@ use TUWF ':html';
use Exporter 'import';
TUWF::register(
- qr{} => \&serverlist,
- qr{s} => \&serverlist,
- qr{s/(.[\w]{1,20})} => \&serverlist,
+ qr{} => \&serverlist,
+ qr{s} => \&serverlist,
+ qr{s/([\w]{1,20})} => \&serverlist,
);
-################################################################################
-# List servers
+#
# Generate a list of selected games in the database per game (arg: gamename)
-################################################################################
+#
sub serverlist
{
my($self, $gamename) = @_;
@@ -21,42 +20,12 @@ sub serverlist
# sorting, page
my $f = $self->formValidate(
- {
- get => 's',
- required => 0,
- default => 'gamename',
- enum => [ qw| hostname gamename country dt_added gametype numplayers mapname | ]
- },
- {
- get => 'o',
- required => 0,
- default => 'a',
- enum => [ 'a','d' ]
- },
- {
- get => 'p',
- required => 0,
- default => 1,
- template => 'page',
- },
- {
- get => 'q',
- required => 0,
- default => '',
- maxlength => 90
- },
- {
- get => 'r',
- required => 0,
- default => 50,
- template => 'page'
- },
- {
- get => 'g',
- required => 0,
- default => '',
- maxlength => 90
- },
+ { get => 's', required => 0, default => 'gamename',enum => [ qw| hostname gamename country dt_added gametype numplayers mapname | ] },
+ { get => 'o', required => 0, default => 'a',enum => [ 'a','d' ] },
+ { get => 'p', required => 0, default => 1, template => 'page',},
+ { get => 'r', required => 0, default => 50, template => 'page' },
+ { get => 'q', required => 0, default => '', maxlength => 90 },
+ { get => 'g', required => 0, default => '', maxlength => 90 },
);
return $self->resNotFound if $f->{_err};
@@ -77,10 +46,6 @@ sub serverlist
# game name description in title
my $gn_desc = $self->dbGetGameDesc($gamename) // $gamename;
- #
- # page
- #
-
# Write page
$self->htmlHeader(title => "Browse $gn_desc game servers");
$self->htmlSearchBox(
@@ -90,7 +55,6 @@ sub serverlist
fq => $f->{q}
);
-
#
# server list
$self->htmlBrowse(
@@ -128,8 +92,8 @@ sub serverlist
title => $country,
'';
- # server name
- my $ip = $self->to_ipv4_str($l->{ip});
+ # server name (and defaults)
+ my $ip = $l->{ip} // "0.0.0.0";
my $hp = $l->{hostport} // 0;
my $gn = $l->{gamename} // "";
td class => "tc2";
diff --git a/lib/MasterWebInterface/Util/AddressFormat.pm b/lib/MasterWebInterface/Util/AddressFormat.pm
deleted file mode 100755
index 68cf82c..0000000
--- a/lib/MasterWebInterface/Util/AddressFormat.pm
+++ /dev/null
@@ -1,54 +0,0 @@
-package MasterWebInterface::Util::AddressFormat;
-use strict;
-use warnings;
-use TUWF ':html';
-use Exporter 'import';
-our @EXPORT = qw| from_addr_str
- to_ipv4_str |;
-
-################################################################################
-# parse incoming addresses to IPv6 type used by MasterServer-Qt5 and port
-# parses IPv4 to ::ffff:0.0.0.0 and port
-# this is only a semi-sanity check -- invalid values (like port > 65535)
-# are ignored since they will simply not be found in the database.
-################################################################################
-sub from_addr_str {
- my ($self, $str_addr) = @_;
- my ($ip, $port);
-
- # ::ffff:127.0.0.1:7778
- if ($str_addr =~ /^::ffff:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,5}$/)
- {
- # ipv4 in ipv6 format is already in the correct format
- return ($ip, $port) = $str_addr =~ m/^(::ffff:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d{1,5})$/;
- }
-
- # ipv6 (without leading ::) and trailing :7778 / port
- if ($str_addr =~ /^\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\d{1,5}$/)
- {
- # ipv6 already in the correct format
- return ($ip, $port) = $str_addr =~ m/^(\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\w{4}):(\d{1,5})$/;
- }
-
- # ipv4 (127.0.0.1:7778)
- if ($str_addr =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,5}$/)
- {
- # rewrite to ::ffff:127.0.0.1
- ($ip, $port) = $str_addr =~ m/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d{1,5})$/;
- return ("::ffff:".$ip, $port);
- }
-
- # failure
- return ("0.0.0.0", 0);
-}
-
-# write ::ffff:0.0.0.0 to 0.0.0.0 format if possible
-# return ipv6 addresses untouched
-sub to_ipv4_str
-{
- my ($self, $str_addr) = @_;
- $str_addr =~ s/^::ffff://;
- return $str_addr;
-}
-
-1;