diff --git a/include/znc/HTTPSock.h b/include/znc/HTTPSock.h index 65da6fdb..2c3cc872 100644 --- a/include/znc/HTTPSock.h +++ b/include/znc/HTTPSock.h @@ -25,8 +25,8 @@ class CModule; class CHTTPSock : public CSocket { public: - CHTTPSock(CModule *pMod); - CHTTPSock(CModule *pMod, const CString& sHostname, unsigned short uPort, int iTimeout = 60); + CHTTPSock(CModule *pMod, const CString& sURIPrefix); + CHTTPSock(CModule *pMod, const CString& sURIPrefix, const CString& sHostname, unsigned short uPort, int iTimeout = 60); virtual ~CHTTPSock(); // Csocket derived members @@ -76,6 +76,7 @@ public: const CString& GetPass() const; const CString& GetParamString() const; const CString& GetContentType() const; + const CString& GetURIPrefix() const; bool IsPost() const; // !Getters @@ -121,6 +122,7 @@ protected: bool m_bAcceptGzip; MCString m_msRequestCookies; MCString m_msResponseCookies; + CString m_sURIPrefix; }; #endif // !_HTTPSOCK_H diff --git a/include/znc/Listener.h b/include/znc/Listener.h index 06aaca58..0f39887d 100644 --- a/include/znc/Listener.h +++ b/include/znc/Listener.h @@ -32,11 +32,12 @@ public: ACCEPT_ALL } EAcceptType; - CListener(unsigned short uPort, const CString& sBindHost, bool bSSL, EAddrType eAddr, EAcceptType eAccept) { + CListener(unsigned short uPort, const CString& sBindHost, const CString& sURIPrefix, bool bSSL, EAddrType eAddr, EAcceptType eAccept) { m_uPort = uPort; m_sBindHost = sBindHost; m_bSSL = bSSL; m_eAddr = eAddr; + m_sURIPrefix = sURIPrefix; m_pListener = NULL; m_eAcceptType = eAccept; } @@ -49,6 +50,7 @@ public: unsigned short GetPort() const { return m_uPort; } const CString& GetBindHost() const { return m_sBindHost; } CRealListener* GetRealListener() const { return m_pListener; } + const CString& GetURIPrefix() const { return m_sURIPrefix; } EAcceptType GetAcceptType() const { return m_eAcceptType; } // !Getters @@ -65,13 +67,14 @@ protected: EAddrType m_eAddr; unsigned short m_uPort; CString m_sBindHost; + CString m_sURIPrefix; CRealListener* m_pListener; EAcceptType m_eAcceptType; }; class CRealListener : public CZNCSock { public: - CRealListener(CListener *pParent) : CZNCSock(), m_pParent(pParent) {} + CRealListener(CListener& listener) : CZNCSock(), m_Listener(listener) {} virtual ~CRealListener(); virtual bool ConnectionFrom(const CString& sHost, unsigned short uPort); @@ -79,18 +82,19 @@ public: virtual void SockError(int iErrno, const CString& sDescription); private: - CListener* m_pParent; + CListener& m_Listener; }; class CIncomingConnection : public CZNCSock { public: - CIncomingConnection(const CString& sHostname, unsigned short uPort, CListener::EAcceptType eAcceptType); + CIncomingConnection(const CString& sHostname, unsigned short uPort, CListener::EAcceptType eAcceptType, const CString& sURIPrefix); virtual ~CIncomingConnection() {} virtual void ReadLine(const CString& sData); virtual void ReachedMaxBuffer(); private: CListener::EAcceptType m_eAcceptType; + const CString m_sURIPrefix; }; #endif // !_LISTENER_H diff --git a/include/znc/WebModules.h b/include/znc/WebModules.h index 3c04ddfd..44e477e5 100644 --- a/include/znc/WebModules.h +++ b/include/znc/WebModules.h @@ -117,7 +117,7 @@ public: PAGE_DONE // all stuff has been done }; - CWebSock(); + CWebSock(const CString& sURIPrefix); virtual ~CWebSock(); virtual bool ForceLogin(); diff --git a/include/znc/ZNCString.h b/include/znc/ZNCString.h index 4a9adcb1..6a63aa6f 100644 --- a/include/znc/ZNCString.h +++ b/include/znc/ZNCString.h @@ -478,6 +478,17 @@ public: */ CString TrimSuffix_n(const CString& sSuffix) const; + /** Check whether the string starts with a given prefix. + * @param sPrefix The prefix. + * @return True if the string starts with prefix, false otherwise. + */ + bool StartsWith(const CString& sPrefix) const; + /** Check whether the string ends with a given suffix. + * @param sSuffix The suffix. + * @return True if the string ends with suffix, false otherwise. + */ + bool EndsWith(const CString& sSuffix) const; + /** Remove characters from the beginning of this string. * @param uLen The number of characters to remove. * @return true if this string was modified. diff --git a/include/znc/znc.h b/include/znc/znc.h index f54d2ddd..7c4f64fc 100644 --- a/include/znc/znc.h +++ b/include/znc/znc.h @@ -154,7 +154,8 @@ public: // Listener yummy CListener* FindListener(u_short uPort, const CString& BindHost, EAddrType eAddr); bool AddListener(CListener*); - bool AddListener(unsigned short uPort, const CString& sBindHost, bool bSSL, + bool AddListener(unsigned short uPort, const CString& sBindHost, + const CString& sURIPrefix, bool bSSL, EAddrType eAddr, CListener::EAcceptType eAccept, CString& sError); bool DelListener(CListener*); diff --git a/modules/data/cert/tmpl/index.tmpl b/modules/data/cert/tmpl/index.tmpl index 675be511..0885cb15 100644 --- a/modules/data/cert/tmpl/index.tmpl +++ b/modules/data/cert/tmpl/index.tmpl @@ -1,12 +1,12 @@ -

You already have a certificate set, use the form below to overwrite the current certificate. Alternatively click here to delete your certificate.

+

You already have a certificate set, use the form below to overwrite the current certificate. Alternatively click here to delete your certificate.

You do not have a cert.

-
+

Certificate

diff --git a/modules/data/certauth/tmpl/index.tmpl b/modules/data/certauth/tmpl/index.tmpl index a4a6af31..c042597b 100644 --- a/modules/data/certauth/tmpl/index.tmpl +++ b/modules/data/certauth/tmpl/index.tmpl @@ -1,6 +1,6 @@ - +

Add A Note

diff --git a/modules/data/lastseen/tmpl/index.tmpl b/modules/data/lastseen/tmpl/index.tmpl index 3e8e43d0..3fb5dc19 100644 --- a/modules/data/lastseen/tmpl/index.tmpl +++ b/modules/data/lastseen/tmpl/index.tmpl @@ -17,8 +17,8 @@ - [Edit] - [Delete] + [Edit] + [Delete] diff --git a/modules/data/notes/tmpl/index.tmpl b/modules/data/notes/tmpl/index.tmpl index def45054..eed791c6 100644 --- a/modules/data/notes/tmpl/index.tmpl +++ b/modules/data/notes/tmpl/index.tmpl @@ -1,6 +1,6 @@ - +

Add A Note

@@ -37,7 +37,7 @@ - [del] + [del] diff --git a/modules/data/perform/tmpl/index.tmpl b/modules/data/perform/tmpl/index.tmpl index 543f676c..ffd768aa 100644 --- a/modules/data/perform/tmpl/index.tmpl +++ b/modules/data/perform/tmpl/index.tmpl @@ -1,6 +1,6 @@ - +

Perform

diff --git a/modules/data/send_raw/tmpl/index.tmpl b/modules/data/send_raw/tmpl/index.tmpl index 38b7c596..9f3fb017 100644 --- a/modules/data/send_raw/tmpl/index.tmpl +++ b/modules/data/send_raw/tmpl/index.tmpl @@ -1,7 +1,7 @@ - +
diff --git a/modules/data/stickychan/tmpl/index.tmpl b/modules/data/stickychan/tmpl/index.tmpl index a7160577..581cc31d 100644 --- a/modules/data/stickychan/tmpl/index.tmpl +++ b/modules/data/stickychan/tmpl/index.tmpl @@ -1,6 +1,6 @@ - + diff --git a/modules/data/webadmin/tmpl/add_edit_chan.tmpl b/modules/data/webadmin/tmpl/add_edit_chan.tmpl index 23feff88..cac7ba14 100644 --- a/modules/data/webadmin/tmpl/add_edit_chan.tmpl +++ b/modules/data/webadmin/tmpl/add_edit_chan.tmpl @@ -1,6 +1,6 @@ - +
diff --git a/modules/data/webadmin/tmpl/add_edit_network.tmpl b/modules/data/webadmin/tmpl/add_edit_network.tmpl index 37cc3a85..bb4384b0 100644 --- a/modules/data/webadmin/tmpl/add_edit_network.tmpl +++ b/modules/data/webadmin/tmpl/add_edit_network.tmpl @@ -5,7 +5,7 @@

To connect to this network from your IRC client, you can set the server password field as follows: /<network>:<password> or username field as /<network>

- +
@@ -116,7 +116,7 @@
- + @@ -135,7 +135,7 @@ diff --git a/modules/data/webadmin/tmpl/add_edit_user.tmpl b/modules/data/webadmin/tmpl/add_edit_user.tmpl index b7c13f8c..7bd906de 100644 --- a/modules/data/webadmin/tmpl/add_edit_user.tmpl +++ b/modules/data/webadmin/tmpl/add_edit_user.tmpl @@ -1,6 +1,6 @@ - +
@@ -128,7 +128,7 @@
[Add][Add] Save Name
- [Edit] [Del] + [Edit] [Del] checked="checked" />
- + @@ -145,7 +145,7 @@ diff --git a/modules/data/webadmin/tmpl/del_network.tmpl b/modules/data/webadmin/tmpl/del_network.tmpl index fd6f9fc9..03d6a75f 100644 --- a/modules/data/webadmin/tmpl/del_network.tmpl +++ b/modules/data/webadmin/tmpl/del_network.tmpl @@ -6,13 +6,13 @@
Are you sure you want to delete "/"? - +
-
+
diff --git a/modules/data/webadmin/tmpl/del_user.tmpl b/modules/data/webadmin/tmpl/del_user.tmpl index ab00167e..bef4a9ff 100644 --- a/modules/data/webadmin/tmpl/del_user.tmpl +++ b/modules/data/webadmin/tmpl/del_user.tmpl @@ -6,13 +6,13 @@
Are you sure you want to delete ""? -
+
-
+
diff --git a/modules/data/webadmin/tmpl/listusers.tmpl b/modules/data/webadmin/tmpl/listusers.tmpl index ed2f9301..7d4f30ae 100644 --- a/modules/data/webadmin/tmpl/listusers.tmpl +++ b/modules/data/webadmin/tmpl/listusers.tmpl @@ -2,7 +2,7 @@
- There are no users defined. Click here if you would like to add one. + There are no users defined. Click here if you would like to add one.
@@ -21,9 +21,9 @@
diff --git a/modules/data/webadmin/tmpl/settings.tmpl b/modules/data/webadmin/tmpl/settings.tmpl index 9c958442..b13d7f4e 100644 --- a/modules/data/webadmin/tmpl/settings.tmpl +++ b/modules/data/webadmin/tmpl/settings.tmpl @@ -16,6 +16,7 @@ + @@ -38,9 +39,10 @@ + - + - + + @@ -71,7 +74,7 @@ - + diff --git a/modules/webadmin.cpp b/modules/webadmin.cpp index ec675080..40a28d3b 100644 --- a/modules/webadmin.cpp +++ b/modules/webadmin.cpp @@ -101,6 +101,7 @@ public: CString sArgs(sArgStr); CString sPort; CString sListenHost; + CString sURIPrefix; while (sArgs.Left(1) == "-") { CString sOpt = sArgs.Token(0); @@ -150,7 +151,7 @@ public: } // Now turn that into a listener instance - CListener *pListener = new CListener(uPort, sListenHost, bSSL, + CListener *pListener = new CListener(uPort, sListenHost, sURIPrefix, bSSL, (!bIPv6 ? ADDR_IPV4ONLY : ADDR_ALL), CListener::ACCEPT_HTTP); if (!pListener->Listen()) { @@ -542,7 +543,7 @@ public: WebSock.PrintErrorPage("Please don't delete yourself, suicide is not the answer!"); return true; } else if (CZNC::Get().DeleteUser(sUser)) { - WebSock.Redirect("listusers"); + WebSock.Redirect(GetWebPath() + "listusers"); return true; } @@ -710,7 +711,7 @@ public: return true; } - WebSock.Redirect("editnetwork?user=" + pUser->GetUserName().Escape_n(CString::EURL) + "&network=" + pNetwork->GetName().Escape_n(CString::EURL)); + WebSock.Redirect(GetWebPath() + "editnetwork?user=" + pUser->GetUserName().Escape_n(CString::EURL) + "&network=" + pNetwork->GetName().Escape_n(CString::EURL)); return true; } @@ -984,7 +985,7 @@ public: return true; } - WebSock.Redirect("edituser?user=" + pUser->GetUserName().Escape_n(CString::EURL)); + WebSock.Redirect(GetWebPath() + "edituser?user=" + pUser->GetUserName().Escape_n(CString::EURL)); return true; } @@ -1020,7 +1021,7 @@ public: return true; } - WebSock.Redirect("edituser?user=" + pUser->GetUserName().Escape_n(CString::EURL)); + WebSock.Redirect(GetWebPath() + "edituser?user=" + pUser->GetUserName().Escape_n(CString::EURL)); return false; } @@ -1040,7 +1041,7 @@ public: return true; } - WebSock.Redirect("editnetwork?user=" + pNetwork->GetUser()->GetUserName().Escape_n(CString::EURL) + "&network=" + pNetwork->GetName().Escape_n(CString::EURL)); + WebSock.Redirect(GetWebPath() + "editnetwork?user=" + pNetwork->GetUser()->GetUserName().Escape_n(CString::EURL) + "&network=" + pNetwork->GetName().Escape_n(CString::EURL)); return false; } @@ -1320,9 +1321,9 @@ public: } if (!spSession->IsAdmin()) { - WebSock.Redirect("edituser"); + WebSock.Redirect(GetWebPath() + "edituser"); } else { - WebSock.Redirect("listusers"); + WebSock.Redirect(GetWebPath() + "listusers"); } /* we don't want the template to be printed while we redirect */ @@ -1420,6 +1421,7 @@ public: bool AddListener(CWebSock& WebSock, CTemplate& Tmpl) { unsigned short uPort = WebSock.GetParam("port").ToUShort(); CString sHost = WebSock.GetParam("host"); + CString sURIPrefix = WebSock.GetParam("uriprefix"); if (sHost == "*") sHost = ""; bool bSSL = WebSock.GetParam("ssl").ToBool(); bool bIPv4 = WebSock.GetParam("ipv4").ToBool(); @@ -1460,7 +1462,7 @@ public: } CString sMessage; - if (CZNC::Get().AddListener(uPort, sHost, bSSL, eAddr, eAccept, sMessage)) { + if (CZNC::Get().AddListener(uPort, sHost, sURIPrefix, bSSL, eAddr, eAccept, sMessage)) { if (!sMessage.empty()) { WebSock.GetSession()->AddSuccess(sMessage); } @@ -1545,6 +1547,8 @@ public: l["IsWeb"] = CString(pListener->GetAcceptType() != CListener::ACCEPT_IRC); l["IsIRC"] = CString(pListener->GetAcceptType() != CListener::ACCEPT_HTTP); + l["URIPrefix"] = pListener->GetURIPrefix() + "/"; + // simple protection for user from shooting his own foot // TODO check also for hosts/families // such check is only here, user still can forge HTTP request to delete web port @@ -1688,7 +1692,7 @@ public: WebSock.GetSession()->AddError("Settings changed, but config was not written"); } - WebSock.Redirect("settings"); + WebSock.Redirect(GetWebPath() + "settings"); /* we don't want the template to be printed while we redirect */ return false; } diff --git a/src/ClientCommand.cpp b/src/ClientCommand.cpp index 1d42ec91..38b8a491 100644 --- a/src/ClientCommand.cpp +++ b/src/ClientCommand.cpp @@ -1430,6 +1430,7 @@ void CClient::UserPortCommand(CString& sLine) { Table.AddColumn("SSL"); Table.AddColumn("Proto"); Table.AddColumn("IRC/Web"); + Table.AddColumn("URIPrefix"); vector::const_iterator it; const vector& vpListeners = CZNC::Get().GetListeners(); @@ -1445,6 +1446,7 @@ void CClient::UserPortCommand(CString& sLine) { CListener::EAcceptType eAccept = (*it)->GetAcceptType(); Table.SetCell("IRC/Web", (eAccept == CListener::ACCEPT_ALL ? "All" : (eAccept == CListener::ACCEPT_IRC ? "IRC" : "Web"))); + Table.SetCell("URIPrefix", (*it)->GetURIPrefix() + "/"); } PutStatus(Table); @@ -1483,12 +1485,13 @@ void CClient::UserPortCommand(CString& sLine) { } if (sPort.empty() || sAddr.empty() || sAccept.empty()) { - PutStatus("Usage: AddPort <[+]port> [bindhost]"); + PutStatus("Usage: AddPort <[+]port> [bindhost [uriprefix]]"); } else { bool bSSL = (sPort.Left(1).Equals("+")); const CString sBindHost = sLine.Token(4); + const CString sURIPrefix = sLine.Token(5); - CListener* pListener = new CListener(uPort, sBindHost, bSSL, eAddr, eAccept); + CListener* pListener = new CListener(uPort, sBindHost, sURIPrefix, bSSL, eAddr, eAccept); if (!pListener->Listen()) { delete pListener; diff --git a/src/HTTPSock.cpp b/src/HTTPSock.cpp index 9ce157eb..ab031307 100644 --- a/src/HTTPSock.cpp +++ b/src/HTTPSock.cpp @@ -28,11 +28,11 @@ using std::set; #define MAX_POST_SIZE 1024 * 1024 -CHTTPSock::CHTTPSock(CModule *pMod) : CSocket(pMod) { +CHTTPSock::CHTTPSock(CModule *pMod, const CString& sURIPrefix) : CSocket(pMod), m_sURIPrefix(sURIPrefix) { Init(); } -CHTTPSock::CHTTPSock(CModule *pMod, const CString& sHostname, unsigned short uPort, int iTimeout) : CSocket(pMod, sHostname, uPort, iTimeout) { +CHTTPSock::CHTTPSock(CModule *pMod, const CString& sURIPrefix, const CString& sHostname, unsigned short uPort, int iTimeout) : CSocket(pMod, sHostname, uPort, iTimeout), m_sURIPrefix(sURIPrefix) { Init(); } @@ -214,7 +214,16 @@ CString CHTTPSock::GetDate(time_t stamp) { void CHTTPSock::GetPage() { DEBUG("Page Request [" << m_sURI << "] "); - OnPageRequest(m_sURI); + // Check that the requested path starts with the prefix. Strip it if so. + if (!m_sURI.TrimPrefix(m_sURIPrefix)) { + DEBUG("INVALID path => Does not start with prefix [" + m_sURIPrefix + "]"); + DEBUG("Expected prefix: " << m_sURIPrefix); + DEBUG("Requested path: " << m_sURI); + Redirect(m_sURI); + } else { + OnPageRequest(m_sURI); + } + } #ifdef HAVE_ZLIB @@ -495,6 +504,10 @@ const CString& CHTTPSock::GetParamString() const { return m_sPostData; } +const CString& CHTTPSock::GetURIPrefix() const { + return m_sURIPrefix; +} + bool CHTTPSock::HasParam(const CString& sName, bool bPost) const { if (bPost) return (m_msvsPOSTParams.find(sName) != m_msvsPOSTParams.end()); @@ -712,13 +725,19 @@ bool CHTTPSock::Redirect(const CString& sURL) { if (SentHeader()) { DEBUG("Redirect() - Header was already sent"); return false; + } else if(!sURL.StartsWith("/")) { + // HTTP/1.1 only admits absolute URIs for the Location header. + DEBUG("Redirect to relative URI [" + sURL + "] is not allowed."); + return false; + } else { + CString location = m_sURIPrefix + sURL; + + DEBUG("- Redirect to [" << location << "] with prefix [" + m_sURIPrefix + "]"); + AddHeader("Location", location); + PrintErrorPage(302, "Found", "The document has moved here."); + + return true; } - - DEBUG("- Redirect to [" << sURL << "]"); - AddHeader("Location", sURL); - PrintErrorPage(302, "Found", "The document has moved here."); - - return true; } void CHTTPSock::Connected() { diff --git a/src/Listener.cpp b/src/Listener.cpp index 4fddeba8..6e0e34eb 100644 --- a/src/Listener.cpp +++ b/src/Listener.cpp @@ -27,7 +27,7 @@ bool CListener::Listen() { return false; } - m_pListener = new CRealListener(this); + m_pListener = new CRealListener(*this); bool bSSL = false; #ifdef HAVE_LIBSSL @@ -50,7 +50,7 @@ void CListener::ResetRealListener() { } CRealListener::~CRealListener() { - m_pParent->ResetRealListener(); + m_Listener.ResetRealListener(); } bool CRealListener::ConnectionFrom(const CString& sHost, unsigned short uPort) { @@ -60,7 +60,9 @@ bool CRealListener::ConnectionFrom(const CString& sHost, unsigned short uPort) { } Csock* CRealListener::GetSockObj(const CString& sHost, unsigned short uPort) { - CIncomingConnection *pClient = new CIncomingConnection(sHost, uPort, m_pParent->GetAcceptType()); + CIncomingConnection *pClient = new CIncomingConnection(sHost, uPort, + m_Listener.GetAcceptType(), + m_Listener.GetURIPrefix()); if (CZNC::Get().AllowConnectionFrom(sHost)) { GLOBALMODULECALL(OnClientConnect(pClient, sHost, uPort), NOTHING); } else { @@ -83,7 +85,7 @@ void CRealListener::SockError(int iErrno, const CString& sDescription) { } } -CIncomingConnection::CIncomingConnection(const CString& sHostname, unsigned short uPort, CListener::EAcceptType eAcceptType) : CZNCSock(sHostname, uPort) { +CIncomingConnection::CIncomingConnection(const CString& sHostname, unsigned short uPort, CListener::EAcceptType eAcceptType, const CString& sURIPrefix) : CZNCSock(sHostname, uPort), m_sURIPrefix(sURIPrefix) { m_eAcceptType = eAcceptType; // The socket will time out in 120 secs, no matter what. // This has to be fixed up later, if desired. @@ -141,7 +143,7 @@ void CIncomingConnection::ReadLine(const CString& sLine) { return; } - pSock = new CWebSock(); + pSock = new CWebSock(m_sURIPrefix); CZNC::Get().GetManager().SwapSockByAddr(pSock, this); // And don't forget to give it some sane name / timeout diff --git a/src/WebModules.cpp b/src/WebModules.cpp index c8f1c655..d61ba235 100644 --- a/src/WebModules.cpp +++ b/src/WebModules.cpp @@ -185,7 +185,7 @@ void CWebAuth::Invalidate() { m_pWebSock = NULL; } -CWebSock::CWebSock() : CHTTPSock(NULL) { +CWebSock::CWebSock(const CString& sURIPrefix) : CHTTPSock(NULL, sURIPrefix) { m_bPathsSet = false; m_Template.AddTagHandler(new CZNCTagHandler(*this)); @@ -325,6 +325,7 @@ void CWebSock::SetVars() { m_Template["Version"] = CZNC::GetVersion(); m_Template["SkinName"] = GetSkinName(); m_Template["_CSRF_Check"] = GetCSRFCheck(); + m_Template["URIPrefix"] = GetURIPrefix(); if (GetSession()->IsAdmin()) { m_Template["IsAdmin"] = "true"; @@ -473,6 +474,7 @@ CWebSock::EPageReqResult CWebSock::PrintStaticFile(const CString& sPath, CString CWebSock::EPageReqResult CWebSock::PrintTemplate(const CString& sPageName, CString& sPageRet, CModule* pModule) { SetVars(); + m_Template["PageName"] = sPageName; if (pModule) { diff --git a/src/ZNCString.cpp b/src/ZNCString.cpp index d0140ab5..4e803881 100644 --- a/src/ZNCString.cpp +++ b/src/ZNCString.cpp @@ -1092,6 +1092,14 @@ bool CString::TrimSuffix(const CString& sSuffix) { } } +bool CString::StartsWith(const CString& sPrefix) const { + return Left(sPrefix.length()).Equals(sPrefix); +} + +bool CString::EndsWith(const CString& sSuffix) const { + return Right(sSuffix.length()).Equals(sSuffix); +} + CString CString::TrimPrefix_n(const CString& sPrefix) const { CString sRet = *this; diff --git a/src/znc.cpp b/src/znc.cpp index 07a3c03a..a019b44d 100644 --- a/src/znc.cpp +++ b/src/znc.cpp @@ -450,6 +450,7 @@ bool CZNC::WriteConfig() { CConfig listenerConfig; listenerConfig.AddKeyValuePair("Host", pListener->GetBindHost()); + listenerConfig.AddKeyValuePair("URIPrefix", pListener->GetURIPrefix() + "/"); listenerConfig.AddKeyValuePair("Port", CString(pListener->GetPort())); listenerConfig.AddKeyValuePair("IPv4", CString(pListener->GetAddrType() != ADDR_IPV6ONLY)); @@ -578,6 +579,7 @@ bool CZNC::WriteNewConfig(const CString& sConfigFile) { bool b6 = false; #endif CString sListenHost; + CString sURIPrefix; bool bListenSSL = false; unsigned int uListenPort = 0; bool bSuccess; @@ -606,7 +608,7 @@ bool CZNC::WriteNewConfig(const CString& sConfigFile) { CUtils::GetInput("Listen Host", sListenHost, sListenHost, "Blank for all ips"); CUtils::PrintAction("Verifying the listener"); - CListener* pListener = new CListener((unsigned short int)uListenPort, sListenHost, bListenSSL, + CListener* pListener = new CListener((unsigned short int)uListenPort, sListenHost, sURIPrefix, bListenSSL, b6 ? ADDR_ALL : ADDR_IPV4ONLY, CListener::ACCEPT_ALL); if (!pListener->Listen()) { CUtils::PrintStatus(false, FormatBindError()); @@ -1689,12 +1691,15 @@ bool CZNC::AddListener(const CString& sLine, CString& sError) { bSSL = true; } + // No support for URIPrefix for old-style configs. + CString sURIPrefix; unsigned short uPort = sPort.ToUShort(); - return AddListener(uPort, sBindHost, bSSL, eAddr, eAccept, sError); + return AddListener(uPort, sBindHost, sURIPrefix, bSSL, eAddr, eAccept, sError); } -bool CZNC::AddListener(unsigned short uPort, const CString& sBindHost, bool bSSL, - EAddrType eAddr, CListener::EAcceptType eAccept, CString& sError) { +bool CZNC::AddListener(unsigned short uPort, const CString& sBindHost, + const CString& sURIPrefixRaw, bool bSSL, + EAddrType eAddr, CListener::EAcceptType eAccept, CString& sError) { CString sHostComment; if (!sBindHost.empty()) { @@ -1755,7 +1760,18 @@ bool CZNC::AddListener(unsigned short uPort, const CString& sBindHost, bool bSSL return false; } - CListener* pListener = new CListener(uPort, sBindHost, bSSL, eAddr, eAccept); + // URIPrefix must start with a slash and end without one. + CString sURIPrefix = CString(sURIPrefixRaw); + if(!sURIPrefix.empty()) { + if (!sURIPrefix.StartsWith("/")) { + sURIPrefix = "/" + sURIPrefix; + } + if (sURIPrefix.EndsWith("/")) { + sURIPrefix.TrimRight("/"); + } + } + + CListener* pListener = new CListener(uPort, sBindHost, sURIPrefix, bSSL, eAddr, eAccept); if (!pListener->Listen()) { sError = FormatBindError(); @@ -1772,6 +1788,7 @@ bool CZNC::AddListener(unsigned short uPort, const CString& sBindHost, bool bSSL bool CZNC::AddListener(CConfig* pConfig, CString& sError) { CString sBindHost; + CString sURIPrefix; bool bSSL; bool b4; #ifdef HAVE_IPV6 @@ -1793,6 +1810,7 @@ bool CZNC::AddListener(CConfig* pConfig, CString& sError) { pConfig->FindBoolEntry("ipv6", b6, b6); pConfig->FindBoolEntry("allowirc", bIRC, true); pConfig->FindBoolEntry("allowweb", bWeb, true); + pConfig->FindStringEntry("uriprefix", sURIPrefix); EAddrType eAddr; if (b4 && b6) { @@ -1820,7 +1838,7 @@ bool CZNC::AddListener(CConfig* pConfig, CString& sError) { return false; } - return AddListener(uPort, sBindHost, bSSL, eAddr, eAccept, sError); + return AddListener(uPort, sBindHost, sURIPrefix, bSSL, eAddr, eAccept, sError); } bool CZNC::AddListener(CListener* pListener) { diff --git a/webskins/_default_/pub/_default_.css b/webskins/_default_/pub/_default_.css index 6282c77e..53258955 100644 --- a/webskins/_default_/pub/_default_.css +++ b/webskins/_default_/pub/_default_.css @@ -247,6 +247,11 @@ input.third, textarea.third, width: 150px; } +input.sixth, textarea.sixth, +.sixth input, .sixth textarea { + width: 75px; +} + input.number { width: 40px; } @@ -299,7 +304,7 @@ tr.evenrow td { .subsection input, .subsection select, .subsection textarea { margin: 5px 0 5px 0; - min-width: 100px; + min-width: 75px; vertical-align: middle; } diff --git a/webskins/_default_/tmpl/BaseHeader.tmpl b/webskins/_default_/tmpl/BaseHeader.tmpl index af63eaf7..ad58c958 100644 --- a/webskins/_default_/tmpl/BaseHeader.tmpl +++ b/webskins/_default_/tmpl/BaseHeader.tmpl @@ -5,12 +5,13 @@ ZNC - <? VAR Title DEFAULT="Web Frontend" ?> + - + - + diff --git a/webskins/_default_/tmpl/LoginBar.tmpl b/webskins/_default_/tmpl/LoginBar.tmpl index a4899058..6d15f2d5 100644 --- a/webskins/_default_/tmpl/LoginBar.tmpl +++ b/webskins/_default_/tmpl/LoginBar.tmpl @@ -1,9 +1,9 @@ - Logout + Logout   - +
User: diff --git a/webskins/_default_/tmpl/Menu.tmpl b/webskins/_default_/tmpl/Menu.tmpl index 97cfaa36..17273d26 100644 --- a/webskins/_default_/tmpl/Menu.tmpl +++ b/webskins/_default_/tmpl/Menu.tmpl @@ -1,14 +1,14 @@
[Add][Add] Name Clients
- [Edit] [Del] + [Edit] [Del]
- [Edit] - [Clone] - [Delete] + [Edit] + [Clone] + [Delete] IPv6 IRC WebURIPrefix
checked="checked"/>
-
+ @@ -53,15 +55,16 @@