mirror of
https://github.com/znc/znc.git
synced 2026-03-28 17:42:41 +01:00
Allow clients to specify an ID via PASS or USER
- PASS [user[@identifier][/network]:]password - USER user[@identifier][/network] ... NOTE: There's a slight ambiguosity with the '@' character, which happens to be a valid character in usernames, but also acts as a marker for the identifier. Therefore, '@' is considered as part of the username if it's followed by non-word characters (as in an email address), otherwise as a marker for an identifier. This is only an enabler for #343. The rest can be done with modules: - managing client ID specific playback buffers - filtering channels based on the client ID The reason this should be part of ZNC core is that only global modules have access to OnUnknownUserRaw(), which is needed to capture USER/PASS. First of all, the aforementioned modules shouldn't be global. Furthermore, it would be possible to have only one module that parsed and removed the client ID so that ZNC core woulnd't choke.
This commit is contained in:
@@ -118,20 +118,7 @@ void CClient::ReadLine(const CString& sData) {
|
||||
m_bGotPass = true;
|
||||
|
||||
CString sAuthLine = sLine.Token(1, true).TrimPrefix_n();
|
||||
|
||||
// [user[/network]:]password
|
||||
if (sAuthLine.find(":") == CString::npos) {
|
||||
m_sPass = sAuthLine;
|
||||
sAuthLine = "";
|
||||
} else {
|
||||
m_sPass = sAuthLine.Token(1, true, ":");
|
||||
sAuthLine = sAuthLine.Token(0, false, ":");
|
||||
}
|
||||
|
||||
if (!sAuthLine.empty()) {
|
||||
m_sUser = sAuthLine.Token(0, false, "/");
|
||||
m_sNetwork = sAuthLine.Token(1, true, "/");
|
||||
}
|
||||
ParsePass(sAuthLine);
|
||||
|
||||
AuthUser();
|
||||
return; // Don't forward this msg. ZNC has already registered us.
|
||||
@@ -144,12 +131,10 @@ void CClient::ReadLine(const CString& sData) {
|
||||
AuthUser();
|
||||
return; // Don't forward this msg. ZNC will handle nick changes until auth is complete
|
||||
} else if (sCommand.Equals("USER")) {
|
||||
// user[/network]
|
||||
CString sAuthLine = sLine.Token(1);
|
||||
|
||||
if (m_sUser.empty() && !sAuthLine.empty()) {
|
||||
m_sUser = sAuthLine.Token(0, false, "/");
|
||||
m_sNetwork = sAuthLine.Token(1, true, "/");
|
||||
ParseUser(sAuthLine);
|
||||
}
|
||||
|
||||
m_bGotUser = true;
|
||||
@@ -771,9 +756,12 @@ void CClient::PutIRC(const CString& sLine) {
|
||||
CString CClient::GetFullName() const {
|
||||
if (!m_pUser)
|
||||
return GetRemoteIP();
|
||||
if (!m_pNetwork)
|
||||
return m_pUser->GetUserName();
|
||||
return m_pUser->GetUserName() + "/" + m_pNetwork->GetName();
|
||||
CString sFullName = m_pUser->GetUserName();
|
||||
if (!m_sIdentifier.empty())
|
||||
sFullName += "@" + m_sIdentifier;
|
||||
if (m_pNetwork)
|
||||
sFullName += "/" + m_pNetwork->GetName();
|
||||
return sFullName;
|
||||
}
|
||||
|
||||
void CClient::PutClient(const CString& sLine) {
|
||||
@@ -849,6 +837,25 @@ CString CClient::GetNickMask() const {
|
||||
return GetNick() + "!" + (m_pNetwork ? m_pNetwork->GetBindHost() : m_pUser->GetIdent()) + "@" + sHost;
|
||||
}
|
||||
|
||||
bool CClient::IsValidIdentifier(const CString& sIdentifier) {
|
||||
// ^[-\w]+$
|
||||
|
||||
if (sIdentifier.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *p = sIdentifier.c_str();
|
||||
while (*p) {
|
||||
if (*p != '_' && *p != '-' && !isalnum(*p)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CClient::RespondCap(const CString& sResponse)
|
||||
{
|
||||
PutClient(":irc.znc.in CAP " + GetNick() + " " + sResponse);
|
||||
@@ -971,3 +978,47 @@ void CClient::HandleCap(const CString& sLine)
|
||||
PutClient(":irc.znc.in 410 " + GetNick() + " " + sSubCmd + " :Invalid CAP subcommand");
|
||||
}
|
||||
}
|
||||
|
||||
void CClient::ParsePass(const CString& sAuthLine) {
|
||||
// [user[@identifier][/network]:]password
|
||||
|
||||
const size_t uColon = sAuthLine.find(":");
|
||||
if (uColon != CString::npos) {
|
||||
m_sPass = sAuthLine.substr(uColon + 1);
|
||||
|
||||
ParseUser(sAuthLine.substr(0, uColon));
|
||||
} else {
|
||||
m_sPass = sAuthLine;
|
||||
}
|
||||
}
|
||||
|
||||
void CClient::ParseUser(const CString& sAuthLine) {
|
||||
// user[@identifier][/network]
|
||||
|
||||
const size_t uSlash = sAuthLine.rfind("/");
|
||||
if (uSlash != CString::npos) {
|
||||
m_sNetwork = sAuthLine.substr(uSlash + 1);
|
||||
|
||||
ParseIdentifier(sAuthLine.substr(0, uSlash));
|
||||
} else {
|
||||
ParseIdentifier(sAuthLine);
|
||||
}
|
||||
}
|
||||
|
||||
void CClient::ParseIdentifier(const CString& sAuthLine) {
|
||||
// user[@identifier]
|
||||
|
||||
const size_t uAt = sAuthLine.rfind("@");
|
||||
if (uAt != CString::npos) {
|
||||
const CString sId = sAuthLine.substr(uAt + 1);
|
||||
|
||||
if (IsValidIdentifier(sId)) {
|
||||
m_sIdentifier = sId;
|
||||
m_sUser = sAuthLine.substr(0, uAt);
|
||||
} else {
|
||||
m_sUser = sAuthLine;
|
||||
}
|
||||
} else {
|
||||
m_sUser = sAuthLine;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user