From 57fbbfbc9f0896e4504b33760117e3e58bf4711c Mon Sep 17 00:00:00 2001 From: prozacx Date: Tue, 5 Jul 2005 09:27:44 +0000 Subject: [PATCH] Allows for adding/editing users on the fly via a browser git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@414 726aef4b-f618-498e-8847-2d620e286838 --- modules/admin.cpp | 385 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 385 insertions(+) create mode 100644 modules/admin.cpp diff --git a/modules/admin.cpp b/modules/admin.cpp new file mode 100644 index 00000000..a0b0527f --- /dev/null +++ b/modules/admin.cpp @@ -0,0 +1,385 @@ +#include "main.h" +#include "User.h" +#include "Nick.h" +#include "Modules.h" +#include "Chan.h" +#include "znc.h" +#include "HTTPSock.h" +#include "Server.h" + +class CAdminMod; + +class CAdminSock : public CHTTPSock { +public: + + CAdminSock(CAdminMod* pModule); + CAdminSock(CAdminMod* pModule, const CString& sHostname, unsigned short uPort, int iTimeout = 60); + virtual ~CAdminSock(); + + bool OnPageRequest(const CString& sURI, CString& sPageRet); + + virtual bool OnLogin(const CString& sUser, const CString& sPass); + + CString Header(const CString& sTitle) { + return "\r\n" + sTitle + "\r\n" + "\r\n" + "

" + sTitle + "


\r\n"; + } + + CString Footer() { + return "\r\n\r\n"; + } + + void PrintMainPage(CString& sPageRet) { + sPageRet = Header("Main Page"); + sPageRet += "Add a user
\r\n" + "List all users
\r\n"; + sPageRet += Footer(); + } + + void GetErrorPage(CString& sPageRet, const CString& sError) { + sPageRet = Header("Error"); + sPageRet += "

" + sError.Escape_n(CString::EHTML) + "

\r\n"; + sPageRet += Footer(); + } + + void ListUsersPage(CString& sPageRet); + bool UserPage(CString& sPageRet, CUser* pUser = NULL); + bool AddNewUser(CString& sPageRet); + + void ListPage(CString& sPageRet) { + VCString vsParams; + const map& msvsParams = GetParams(); + + sPageRet = Header("fooooooo"); + + if (msvsParams.empty()) { + sPageRet += "You passed in no params.\r\n"; + } else { + for (map::const_iterator it = msvsParams.begin(); it != msvsParams.end(); it++) { + sPageRet += "

" + it->first + "

\r\n
    \r\n"; + const VCString vsParams = it->second; + + for (unsigned int a = 0; a < vsParams.size(); a++) { + sPageRet += "
  • [" + vsParams[a] + "]
  • \r\n"; + } + + sPageRet += "
