<commit_before>#include "main.h"
#include "User.h"
#include "Nick.h"
#include "Modules.h"
#include "Chan.h"
#include "znc.h"
#include "HTTPSock.h"
#include "Server.h"
#include <map>

using std::map;

class CIMAPAuthMod;

class CIMAPSock : public CSocket {
public:
	CIMAPSock(CIMAPAuthMod* pModule, CSmartPtr<CAuthBase> Auth)
		: CSocket((CModule*) pModule, "IMAPMod"), m_spAuth(Auth) {
			m_pIMAPMod = pModule;
			m_bSentReply = false;
			m_bSentLogin = false;
			EnableReadLine();
	}

	virtual ~CIMAPSock() {
		if (!m_bSentReply) {
			m_spAuth->RefuseLogin("IMAP server is down, please try again later");
		}
	}

	virtual void ReadLine(const CString& sLine);
private:
protected:
	CIMAPAuthMod*			m_pIMAPMod;
	bool					m_bSentLogin;
	bool					m_bSentReply;
	CSmartPtr<CAuthBase>	m_spAuth;
};


class CIMAPAuthMod : public CGlobalModule {
public:
	GLOBALMODCONSTRUCTOR(CIMAPAuthMod) {
		m_Cache.SetTTL(60000);
		m_sServer = "localhost";
		m_uPort = 143;
		m_bSSL = false;
	}

	virtual ~CIMAPAuthMod() {}

	virtual bool OnBoot() {
		return true;
	}

	virtual bool OnLoad(const CString& sArgs) {
		if (sArgs.Trim_n().empty()) {
			return true;	// use defaults
		}

		m_sServer = sArgs.Token(0);
		CString sPort = sArgs.Token(1);
		m_sUserFormat = sArgs.Token(2);

		if (sPort.Left(1) == "+") {
			m_bSSL = true;
			sPort.LeftChomp();
		}

		unsigned short uPort = sPort.ToUShort();

		if (uPort) {
			m_uPort = uPort;
		}

		return true;
	}

	virtual EModRet OnLoginAttempt(CSmartPtr<CAuthBase> Auth) {
		CUser* pUser = CZNC::Get().FindUser(Auth->GetUsername());

		if (!pUser) {	// @todo Will want to do some sort of && !m_bAllowCreate in the future
			Auth->RefuseLogin("Invalid User - Halting IMAP Lookup");
			return HALT;
		}

		if (pUser && m_Cache.HasItem(CString(Auth->GetUsername() + ":" + Auth->GetPassword()).MD5())) {
			DEBUG_ONLY(cerr << "+++ Found in cache" << endl);
			Auth->AcceptLogin(*pUser);
			return HALT;
		}

		CIMAPSock* pSock = new CIMAPSock(this, Auth);
		pSock->Connect(m_sServer, m_uPort, m_bSSL, 20);

		return HALT;
	}

	virtual void OnModCommand(const CString& sLine) {
		ListSockets();
	}

	void CacheLogin(const CString& sLogin) {
		m_Cache.AddItem(sLogin);
	}

	// Getters
	const CString& GetUserFormat() const { return m_sUserFormat; }
	// !Getters
private:
	// Settings
	CString				m_sServer;
	unsigned short		m_uPort;
	bool				m_bSSL;
	CString				m_sUserFormat;
	// !Settings

	TCacheMap<CString>	m_Cache;
};

void CIMAPSock::ReadLine(const CString& sLine) {
	if (!m_bSentLogin) {
		CString sUsername = m_spAuth->GetUsername();
		m_bSentLogin = true;

		const CString& sFormat = m_pIMAPMod->GetUserFormat();

		if (!sFormat.empty()) {
			if (sFormat.find('%') != CString::npos) {
				sUsername = sFormat.Replace_n("%", sUsername);
			} else {
				sUsername += sFormat;
			}
		}

		Write("AUTH LOGIN " + sUsername + " " + m_spAuth->GetPassword() + "\r\n");
	} else {
		CUser* pUser = CZNC::Get().FindUser(m_spAuth->GetUsername());

		if (pUser && sLine.Left(7).CaseCmp("AUTH OK") == 0) {
			m_spAuth->AcceptLogin(*pUser);
			m_pIMAPMod->CacheLogin(CString(m_spAuth->GetUsername() + ":" + m_spAuth->GetPassword()).MD5());		// Use MD5 so passes don't sit in memory in plain text
			DEBUG_ONLY(cerr << "+++ Successful IMAP lookup" << endl);
		} else {
			m_spAuth->RefuseLogin("Invalid Password");
			DEBUG_ONLY(cerr << "--- FAILED IMAP lookup" << endl);
		}

		m_bSentReply = true;
		Close();
	}
}

GLOBALMODULEDEFS(CIMAPAuthMod, "Allow users to authenticate via imap");
<commit_msg>Removed call to ListSockets() that was left over from debugging<commit_after>#include "main.h"
#include "User.h"
#include "Nick.h"
#include "Modules.h"
#include "Chan.h"
#include "znc.h"
#include "HTTPSock.h"
#include "Server.h"
#include <map>

