diff options
Diffstat (limited to 'Starserver/NetAdminServer.cpp')
-rw-r--r-- | Starserver/NetAdminServer.cpp | 784 |
1 files changed, 784 insertions, 0 deletions
diff --git a/Starserver/NetAdminServer.cpp b/Starserver/NetAdminServer.cpp new file mode 100644 index 0000000..7e82801 --- /dev/null +++ b/Starserver/NetAdminServer.cpp @@ -0,0 +1,784 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. + + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + HTTP Servlet Engine for Multiplayer Admin +*/ + + +#include "NetAdminServer.h" +#include "NetLobbyServer.h" +#include "NetServerConfig.h" +#include "NetClientConfig.h" +#include "NetAdminChat.h" +#include "NetUser.h" +#include "NetChat.h" + +#include "HttpServlet.h" +#include "NetLayer.h" + +#include "DataLoader.h" +#include "FormatUtil.h" +#include "MachineInfo.h" +#include "VersionInfo.h" + +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ + +class NetAdminLogin : public NetAdminServlet +{ +public: + NetAdminLogin() { } + virtual ~NetAdminLogin() { } + + virtual bool DoGet(HttpRequest& request, HttpResponse& response) { + NetServerConfig* config = NetServerConfig::GetInstance(); + + Text admin_name = "system"; + Text admin_pass = "manager"; + + if (config) { + admin_name = config->GetAdminName(); + admin_pass = config->GetAdminPass(); + } + + Text name = request.GetParam("user"); + Text pass = request.GetParam("pass"); + + Sleep(500); + + if (CheckUser(request, response)) { + response.SetStatus(HttpResponse::SC_TEMPORARY_REDIRECT); + response.SetHeader("MIME-Version", "1.0"); + response.SetHeader("Content-Type", "text/html"); + response.SetHeader("Cache-Control", "no-cache"); + response.SetHeader("Expires", "-1"); + response.SetHeader("Location", "/home"); + + response.SetContent(GetHead("Login") + + "<body><br>You are already logged in.<br>" + + GetBodyClose()); + } + + else if (name == admin_name && pass == admin_pass) { + user = new NetUser(name); + user->SetAddress(request.GetClientAddr()); + + if (session) + user->SetSessionID(session->GetID()); + + admin->AddUser(user); + + response.SetStatus(HttpResponse::SC_TEMPORARY_REDIRECT); + response.SetHeader("MIME-Version", "1.0"); + response.SetHeader("Content-Type", "text/html"); + response.SetHeader("Cache-Control", "no-cache"); + response.SetHeader("Expires", "-1"); + response.SetHeader("Location", "/home"); + + response.SetContent(GetHead("Login") + + "<body><br>You have successfully logged in.<br>" + + GetBodyClose()); + } + + else { + response.SetStatus(HttpResponse::SC_OK); + response.SetHeader("MIME-Version", "1.0"); + response.SetHeader("Content-Type", "text/html"); + response.SetHeader("Cache-Control", "no-cache"); + response.SetHeader("Expires", "-1"); + + response.SetContent(GetHead("Login") + + GetTitleBar(0, "onLoad=\"self.focus();document.loginForm.user.focus();\"") + + GetContent() + + GetBodyClose()); + } + + return true; + } + + virtual Text GetContent() { Text content = + " <table border=\"0\" cellspacing=\"0\" cellpadding=\"4\" align=\"left\" width =\"100%\">\n\ + <tr>\n\ + <td width=\"100\"> </td>\n\ + <td valign=\"top\" align=\"left\" width=\"400\"><br><br>\n\ + <span class=\"subhead\">Welcome to the Starshatter Server!</span><br><br>\n\ + <span class=\"std\">Login to access the server <b>"; + + NetServerConfig* config = NetServerConfig::GetInstance(); + if (config) + content += config->Name(); + else + content += "server"; + + content += "</b></span><br>\n\ + <form name=\"loginForm\" method=\"get\" action=\"/login\">\n\ + <table border=\"0\" cellspacing=\"0\" cellpadding=\"4\" width=\"100\">\n\ + <tr>\n\ + <td align=\"left\" valign=\"middle\" width=\"80\"><span class=\"std\">Username:</span></td>\n\ + <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"user\" size=\"25\"></td>\n\ + </tr>\n\ + <tr>\n\ + <td align=\"left\" valign=\"middle\" width=\"80\"><span class=\"std\">Password:</span></td>\n\ + <td align=\"left\" valign=\"middle\"><input type=\"password\" name=\"pass\" size=\"25\"></td>\n\ + </tr>\n\ + <tr>\n\ + <td> </td>\n\ + <td align=\"right\"><input type=\"submit\" value=\"Login\"></td>\n\ + </tr>\n\ + </table>\n\ + </form>\n\ + <td> </td>\n\ + </tr>\n\ +</table>\n"; + + return content; + } +}; + +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ + +class NetAdminFile : public NetAdminServlet +{ +public: + NetAdminFile() { } + virtual ~NetAdminFile() { } + + virtual bool DoGet(HttpRequest& request, HttpResponse& response) { + if (!CheckUser(request, response)) + return true; + + Text content; + Text path = request.GetParam("path"); + Text name = request.GetParam("name"); + + if (name.length()) { + BYTE* buffer = 0; + DataLoader* loader = DataLoader::GetLoader(); + + if (loader) { + bool use_file_system = loader->IsFileSystemEnabled(); + + loader->UseFileSystem(true); + loader->SetDataPath(path); + int len = loader->LoadBuffer(name, buffer); + + if (len) { + content = Text((const char*) buffer, len); + } + + loader->ReleaseBuffer(buffer); + loader->SetDataPath(0); + loader->UseFileSystem(use_file_system); + } + } + + response.SetStatus(HttpResponse::SC_OK); + response.AddHeader("MIME-Version", "1.0"); + response.AddHeader("Cache-Control", "no-cache"); + response.AddHeader("Expires", "-1"); + response.AddHeader("Content-Type", "text/plain"); + response.SetContent(content); + + return true; + } +}; + +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ + +class NetAdminUserList : public NetAdminServlet +{ +public: + NetAdminUserList() { } + virtual ~NetAdminUserList() { } + + virtual bool DoGet(HttpRequest& request, HttpResponse& response) { + if (CheckUser(request, response)) { + response.SetStatus(HttpResponse::SC_OK); + response.SetHeader("MIME-Version", "1.0"); + response.SetHeader("Content-Type", "text/html"); + response.SetHeader("Cache-Control", "no-cache"); + response.SetHeader("Expires", "-1"); + + response.SetContent(GetHead("User List") + + GetTitleBar() + + GetContent() + + GetBodyClose()); + } + + return true; + } + + virtual Text GetContent() { + Text content = + "<script LANGUAGE=\"JavaScript\">\n\ +<!--\n\ +function doConfirm() {\n\ +return confirm(\"Are you sure you want to ban this player?\");\n\ +}\n\ +// -->\n\ +</script>\n\ +<div class=\"content\">\n\ +<table border=\"0\" width=\"95%\">\n\ + <tr class=\"heading\">\n\ + <td nowrap valign=\"middle\" align=\"left\">\n\ + <span class=\"heading\"> User List</span>\n\ + </td>\n\ + </tr>\n\ +</table>\n\n"; + + content += + " <table border=\"0\" width=\"95%\" class=\"std\">\n\ + <tr>\n\ + <td nowrap width=\"1%\"> </td>\n\ + <td nowrap width=\"20%\" valign=\"middle\" align=\"left\"><b>Name</b></td>\n\ + <td nowrap width=\"10%\" valign=\"middle\" align=\"left\"><b>Address</b></td>\n\ + <td nowrap width=\"10%\" valign=\"middle\" align=\"center\"><b>Is Host</b></td>\n\ + <td nowrap width=\"20%\" valign=\"middle\" align=\"left\"><b>Squadron</b></td>\n\ + <td nowrap width=\"20%\" valign=\"middle\" align=\"center\"><b>Stats</b></td>\n\ + <td nowrap width=\"19%\" valign=\"middle\" align=\"center\"><b>Ban</b></td>\n\ + <td></td>\n\ +</tr>\n"; + + NetLobbyServer* lobby = NetLobbyServer::GetInstance(); + + if (lobby) { + ListIter<NetUser> u_iter = lobby->GetUsers(); + while (++u_iter) { + NetUser* u = u_iter.value(); + NetAddr a = u->GetAddress(); + + char addr_dotted[32]; + char addr_hex[16]; + char user_stats[16]; + + sprintf_s(addr_dotted, "%d.%d.%d.%d", a.B1(), a.B2(), a.B3(), a.B4()); + sprintf_s(addr_hex, "%08x", a.IPAddr()); + sprintf_s(user_stats, "%d / %d / %d", u->Missions(), u->Kills(), u->Losses()); + + content += "<tr>\n<td nowrap width=\"1%\"> </td>\n\ + <td nowrap valign=\"middle\" align=\"left\">"; + content += u->Name(); + content += "</td><td nowrap valign=\"middle\" align=\"left\">"; + content += addr_dotted; + content += "</td><td nowrap valign=\"middle\" align=\"center\">"; + content += u->IsHost() ? "*" : " "; + content += "</td><td nowrap valign=\"middle\" align=\"left\">"; + content += u->Squadron(); + content += "</td><td nowrap valign=\"middle\" align=\"center\">"; + content += user_stats; + content += "</td><td nowrap valign=\"middle\" align=\"center\">"; + content += "<a onclick=\"return doConfirm()\" href=\"/ban?name="; + content += HttpRequest::EncodeParam(u->Name()); + content += "&addr="; + content += addr_hex; + content += "\">BAN</a></td></tr>\n"; + } + } + + content += " </table>\n\n"; + + content += "</div>\n\n"; + content += GetCopyright(); + return content; + } +}; + +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ + +class NetAdminBanUser : public NetAdminServlet +{ +public: + NetAdminBanUser() { } + virtual ~NetAdminBanUser() { } + + virtual bool DoGet(HttpRequest& request, HttpResponse& response) { + if (CheckUser(request, response)) { + Text name = request.GetParam("name"); + bool completed = false; + + NetLobbyServer* lobby = NetLobbyServer::GetInstance(); + + if (lobby) { + ListIter<NetUser> u_iter = lobby->GetUsers(); + while (++u_iter && !completed) { + NetUser* u = u_iter.value(); + + if (u->Name() == name) { + NetLobbyServer* nls = NetLobbyServer::GetInstance(); + + if (nls) { + nls->BanUser(u); + completed = true; + } + } + } + } + + response.SetStatus(HttpResponse::SC_TEMPORARY_REDIRECT); + response.SetHeader("MIME-Version", "1.0"); + response.SetHeader("Content-Type", "text/html"); + response.SetHeader("Cache-Control", "no-cache"); + response.SetHeader("Expires", "-1"); + response.SetHeader("Location", "/users"); + + response.SetContent(GetHead("User List") + + GetTitleBar() + + "<div class=\"content\">User Banned.<br></div>" + + GetBodyClose()); + } + + return true; + } +}; + +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ + +static NetAdminServer* net_Admin_server = 0; + +NetAdminServer* +NetAdminServer::GetInstance(WORD port) +{ + if (!net_Admin_server && port > 0) + net_Admin_server = new NetAdminServer(port); + + return net_Admin_server; +} + +NetAdminServer::NetAdminServer(WORD port) +: HttpServletExec(port) +{ + http_server_name = Text("Starshatter NetAdminServer ") + versionInfo; +} + +NetAdminServer::~NetAdminServer() +{ + if (net_Admin_server == this) + net_Admin_server = 0; +} + +// +--------------------------------------------------------------------+ + +HttpServlet* +NetAdminServer::GetServlet(HttpRequest& request) +{ + Text path = request.URI(); + path.setSensitive(false); + + if (path.indexOf("/login") == 0) + return new NetAdminLogin; + + if (path.indexOf("/chat") == 0) + return new NetAdminChat; + + if (path.indexOf("/file") == 0) + return new NetAdminFile; + + if (path.indexOf("/user") == 0) + return new NetAdminUserList; + + if (path.indexOf("/ban") == 0) + return new NetAdminBanUser; + + return new NetAdminServlet; +} + +// +-------------------------------------------------------------------+ + +void +NetAdminServer::AddChat(NetUser* user, const char* msg) +{ + if (user && msg && *msg) { + NetLobbyServer* lobby = NetLobbyServer::GetInstance(); + + if (lobby) + lobby->AddChat(user, msg); + } +} + +ListIter<NetChatEntry> +NetAdminServer::GetChat() +{ + NetLobbyServer* lobby = NetLobbyServer::GetInstance(); + + if (lobby) + return lobby->GetChat(); + + static List<NetChatEntry> idle_chatter; + return idle_chatter; +} + +// +-------------------------------------------------------------------+ + +void +NetAdminServer::AddUser(NetUser* user) +{ + if (user && !admin_users.contains(user)) + admin_users.append(user); +} + +void +NetAdminServer::DelUser(NetUser* user) +{ + if (user) { + admin_users.remove(user); + delete user; + } +} + +int +NetAdminServer::NumUsers() +{ + return admin_users.size(); +} + + +List<NetUser>& +NetAdminServer::GetUsers() +{ + return admin_users; +} + +bool +NetAdminServer::HasHost() +{ + bool result = false; + + NetLobbyServer* lobby = NetLobbyServer::GetInstance(); + + if (lobby) + result = lobby->HasHost(); + + return result; +} + +NetUser* +NetAdminServer::FindUserBySession(Text id) +{ + ListIter<NetUser> iter = admin_users; + while (++iter) { + NetUser* u = iter.value(); + if (u->GetSessionID() == id) + return u; + } + + return 0; +} + +void +NetAdminServer::DoSyncedCheck() +{ + ListIter<NetUser> iter = admin_users; + while (++iter) { + NetUser* u = iter.value(); + + bool found = false; + + ListIter<HttpSession> s_iter = sessions; + while (++s_iter && !found) { + HttpSession* s = s_iter.value(); + + if (s->GetID() == u->GetSessionID()) + found = true; + } + + if (!found) + delete iter.removeItem(); + } +} + + +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ + +NetAdminServlet::NetAdminServlet() +{ + admin = NetAdminServer::GetInstance(); + user = 0; +} + +// +-------------------------------------------------------------------+ + +bool +NetAdminServlet::DoGet(HttpRequest& request, HttpResponse& response) +{ + if (CheckUser(request, response)) { + + if (request.URI() == "/home") + response.SetStatus(HttpResponse::SC_OK); + else + response.SetStatus(HttpResponse::SC_TEMPORARY_REDIRECT); + + response.SetHeader("MIME-Version", "1.0"); + response.SetHeader("Content-Type", "text/html"); + response.SetHeader("Cache-Control", "no-cache"); + response.SetHeader("Expires", "-1"); + response.SetHeader("Location", "/home"); + + response.SetContent(GetHead() + + GetTitleBar(GetStatLine()) + + GetContent() + + GetBodyClose()); + } + + return true; +} + +// +-------------------------------------------------------------------+ + +bool +NetAdminServlet::CheckUser(HttpRequest& request, HttpResponse& response) +{ + if (!user) { + if (session) + user = admin->FindUserBySession(session->GetID()); + + if (!user) { + response.SetStatus(HttpResponse::SC_TEMPORARY_REDIRECT); + response.SetHeader("MIME-Version", "1.0"); + response.SetHeader("Content-Type", "text/plain"); + response.SetHeader("Cache-Control", "no-cache"); + response.SetHeader("Expires", "-1"); + response.SetHeader("Location", "/login"); + response.SetContent("You are not logged in."); + } + } + + return user != 0; +} + +// +-------------------------------------------------------------------+ + +Text +NetAdminServlet::GetCSS() +{ + return + + "body { font-family:arial,helvetica,sans-serif; color:black; background-color:white }\n\ +a:link { text-decoration:none; font-weight:normal; font-size:10pt; color:black }\n\ +a:visited { text-decoration:none; font-weight:normal; font-size:10pt; color:black }\n\ +a:hover { text-decoration:underline; font-weight:normal; font-size:10pt; color:black }\n\ +.std { font-size:10pt }\n\ +.tiny { font-size:8pt }\n\ +.heading { font-size:14pt; font-weight:bold; background-color:#99BBEE }\n\ +.subhead { font-size:11pt; font-weight:bold }\n\ +.status { font-size:10pt; color:white }\n\ +.content { padding-right: 4pt; padding-left: 4pt; padding-bottom: 4pt; padding-top: 4pt; margin: 4pt; }\n\ +.copy { font-size:8pt; }\n\ +.top-bar { color: white; background-color: #336699 }\n\ +.top-line { color: yellow; background-color: black }\n\ +.topbarbig { line-height:24px; color:white; font-size:18px; font-weight:bold; }\n\ +.topbarsmall { line-height:18px; color:white; font-size:14px; }\n"; +} + +Text +NetAdminServlet::GetHead(const char* title) +{ + Text head = "<html>\n<head>\n<title>Starshatter Server"; + + if (title && *title) { + head += " - "; + head += title; + } + + head += "</title>\n<style type=\"text/css\" media=\"screen\">\n"; + head += GetCSS(); + head += "</style>\n</head>\n"; + + return head; +} + +Text +NetAdminServlet::GetBody() +{ + return GetTitleBar(GetStatLine()) + + GetContent() + + GetBodyClose(); +} + +Text +NetAdminServlet::GetTitleBar(const char* statline, const char* onload) +{ + Text bar = "<body "; + + if (onload && *onload) + bar += onload; + + bar += " leftmargin=\"0\" topmargin=\"0\" marginwidth=\"0\" marginheight=\"0\">\n\ +<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" width=\"100%\" class=\"top-bar\">\n\ + <tr height=\"50\">\n\ + <td> </td>\n\ + <td valign=\"middle\" align=\"left\">\n\ + <span class=\"topbarsmall\">Administration Console</span><br>\n"; + + if (statline) { + bar += "<a href=\"/home\">"; + } + + bar += "<span class=\"topbarbig\">Starshatter Server "; + bar += versionInfo; + bar += "</span>"; + + if (statline) { + bar += "</a>"; + } + + bar += "\n\ + </td>\n\ + </tr>\n\ + <tr class=\"top-line\">\n\ + <td colspan=\"2\">"; + + if (statline && *statline) + bar += statline; + else + bar += " "; + + bar += "</td>\n\ + </tr>\n\ +</table>\n\n"; + + return bar; +} + +Text +NetAdminServlet::GetStatLine() +{ + NetServerConfig* config = NetServerConfig::GetInstance(); + + Text line = + " <table width=\"100%\" cellspacing=\"0\" cellpadding=\"2\" border=\"0\">\n\ + <tr>\n\ + <td nowrap width=\"33%\" class=\"top-line\" align=\"left\">\n\ + <span class=\"status\"> Connected to <b>"; + + char buffer[256]; + sprintf_s(buffer, "%s:%d", config->Name().data(), config->GetAdminPort()); + line += buffer; + + line += "</b></span>\n\ + </td>\n\ + <td nowrap width=\"34%\" class=\"top-line\" align=\"center\">\n\ + <span class=\"status\">Server Mode: <b>"; + + NetLobbyServer* lobby = NetLobbyServer::GetInstance(); + if (lobby) { + switch (lobby->GetStatus()) { + default: + case NetServerInfo::OFFLINE: line += "Offline"; break; + case NetServerInfo::LOBBY: line += "Lobby"; break; + case NetServerInfo::BRIEFING: line += "Briefing"; break; + case NetServerInfo::ACTIVE: line += "Active"; break; + case NetServerInfo::DEBRIEFING: line += "Debriefing"; break; + case NetServerInfo::PERSISTENT: line += "PERSISTENT"; break; + } + } + else { + line += "Unknown"; + } + + line += "</b></span>\n\ + </td>\n\ + <td nowrap width=\"33%\" class=\"top-line\" align=\"right\">\n\ + <span class=\"status\">"; + + line += FormatTimeString(); + + line += " </span>\n\ + </td>\n\ + </tr>\n\ + </table>\n"; + + return line; +} + +Text +NetAdminServlet::GetContent() +{ + Text content = + "<script LANGUAGE=\"JavaScript\">\n\ +<!--\n\ +function doConfirm() {\n\ +return confirm(\"Are you sure you want to do this?\");\n\ +}\n\ +// -->\n\ +</script>\n\ +<div class=\"content\">\n\ +<table border=\"0\" width=\"95%\">\n\ + <tr class=\"heading\">\n\ + <td nowrap valign=\"middle\" align=\"left\">\n\ + <span class=\"heading\"> Game Admin Functions</span>\n\ + </td>\n\ + </tr>\n\ +</table>\n\n\ +<table border=\"0\" width=\"95%\">\n\ + <tr>\n\ + <td nowrap width=\"1%\"> </td>\n\ + <td nowrap width=\"33%\" valign=\"middle\" align=\"left\">\n\ + <a href=\"/chat\">Lobby Chat</a>\n\ + </td>\n\ + <td nowrap width=\"33%\" valign=\"middle\" align=\"left\">\n\ + <a href=\"/home\">Mission List</a>\n\ + </td>\n\ + <td></td>\n\ + </tr>\n\ + <tr>\n\ + <td nowrap width=\"1%\"> </td>\n\ + <td nowrap width=\"33%\" valign=\"middle\" align=\"left\">\n\ + <a href=\"/file?name=errlog.txt\">View Error Log</a>\n\ + </td>\n\ + <td nowrap width=\"33%\" valign=\"middle\" align=\"left\">\n\ + <a href=\"/users\">Player List</a>\n\ + </td>\n\ + <td></td>\n\ + </tr>\n\ + <tr>\n\ + <td nowrap width=\"1%\"> </td>\n\ + <td nowrap width=\"33%\" valign=\"middle\" align=\"left\">\n\ + <a href=\"/file?name=serverlog.txt\">View Server Log</a>\n\ + </td>\n\ + <td nowrap width=\"33%\" valign=\"middle\" align=\"left\">\n\ + <a href=\"/home\">Ban List</a>\n\ + </td>\n\ + <td></td>\n\ + </tr>\n\ + <tr>\n\ + <td nowrap width=\"1%\"> </td>\n\ + <td nowrap width=\"33%\" valign=\"middle\" align=\"left\"></td>\n\ + <td nowrap width=\"33%\" valign=\"middle\" align=\"left\"></td>\n\ + <td></td>\n\ +</tr>\n\ +</table>\n\n"; + + content += "</div>\n\n"; + content += GetCopyright(); + return content; +} + +Text +NetAdminServlet::GetBodyClose() +{ + return "\n\n</body>\n</html>\n"; +} + +Text +NetAdminServlet::GetCopyright() +{ + return "<br><span class=\"copy\"> Copyright © 1997-2004 Destroyer Studios. All rights reserved.</span><br>"; +} |