\r\n"; + } + } + + sPageRet += Footer(); + } + + virtual Csock* GetSockObj(const CString& sHost, unsigned short uPort); + +private: +protected: + CAdminMod* m_pModule; +}; + +class CAdminMod : public CGlobalModule { +public: + CAdminMod(void *pDLL, CZNC* pZNC, const CString& sModName) : CGlobalModule(pDLL, pZNC, sModName) { + m_uPort = 8080; + } + + virtual ~CAdminMod() { + for (set::iterator it = m_sSocks.begin(); it != m_sSocks.end(); it++) { + m_pManager->DelSockByAddr(*it); + } + } + + virtual bool OnBoot() { + return true; + } + + virtual bool OnLoad(const CString& sArgs) { + m_uPort = sArgs.Token(0).ToUInt(); + m_sUser = sArgs.Token(1); + m_sPass = sArgs.Token(2); + + if (m_sPass.empty()) { + return false; + } + + CAdminSock* pListenSock = new CAdminSock(this); + //pListenSock->SetPemLocation(m_pZNC->GetPemLocation()); + return m_pManager->ListenAll(m_uPort, "Admin::Listener", false, SOMAXCONN, pListenSock); + } + + void AddSock(CAdminSock* pSock) { + m_sSocks.insert(pSock); + } + + void SockDestroyed(CAdminSock* pSock) { + m_sSocks.erase(pSock); + } + + const CString& GetUser() const { return m_sUser; } + const CString& GetPass() const { return m_sPass; } +private: + unsigned int m_uPort; + CString m_sUser; + CString m_sPass; + set m_sSocks; +}; + +bool CAdminSock::OnLogin(const CString& sUser, const CString& sPass) { + if (GetUser() == m_pModule->GetUser() && GetPass() == m_pModule->GetPass()) { + return true; + } + + return false; +} + +void CAdminSock::ListUsersPage(CString& sPageRet) { + const map& msUsers = m_pModule->GetZNC()->GetUserMap(); + sPageRet = Header("List Users"); + + if (!msUsers.size()) { + sPageRet += "There are no users defined. Click here if you would like to add one.\r\n"; + } else { + sPageRet += "\r\n" + "\t\r\n"; + + for (map::const_iterator it = msUsers.begin(); it != msUsers.end(); it++) { + CServer* pServer = it->second->GetCurrentServer(); + sPageRet += "\t\r\n\t\t\r\n" + "\t\t\r\n" + "\t\t\r\n" + "\t"; + } + + sPageRet +="\r\n
ActionUsernameCurrent Server
[second->GetUserName().Escape_n(CString::EURL) + "\">Edit] [second->GetUserName().Escape_n(CString::EURL) + "\">Delete]" + it->second->GetUserName().Escape_n(CString::EHTML) + "" + CString((pServer) ? pServer->GetName().Escape_n(CString::EHTML) : "-N/A-") + "
\r\n"; + } + + sPageRet += Footer(); +} + +Csock* CAdminSock::GetSockObj(const CString& sHost, unsigned short uPort) { + CAdminSock* pSock = new CAdminSock(m_pModule, sHost, uPort); + pSock->SetSockName("Admin::Client"); + pSock->SetTimeout(120); + m_pModule->AddSock(pSock); + + return pSock; +} + +CAdminSock::CAdminSock(CAdminMod* pModule) : CHTTPSock() { + m_pModule = pModule; + m_pModule->AddSock(this); +} +CAdminSock::CAdminSock(CAdminMod* pModule, const CString& sHostname, unsigned short uPort, int iTimeout) : CHTTPSock(sHostname, uPort, iTimeout) { + m_pModule = pModule; + m_pModule->AddSock(this); +} +CAdminSock::~CAdminSock() { + m_pModule->SockDestroyed(this); +} + +bool CAdminSock::OnPageRequest(const CString& sURI, CString& sPageRet) { + DEBUG_ONLY(cout << "Request for [" << sURI << "] "); + if (!ForceLogin()) { + DEBUG_ONLY(cout << "- User not logged in!" << endl); + return false; + } + + if (sURI == "/") { + PrintMainPage(sPageRet); + } else if (sURI == "/adduser") { + if (!UserPage(sPageRet)) { + DEBUG_ONLY(cout << "- 302 Redirect" << endl); + return false; + } + } else if (sURI == "/edituser") { + CUser* pUser = m_pModule->GetZNC()->FindUser(GetParam("user")); + + if (pUser) { + if (!UserPage(sPageRet, pUser)) { + DEBUG_ONLY(cout << "- 302 Redirect" << endl); + return false; + } + } else { + GetErrorPage(sPageRet, "No such username"); + } + } else if (sURI == "/listusers") { + ListUsersPage(sPageRet); + } else if (sURI == "/deluser") { + if (m_pModule->GetZNC()->DeleteUser(GetParam("user"))) { + DEBUG_ONLY(cout << "- 302 Redirect" << endl); + Redirect("/listusers"); + return false; + } else { + GetErrorPage(sPageRet, "No such username"); + } + } else if (sURI == "/list") { + ListPage(sPageRet); + } else { + DEBUG_ONLY(cout << "- 404 Not Found!" << endl); + return false; + } + + DEBUG_ONLY(cout << "- 200 OK!" << endl); + + return true; +} + +bool CAdminSock::UserPage(CString& sPageRet, CUser* pUser) { + if (!GetParam("submitted").ToUInt()) { + sPageRet = Header("Add User"); + + sPageRet += "
\r\n" + "\r\n" + "
Authentication\r\n" + "
Username:

\r\n" + "Password:

\r\n" + "Confirm Password:
\r\n" + "
Allowed IPs:
\r\n" + "

\r\n" + + "
IRC Information\r\n" + "
Nick:
\r\n" + "
AltNick:
\r\n" + "
AwaySuffix:
\r\n" + "
StatusPrefix:

\r\n" + "
Ident:
\r\n" + "
RealName:

\r\n" + "VHost:


\r\n" + "QuitMsg:


\r\n" + "
Servers:
\r\n" + "

\r\n" + + "
Modules\r\n"; + + set ssUserMods; + m_pModule->GetZNC()->GetModules().GetAvailableMods(ssUserMods, m_pModule->GetZNC()); + + for (set::iterator it = ssUserMods.begin(); it != ssUserMods.end(); it++) { + const CModInfo& Info = *it; + sPageRet += "" + " (" + Info.GetDescription().Escape_n(CString::EHTML) + ")
"; + } + + sPageRet += "

\r\n" + "
Channels\r\n" + "Default Modes:


\r\n" + "
Channels:
\r\n" + "

\r\n" + + "
ZNC Behavior\r\n" + "Playback Buffer Size:


\r\n" + "Options:
\r\n" + "  \r\n" + "  \r\n" + "  \r\n" + "  \r\n" + "  \r\n" + "

" + "CTCP Replies:
\r\n" + "

\r\n" + + "\r\n" + "
\r\n"; + + sPageRet += Footer(); + return true; + } + + if (!pUser) { + if (AddNewUser(sPageRet)) { + return true; + } + } + + Redirect("/listusers"); + return false; +} + +bool CAdminSock::AddNewUser(CString& sPageRet) { + CString sUsername = GetParam("username"); + if (sUsername.empty()) { + GetErrorPage(sPageRet, "Invalid Submission [Username is required]"); + return true; + } + + if (m_pModule->GetZNC()->FindUser(sUsername)) { + GetErrorPage(sPageRet, "Invalid Submission [User " + sUsername.Escape_n(CString::EHTML) + " already exists]"); + return true; + } + + CString sArg = GetParam("password"); + + if (sArg != GetParam("password2")) { + GetErrorPage(sPageRet, "Invalid Submission [Passwords do not match]"); + return true; + } + + CUser* pNewUser = new CUser(sUsername, m_pModule->GetZNC()); + + if (!sArg.empty()) { + pNewUser->SetPass(sArg.MD5(), true); + } + + VCString vsArgs; + GetParam("servers").Split("\n", vsArgs); + unsigned int a = 0; + + for (a = 0; a < vsArgs.size(); a++) { + pNewUser->AddServer(vsArgs[a].TrimRight_n("\r")); + } + + GetParam("allowedips").Split("\n", vsArgs); + for (a = 0; a < vsArgs.size(); a++) { + pNewUser->AddAllowedHost(vsArgs[a]); + } + + GetParam("ctcpreplies").Split("\n", vsArgs); + for (a = 0; a < vsArgs.size(); a++) { + const CString& sReply = vsArgs[a]; + pNewUser->AddCTCPReply(sReply.Token(0), sReply.Token(1, true)); + } + + GetParamValues("loadmod", vsArgs); + for (a = 0; a < vsArgs.size(); a++) { + CString sModRet; + pNewUser->GetModules().LoadModule(vsArgs[a], "", pNewUser, sModRet); + } + + sArg = GetParam("nick"); if (!sArg.empty()) { pNewUser->SetNick(sArg); } + sArg = GetParam("altnick"); if (!sArg.empty()) { pNewUser->SetAltNick(sArg); } + sArg = GetParam("awaysuffix"); if (!sArg.empty()) { pNewUser->SetAwaySuffix(sArg); } + sArg = GetParam("statusprefix"); if (!sArg.empty()) { pNewUser->SetStatusPrefix(sArg); } + sArg = GetParam("ident"); if (!sArg.empty()) { pNewUser->SetIdent(sArg); } + sArg = GetParam("realname"); if (!sArg.empty()) { pNewUser->SetRealName(sArg); } + sArg = GetParam("vhost"); if (!sArg.empty()) { pNewUser->SetVHost(sArg); } + sArg = GetParam("quitmsg"); if (!sArg.empty()) { pNewUser->SetQuitMsg(sArg); } + sArg = GetParam("chanmodes"); if (!sArg.empty()) { pNewUser->SetDefaultChanModes(sArg); } + + pNewUser->SetBufferCount(GetParam("bufsize").ToUInt()); + pNewUser->SetKeepBuffer(GetParam("keepbuffer").ToBool()); + pNewUser->SetBounceDCCs(GetParam("bouncedccs").ToBool()); + pNewUser->SetAutoCycle(GetParam("autocycle").ToBool()); + pNewUser->SetKeepNick(GetParam("keepnick").ToBool()); + pNewUser->SetUseClientIP(GetParam("useclientip").ToBool()); + pNewUser->SetDenyLoadMod(GetParam("denyloadmod").ToBool()); + + GetParam("channels").Split("\n", vsArgs); + + for (a = 0; a < vsArgs.size(); a++) { + pNewUser->AddChan(vsArgs[a].TrimRight_n("\r")); + } + + CString sErr; + if (!pNewUser->IsValid(sErr)) { + delete pNewUser; + GetErrorPage(sPageRet, "Invalid submission [" + sErr.Escape_n(CString::EHTML) + "]"); + return true; + } + + m_pModule->GetZNC()->AddUser(pNewUser); + + return false; +} + +GLOBALMODULEDEFS(CAdminMod, "Add, Edit, Remove users on the fly")