using std::map;

class CIMAPAuthMod;

class CIMAPSock : public CSocket {
public:
	CIMAPSock(CIMAPAuthMod* pModule, CSmartPtr<CAuthBase> Auth)
		: CSocket((CModule*) pModule, "IMAPMod"), m_spAuth(Auth) {
			m_pIMAPMod = pModule;
			m_bSentReply = false;
			m_bSentLogin = false;
			EnableReadLine();
	}

	virtual ~CIMAPSock() {
		if (!m_bSentReply) {
			m_spAuth->RefuseLogin("IMAP server is down, please try again later");
		}
	}

	virtual void ReadLine(const CString& sLine);
private:
protected:
	CIMAPAuthMod*			m_pIMAPMod;
	bool					m_bSentLogin;
	bool					m_bSentReply;
	CSmartPtr<CAuthBase>	m_spAuth;
};


class CIMAPAuthMod : public CGlobalModule {
public:
	GLOBALMODCONSTRUCTOR(CIMAPAuthMod) {
		m_Cache.SetTTL(60000);
		m_sServer = "localhost";
		m_uPort = 143;
		m_bSSL = false;
	}

	virtual ~CIMAPAuthMod() {}

	virtual bool OnBoot() {
		return true;
	}

	virtual bool OnLoad(const CString& sArgs) {
		if (sArgs.Trim_n().empty()) {
			return true;	// use defaults
		}

		m_sServer = sArgs.Token(0);
		CString sPort = sArgs.Token(1);
		m_sUserFormat = sArgs.Token(2);

		if (sPort.Left(1) == "+") {
			m_bSSL = true;
			sPort.LeftChomp();
		}

		unsigned short uPort = sPort.ToUShort();

		if (uPort) {
			m_uPort = uPort;
		}

		return true;
	}

	virtual EModRet OnLoginAttempt(CSmartPtr<CAuthBase> Auth) {
		CUser* pUser = CZNC::Get().FindUser(Auth->GetUsername());

		if (!pUser) {	// @todo Will want to do some sort of && !m_bAllowCreate in the future
			Auth->RefuseLogin("Invalid User - Halting IMAP Lookup");
			return HALT;
		}

		if (pUser && m_Cache.HasItem(CString(Auth->GetUsername() + ":" + Auth->GetPassword()).MD5())) {
			DEBUG_ONLY(cerr << "+++ Found in cache" << endl);
			Auth->AcceptLogin(*pUser);
			return HALT;
		}

		CIMAPSock* pSock = new CIMAPSock(this, Auth);
		pSock->Connect(m_sServer, m_uPort, m_bSSL, 20);

		return HALT;
	}

	virtual void OnModCommand(const CString& sLine) {
	}

	void CacheLogin(const CString& sLogin) {
		m_Cache.AddItem(sLogin);
	}

	// Getters
	const CString& GetUserFormat() const { return m_sUserFormat; }
	// !Getters
private:
	// Settings
	CString				m_sServer;
	unsigned short		m_uPort;
	bool				m_bSSL;
	CString				m_sUserFormat;
	// !Settings

	TCacheMap<CString>	m_Cache;
};

void CIMAPSock::ReadLine(const CString& sLine) {
	if (!m_bSentLogin) {
		CString sUsername = m_spAuth->GetUsername();
		m_bSentLogin = true;

		const CString& sFormat = m_pIMAPMod->GetUserFormat();

		if (!sFormat.empty()) {
			if (sFormat.find('%') != CString::npos) {
				sUsername = sFormat.Replace_n("%", sUsername);
			} else {
				sUsername += sFormat;
			}
		}

		Write("AUTH LOGIN " + sUsername + " " + m_spAuth->GetPassword() + "\r\n");
	} else {
		CUser* pUser = CZNC::Get().FindUser(m_spAuth->GetUsername());

		if (pUser && sLine.Left(7).CaseCmp("AUTH OK") == 0) {
			m_spAuth->AcceptLogin(*pUser);
			m_pIMAPMod->CacheLogin(CString(m_spAuth->GetUsername() + ":" + m_spAuth->GetPassword()).MD5());		// Use MD5 so passes don't sit in memory in plain text
			DEBUG_ONLY(cerr << "+++ Successful IMAP lookup" << endl);
		} else {
			m_spAuth->RefuseLogin("<PASSWORD> Password");
			DEBUG_ONLY(cerr << "--- FAILED IMAP lookup" << endl);
		}

		m_bSentReply = true;
		Close();
	}
}

GLOBALMODULEDEFS(CIMAPAuthMod, "Allow users to authenticate via imap");

{'fraction_non_alphanumeric': 0.15096208262591965, 'fraction_numerical': 0.005376344086021506, 'mean_word_length': 4.0099220411055985, 'pattern_counts': {'":': 4, '<': 38, '<?xml version=': 0, '>': 46, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1162098', 'n_tokens_mistral': 3064, 'n_tokens_neox': 2767, 'n_words': 574}