62 m_TemplateScript(
"<webadmin_template>"),
63 m_IsInitialized(false),
89 LOGD(
"Initialising WebAdmin...");
118 LOGD(
"Starting WebAdmin...");
135 LOGD(
"Stopping WebAdmin...");
172 return (a_CBWebTab->m_PluginName == a_PluginName);
189 "WebAdmin was previously enabled and now the settings say to disable it."
190 " This will not take effect until you restart the server."
196 "The webadmin is enabled but has no users configured."
197 " To add new users, edit webadmin.ini"
210 LOGWARN(
"Could not load WebAdmin template \"%s\". WebAdmin will not work properly!",
"webadmin/template.lua");
217 LOGWARN(
"Could not load WebAdmin login page \"%s\", using fallback template.",
"webadmin/login_template.html");
221 "<h1>Cuberite WebAdmin</h1>" \
223 "<form method='get' action='webadmin/'>" \
224 "<input type='submit' value='Log in'>" \
239 LOGWARN(
"Regenerating webadmin.ini, all settings will be reset");
263 if (key.rfind(
"User:", 0) == 0)
287 if ((UserPassword ==
"") || (a_Request.
GetAuthPassword() != UserPassword))
289 a_Connection.
SendNeedAuth(
"Cuberite WebAdmin - bad username or password");
296 ASSERT(BareURL.length() > 0);
297 bool ShouldWrapInTemplate = (!BareURL.empty() && (BareURL[1] !=
'~'));
300 auto Data = std::static_pointer_cast<cWebadminRequestData>(a_Request.
GetUserData());
315 if (Data->m_Form.Finish())
317 for (cHTTPFormParser::const_iterator itr = Data->m_Form.begin(), end = Data->m_Form.end(); itr != end; ++itr)
320 HTTPfd.
Value = itr->second;
322 HTTPfd.
Name = itr->first;
329 size_t idxQM = URL.find(
'?');
330 if (idxQM != AString::npos)
334 for (cHTTPFormParser::const_iterator itr = URLParams.begin(), end = URLParams.end(); itr != end; ++itr)
342 if (ShouldWrapInTemplate)
350 a_Connection.
Send(Resp);
351 a_Connection.
Send(Template.c_str(), Template.length());
363 a_Connection.
Send(resp);
364 a_Connection.
Send(page.Content.c_str(), page.Content.length());
378 a_Connection.
Send(Resp);
390 std::replace(FileURL.begin(), FileURL.end(),
'\\',
'/');
393 if (!FileURL.empty() && (FileURL[0] ==
'/'))
395 size_t FirstCharToRead = FileURL.find_first_not_of(
'/');
396 if (FirstCharToRead != AString::npos)
398 FileURL = FileURL.substr(FirstCharToRead);
403 AString Content =
"<h2>404 Not Found</h2>";
404 AString ContentType =
"text/html";
405 AString Path =
"webadmin/files/" + FileURL;
408 if ((FileURL.find(
"../") == AString::npos) &&
cFile::IsFile(Path))
414 std::swap(Content, FileContent);
415 size_t LastPointPosition = Path.find_last_of(
'.');
416 if (LastPointPosition != AString::npos)
421 if (ContentType.empty())
423 ContentType =
"application/unknown";
430 a_Connection.
Send(Resp);
431 a_Connection.
Send(Content);
441 static bool IsInitialized =
false;
446 ContentTypeMap[
"png"] =
"image/png";
447 ContentTypeMap[
"fif"] =
"image/fif";
448 ContentTypeMap[
"gif"] =
"image/gif";
449 ContentTypeMap[
"jpeg"] =
"image/jpeg";
450 ContentTypeMap[
"jpg"] =
"image/jpeg";
451 ContentTypeMap[
"jpe"] =
"image/jpeg";
452 ContentTypeMap[
"tiff"] =
"image/tiff";
453 ContentTypeMap[
"ico"] =
"image/ico";
454 ContentTypeMap[
"csv"] =
"text/csv";
455 ContentTypeMap[
"css"] =
"text/css";
456 ContentTypeMap[
"js"] =
"text/javascript";
457 ContentTypeMap[
"txt"] =
"text/plain";
458 ContentTypeMap[
"rtx"] =
"text/richtext";
459 ContentTypeMap[
"rtf"] =
"text/richtext";
460 ContentTypeMap[
"xml"] =
"text/xml";
461 ContentTypeMap[
"html"] =
"text/html";
462 ContentTypeMap[
"htm"] =
"text/html";
463 ContentTypeMap[
"xhtml"] =
"application/xhtml+xml";
466 auto itr = ContentTypeMap.find(
StrToLower(a_FileExtension));
467 if (itr == ContentTypeMap.end())
484 if (split.size() <= 2)
496 (wt->m_PluginName == split[1]) &&
497 (wt->m_UrlPath == split[2])
513 FMT_STRING(
"WebTab callback for plugin {}, page {} has failed."),
514 tab->m_PluginName, tab->m_Title
542 std::shared_ptr<cWebAdmin::cWebTabCallback> a_Callback
546 m_WebTabs.emplace_back(std::make_shared<cWebTab>(a_Title, a_UrlPath, a_PluginName, std::move(a_Callback)));
558 if ((*itr)->m_UrlPath == a_UrlPath)
576 dst.reserve(a_Input.length());
579 size_t len = a_Input.length();
580 for (
size_t i = 0; i < len; i++)
584 case '&': dst.append(
"&");
break;
585 case '\'': dst.append(
"'");
break;
586 case '"': dst.append(
""");
break;
587 case '<': dst.append(
"<");
break;
588 case '>': dst.append(
">");
break;
591 dst.push_back(a_Input[i]);
616 if (a_URLSplit.size() > 1)
618 for (
unsigned int i = 0; i < a_URLSplit.size(); i++)
622 BaseURL +=
"webadmin/";
636 (strncmp(URL.c_str(),
"/webadmin", 9) == 0) ||
637 (strncmp(URL.c_str(),
"/~webadmin", 10) == 0)
640 a_Request.
SetUserData(std::make_shared<cWebadminRequestData>(a_Request));
658 auto Data = std::static_pointer_cast<cWebadminRequestData>(a_Request.
GetUserData());
663 Data->m_Form.Parse(a_Data, a_Size);
674 (strncmp(URL.c_str(),
"/webadmin", 9) == 0) ||
675 (strncmp(URL.c_str(),
"/~webadmin", 10) == 0)
AStringVector ReadUpgradeIniPorts(cSettingsRepositoryInterface &a_Settings, const AString &a_KeyName, const AString &a_PortsValueName, const AString &a_OldIPv4ValueName, const AString &a_OldIPv6ValueName, const AString &a_DefaultValue)
Reads the list of ports from the INI file, possibly upgrading from IPv4 / IPv6-specific values into n...
void LOGWARNING(std::string_view a_Format, const Args &... args)
AString URLEncode(const AString &a_Text)
URL-encodes the given string.
AString StrToLower(const AString &s)
Returns a lower-cased copy of the string.
AStringVector StringSplit(const AString &str, const AString &delim)
Split the string at any of the listed delimiters.
std::vector< AString > AStringVector
std::map< AString, AString > AStringMap
A string dictionary, used for key-value pairs.
static const char DEFAULT_WEBADMIN_PORTS[]
void Close(void)
Closes the m_LuaState, if not closed already.
bool Call(const FnT &a_Function, Args &&... args)
Call the specified Lua function.
bool LoadFile(const AString &a_FileName, bool a_LogWarnings=true)
Loads the specified file Returns false and optionally logs a warning to the console if not successful...
void RegisterAPILibs(void)
Registers all the API libraries that MCS provides into m_LuaState.
bool IsValid(void) const
Returns true if the m_LuaState is valid.
void Create(void)
Creates the m_LuaState, if not created already.
Provides a RAII-style locking for the LuaState.
bool Finish(void)
Notifies that there's no more data incoming and the parser should finish its parsing.
@ fpkURL
The form has been transmitted as parameters to a GET request.
void SetContentType(const AString &a_ContentType)
Stores outgoing response headers and serializes them to an HTTP data stream.
Provides storage for an incoming HTTP request.
const AString & GetMethod(void) const
Returns the method used in the request.
const AString & GetAuthUsername(void) const
Returns the username that the request presented.
void SetUserData(cUserDataPtr a_UserData)
Attaches any kind of data to this request, to be later retrieved by GetUserData().
AString GetURLPath(void) const
Returns the path part of the URL.
cUserDataPtr GetUserData(void)
Returns the data attached to this request by the class client.
const AString & GetAuthPassword(void) const
Returns the password that the request presented.
bool HasAuth(void) const
Returns true if the request has had the Auth header present.
const AString & GetURL(void) const
Returns the URL used in the request.
Base class for anything that can be used as the UserData for the request.
bool Initialize(void)
Initializes the server - reads the cert files etc.
void Stop(void)
Stops the server, drops all current connections.
bool Start(cCallbacks &a_Callbacks, const AStringVector &a_Ports)
Starts the server and assigns the callbacks to use for incoming requests.
void SendNeedAuth(const AString &a_Realm)
Sends the "401 unauthorized" reply together with instructions on authorizing, using the specified rea...
void FinishResponse(void)
Indicates that the current response is finished, gets ready for receiving another request (HTTP 1....
void SendStatusAndReason(int a_StatusCode, const AString &a_Reason)
Sends HTTP status code together with a_Reason (used for HTTP errors).
void Send(const cHTTPOutgoingResponse &a_Response)
Sends the headers contained in a_Response.
AString GetKeyName(const int keyID) const
AString GetValue(const AString &keyname, const AString &valuename, const AString &defValue="") const override
Get the value at the specified key and value, returns defValue on failure.
bool WriteFile(const AString &a_FileName) const
Writes data stored in class to the specified ini file.
bool ReadFile(const AString &a_FileName, bool a_AllowExampleRedirect=true)
Reads the contents of the specified ini file If the file doesn't exist and a_AllowExampleRedirect is ...
void Clear(void)
Deletes all stored ini data (but doesn't touch the file)
void AddHeaderComment(const AString &comment)
Adds a header comment.
bool SetValue(const int keyID, const int valueID, const AString &value)
int GetNumKeys(void) const
Returns number of keys currently in the ini.
bool GetValueSetB(const AString &keyname, const AString &valuename, const bool defValue=false) override
RAII for cCriticalSection - locks the CS on creation, unlocks on destruction.
int ReadRestOfFile(AString &a_Contents)
Reads the file from current position till EOF into an AString; returns the number of bytes read or -1...
static bool IsFile(const AString &a_Path)
Returns true if the specified path is a regular file.
The form parser callbacks for requests in the "/webadmin" and "/~webadmin" paths.
cWebadminRequestData(const cHTTPIncomingRequest &a_Request)
virtual void OnFileData(cHTTPFormParser &, const char *a_Data, size_t a_Size) override
Called when more file data has come for the current file in the form data.
virtual void OnFileEnd(cHTTPFormParser &) override
Called when the current file part has ended in the form data.
virtual void OnFileStart(cHTTPFormParser &, const AString &a_FileName) override
Called when a new file part is encountered in the form data.
FormDataMap FormData
Same as PostParams.
StringStringMap PostParams
Parameters posted as a part of a form - either in the URL (GET method) or in the body (POST method)
AString URL
The entire URL presented to the HTTP server.
AString Method
HTTP method used for the request ("GET", "POST" etc.)
StringStringMap Params
Parameters given in the URL, after the questionmark.
AString Path
The Path part of the request's URL (excluding GET params).
AString Username
Name of the logged-in user.
virtual void OnRequestBody(cHTTPServerConnection &a_Connection, cHTTPIncomingRequest &a_Request, const char *a_Data, size_t a_Size) override
Called when another part of request body has arrived.
cLuaState m_TemplateScript
The Lua template script to provide templates.
void Stop(void)
Stops the HTTP server, if it was started.
static AString GetContentTypeFromFileExt(const AString &a_FileExtension)
Returns the content type from the file extension.
AStringVector m_Ports
The ports on which the webadmin is running.
std::shared_ptr< cWebTab > cWebTabPtr
cIniFile m_IniFile
The webadmin.ini file, used for the settings and allowed logins.
void HandleFileRequest(cHTTPServerConnection &a_Connection, cHTTPIncomingRequest &a_Request)
Handles requests for a file.
virtual void OnRequestBegun(cHTTPServerConnection &a_Connection, cHTTPIncomingRequest &a_Request) override
Called when a new request arrives over a connection and all its headers have been parsed.
cCriticalSection m_CS
Protects m_WebTabs, m_TemplateScript, m_LoginTemplate and m_IniFile against multithreaded access.
void HandleWebadminRequest(cHTTPServerConnection &a_Connection, cHTTPIncomingRequest &a_Request)
Handles requests coming to the "/webadmin" or "/~webadmin" URLs.
virtual void OnRequestFinished(cHTTPServerConnection &a_Connection, cHTTPIncomingRequest &a_Request) override
Called when the request body has been fully received in previous calls to OnRequestBody()
bool DelWebTab(const AString &a_UrlPath)
Removes the WebTab with the specified URL path.
bool LoadIniFile(void)
Loads webadmin.ini into m_IniFile.
void HandleRootRequest(cHTTPServerConnection &a_Connection, cHTTPIncomingRequest &a_Request)
Handles requests for the root page.
bool LoadLoginPage(void)
Loads the login template into m_LoginPage.
bool Start(void)
Starts the HTTP server taking care of the webadmin.
bool Init(void)
Initializes the object.
bool m_IsRunning
Set to true if Start() succeeds in starting the server, reset back to false in Stop().
virtual ~cWebAdmin() override
bool HasUsers()
Checks inside the webadmin.ini file if there are users configured.
void RemoveAllPluginWebTabs(const AString &a_PluginName)
Removes all WebTabs registered by the specified plugin.
static AString GetURLEncodedString(const AString &a_Input)
Escapes the string for use in an URL Exported to Lua in ManualBindings.cpp.
void Reload(void)
Reloads m_IniFile, m_LoginPage and m_TemplateScript.
void AddWebTab(const AString &a_Title, const AString &a_UrlPath, const AString &a_PluginName, std::shared_ptr< cWebTabCallback > a_Callback)
Adds a new WebTab handler.
cWebTabPtrs m_WebTabs
All registered WebTab handlers.
cHTTPServer m_HTTPServer
The HTTP server which provides the underlying HTTP parsing, serialization and events.
static AString GetBaseURL(const AString &a_URL)
Returns the prefix needed for making a link point to the webadmin root from the given URL ("....
static AString GetHTMLEscapedString(const AString &a_Input)
Escapes text passed into it, so it can be embedded into html.
bool m_IsInitialized
Set to true if Init() succeeds and the webadmin isn't to be disabled.
sWebAdminPage GetPage(const HTTPRequest &a_Request)
Returns the (inner) page contents for the specified request.
AString m_LoginPage
The HTML page that provides the login.