From fa910b8e62f27e54312dff6d4445baabd34d805d Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Wed, 10 Jan 2018 22:42:44 +0100 Subject: Add read only mode --- TODO | 1 - debian/README.Debian | 10 ++++++-- html/index.html | 8 +++--- html/webbox.js | 32 +++++++++++++++++++----- src/webbox.cpp | 69 +++++++++++++++++++++++++++++++++++++++++----------- 5 files changed, 93 insertions(+), 27 deletions(-) diff --git a/TODO b/TODO index 0e8f8c0..8f0cdb7 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,6 @@ Prio 1 (for next version) ====== -handle writability rename function gallery diff --git a/debian/README.Debian b/debian/README.Debian index f24b3b8..fac423e 100644 --- a/debian/README.Debian +++ b/debian/README.Debian @@ -48,14 +48,20 @@ Environment Variables The following environment variables are supported: -WEBBOX_PATH +WEBBOX_PATH Directory with the payload files to be served by a webbox. -WEBBOX_NAME +WEBBOX_NAME Title of the webbox. Will be written on top of the Web UI. +WEBBOX_READONLY On|Off + + If present and set to On, the whole webbox will not provide write/changes + to the contents of the box. + + Authentication -------------- diff --git a/html/index.html b/html/index.html index 43ef009..580e415 100644 --- a/html/index.html +++ b/html/index.html @@ -39,11 +39,11 @@ <div class="menuwindow" id="menuwindow" hidden> <div class="menudiv"> <table class="menudialog"> - <tr><td class="entry" onclick="hideMenu(); createDir();">New Folder</td></tr> + <tr class="writecommand"><td class="entry" onclick="hideMenu(); createDir();">New Folder</td></tr> <tr><td class="entry" onclick="hideMenu(); download();">Download</td></tr> - <tr><td class="entry" onclick="hideMenu(); upload();">Upload</td></tr> - <tr><td class="entry" onclick="hideMenu(); deleteItems();">Delete</td></tr> - <tr><td class="entry" onclick="hideMenu(); move();">Move</td></tr> + <tr class="writecommand"><td class="entry" onclick="hideMenu(); upload();">Upload</td></tr> + <tr class="writecommand"><td class="entry" onclick="hideMenu(); deleteItems();">Delete</td></tr> + <tr class="writecommand"><td class="entry" onclick="hideMenu(); move();">Move</td></tr> <tr><td class="entry" onclick="hideMenu(); info();">Info</td></tr> <tr><td class="entry" onclick="hideMenu(); selectAll();">Select/Unselect All</td></tr> <tr><td class="entry" onclick="hideMenu();">Close Menu</td></tr> diff --git a/html/webbox.js b/html/webbox.js index 296429b..40a7a1a 100644 --- a/html/webbox.js +++ b/html/webbox.js @@ -31,9 +31,9 @@ function loadContents(dir) { } result += "<tr " + - "onmousedown=\"entryMouseDown('" + listElements[i].childNodes[0].nodeValue + "')\" " + - "onmouseup=\"entryMouseUp('" + listElements[i].childNodes[0].nodeValue + "')\"" + - "><td class=\"type\">" + type + "</td><td class=\"name\">" + listElements[i].childNodes[0].nodeValue + "</td></tr>"; + "onmousedown=\"entryMouseDown('" + listElements[i].textContent + "')\" " + + "onmouseup=\"entryMouseUp('" + listElements[i].textContent + "')\"" + + "><td class=\"type\">" + type + "</td><td class=\"name\">" + listElements[i].textContent + "</td></tr>"; } } @@ -224,6 +224,16 @@ function hideMenu() { document.getElementById("menuwindow").style.display = 'none'; } +// if readOnly = "1", disable respective controls since this setting is global and constant +function prepareReadOnly(readOnly) { + if (readOnly == "1") { + var writecommands = document.getElementsByClassName("writecommand"); + for (var i = 0; i < writecommands.length; i++) { + writecommands[i].style.display = "none"; + } + } +} + function initMainpage() { setCurrentDir("/"); @@ -248,13 +258,23 @@ function initMainpage() { var xhrTitle = new XMLHttpRequest(); xhrTitle.onreadystatechange = function() { - if (this.readyState != 4 || this.status != 200) { + if (this.readyState != 4) { return; } - document.getElementsByClassName("title")[0].innerHTML = xhrTitle.responseText; + if (this.status != 200) { + document.getElementsByClassName("title")[0].innerHTML = "HTTP error"; + return; + } + + var serverInfo = xhrTitle.responseXML; + var title = serverInfo.getElementsByTagName("title")[0].textContent; + document.getElementsByClassName("title")[0].innerHTML = title; + + var readOnly = serverInfo.getElementsByTagName("readonly")[0].textContent; + prepareReadOnly(readOnly); } - xhrTitle.open("GET", "/bin/query?command=title", true); + xhrTitle.open("GET", "/bin/query?command=server-info", true); xhrTitle.send(); // load footer diff --git a/src/webbox.cpp b/src/webbox.cpp index c3f03e2..d0cfebc 100644 --- a/src/webbox.cpp +++ b/src/webbox.cpp @@ -72,22 +72,31 @@ struct CommandParameters { QHash<QString, QString> paramHash; // derived from urlQuery int count; // request count for this instance + + // Webbox parameters, constant and set globally in Web server config + QString webboxPath; + QString webboxName; + bool webboxReadOnly; }; class Command { public: // call interface void execute(CommandParameters& p) { + // check if this webbox is writable and enforce this + if (p.webboxReadOnly && m_isWriteCommand) { + printHttpError(400, QString("Webbox is Read-Only"), p); + return; + } + + // check for correct method GET/POST QString requestMethod(FCGX_GetParam("REQUEST_METHOD", p.request.envp)); if (requestMethod != m_requestMethod) { printHttpError(403, QString("Bad request method"), p); return; } - // process environment - QString webboxPath(getenv("WEBBOX_PATH")); - - // FastCGI request environment + // Set parameters from FastCGI request environment m_pathInfo = FCGX_GetParam("PATH_INFO", p.request.envp); if (m_pathInfo == "") { m_pathInfo = "/"; @@ -97,7 +106,7 @@ class Command { return; } - m_path = webboxPath + m_pathInfo; + m_path = p.webboxPath + m_pathInfo; this->start(p); } @@ -118,6 +127,7 @@ class Command { // Implementation class constants QString m_commandName; QString m_requestMethod; + bool m_isWriteCommand; // if true, command must be prevented if p.webboxReadOnly // calculated during start of execute() QString m_pathInfo; // path inside webbox, derived from request @@ -169,6 +179,7 @@ class DiagCommand: public GetCommand { public: DiagCommand() { m_commandName = "diag"; + m_isWriteCommand = false; } protected: @@ -193,7 +204,7 @@ class DiagCommand: public GetCommand { tmp++; } - FCGX_PutS(QString("<br/>WEBBOX_PATH=%1<br/>\r\n").arg(getenv("WEBBOX_PATH")).toUtf8().data(), p.request.out); + FCGX_PutS(QString("<br/>WEBBOX_PATH=%1<br/>\r\n").arg(p.webboxPath).toUtf8().data(), p.request.out); FCGX_PutS(QString("<br/>URL Query=%1<br/>\r\n").arg(p.urlQuery.toString()).toUtf8().data(), p.request.out); @@ -206,6 +217,7 @@ class ListCommand: public GetCommand { public: ListCommand() { m_commandName = "list"; + m_isWriteCommand = false; } protected: @@ -233,16 +245,32 @@ class ListCommand: public GetCommand { } }; -class TitleCommand: public GetCommand { +// Retrieve from Server: +// Title +// ReadOnly flag +class ServerInfoCommand: public GetCommand { public: - TitleCommand() { - m_commandName = "title"; + ServerInfoCommand() { + m_commandName = "server-info"; + m_isWriteCommand = false; } protected: virtual void start(CommandParameters& p) { - FCGX_PutS("Content-Type: text/plain\r\n\r\n", p.request.out); - FCGX_PutS(getenv("WEBBOX_NAME"), p.request.out); + FCGX_PutS("Content-Type: text/xml\r\n\r\n", p.request.out); + + QByteArray xmlData; + QXmlStreamWriter xmlWriter(&xmlData); + xmlWriter.writeStartDocument(); + xmlWriter.writeStartElement("serverinfo"); + + xmlWriter.writeTextElement("title", p.webboxName); + + xmlWriter.writeTextElement("readonly", p.webboxReadOnly ? "1" : "0"); + + xmlWriter.writeEndElement(); // serverinfo + xmlWriter.writeEndDocument(); + FCGX_PutS(xmlData.data(), p.request.out); } }; @@ -250,12 +278,13 @@ class VersionCommand: public GetCommand { public: VersionCommand() { m_commandName = "version"; + m_isWriteCommand = false; } protected: virtual void start(CommandParameters& p) { FCGX_PutS("Content-Type: text/plain\r\n\r\n", p.request.out); - FCGX_PutS(QString("webbox %1<br/>(C) 2017 <a href=\"https://www.reichwein.it/\">Reichwein.IT</a>\r\n").arg(PROGRAMVERSION).toUtf8().data(), p.request.out); + FCGX_PutS(QString("webbox %1<br/>(C) 2018 <a href=\"https://www.reichwein.it/\">Reichwein.IT</a>\r\n").arg(PROGRAMVERSION).toUtf8().data(), p.request.out); } }; @@ -263,6 +292,7 @@ class NewDirCommand: public PostCommand { public: NewDirCommand() { m_commandName = "newdir"; + m_isWriteCommand = true; } protected: @@ -293,6 +323,7 @@ class InfoCommand: public PostCommand { public: InfoCommand() { m_commandName = "info"; + m_isWriteCommand = false; } protected: @@ -413,6 +444,7 @@ class DeleteCommand: public PostCommand { public: DeleteCommand() { m_commandName = "delete"; + m_isWriteCommand = true; } protected: @@ -464,6 +496,7 @@ class MoveCommand: public PostCommand { public: MoveCommand() { m_commandName = "move"; + m_isWriteCommand = true; } protected: @@ -518,6 +551,7 @@ class UploadCommand: public PostCommand { public: UploadCommand() { m_commandName = "upload"; + m_isWriteCommand = true; } protected: @@ -590,6 +624,7 @@ class DownloadCommand: public GetCommand { public: DownloadCommand() { m_commandName = ""; // default command w/o explict "command=" query argument + m_isWriteCommand = false; } protected: @@ -642,6 +677,12 @@ int main(int argc, char* argv[]) { commandParameters.count = 0; + // values constant to this instance: + commandParameters.webboxPath = getenv("WEBBOX_PATH"); + commandParameters.webboxName = getenv("WEBBOX_NAME"); + char* WEBBOX_READONLY = getenv("WEBBOX_READONLY"); + commandParameters.webboxReadOnly = ((WEBBOX_READONLY != NULL) && !strcmp(WEBBOX_READONLY, "On")); + Commands commands; DiagCommand diagCommand; @@ -650,8 +691,8 @@ int main(int argc, char* argv[]) { ListCommand listCommand; commands.registerCommand(listCommand); - TitleCommand titleCommand; - commands.registerCommand(titleCommand); + ServerInfoCommand serverInfoCommand; + commands.registerCommand(serverInfoCommand); VersionCommand versionCommand; commands.registerCommand(versionCommand); -- cgit v1.2.3