1 /*
2  * Copyright (C) 2004-2020 ZNC, see the NOTICE file for details.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <gtest/gtest.h>
18 #include <gmock/gmock.h>
19 #include "IRCTest.h"
20 
21 using ::testing::IsEmpty;
22 using ::testing::ElementsAre;
23 
24 class ClientTest : public IRCTest {
25   protected:
testPass(const CString & sInput,const CString & sUser,const CString & sIdentifier,const CString & sNetwork,const CString & sPass) const26     void testPass(const CString& sInput, const CString& sUser,
27                   const CString& sIdentifier, const CString& sNetwork,
28                   const CString& sPass) const {
29         CClient client;
30         client.ParsePass(sInput);
31         EXPECT_EQ(client.m_sUser, sUser);
32         EXPECT_EQ(client.m_sIdentifier, sIdentifier);
33         EXPECT_EQ(client.m_sNetwork, sNetwork);
34         EXPECT_EQ(client.m_sPass, sPass);
35     }
36 
testUser(const CString & sInput,const CString & sUser,const CString & sIdentifier,const CString & sNetwork) const37     void testUser(const CString& sInput, const CString& sUser,
38                   const CString& sIdentifier, const CString& sNetwork) const {
39         CClient client;
40         client.ParseUser(sInput);
41         EXPECT_EQ(client.m_sUser, sUser);
42         EXPECT_EQ(client.m_sIdentifier, sIdentifier);
43         EXPECT_EQ(client.m_sNetwork, sNetwork);
44     }
45 };
46 
TEST_F(ClientTest,Pass)47 TEST_F(ClientTest, Pass) {
48     // clang-format off
49     testPass("p@ss#w0rd",                                 "",            "",           "",         "p@ss#w0rd");
50     testPass("user:p@ss#w0rd",                            "user",        "",           "",         "p@ss#w0rd");
51     testPass("user/net-work:p@ss#w0rd",                   "user",        "",           "net-work", "p@ss#w0rd");
52     testPass("user@identifier:p@ss#w0rd",                 "user",        "identifier", "",         "p@ss#w0rd");
53     testPass("user@identifier/net-work:p@ss#w0rd",        "user",        "identifier", "net-work", "p@ss#w0rd");
54 
55     testPass("user@znc.in:p@ss#w0rd",                     "user@znc.in", "",           "",         "p@ss#w0rd");
56     testPass("user@znc.in/net-work:p@ss#w0rd",            "user@znc.in", "",           "net-work", "p@ss#w0rd");
57     testPass("user@znc.in@identifier:p@ss#w0rd",          "user@znc.in", "identifier", "",         "p@ss#w0rd");
58     testPass("user@znc.in@identifier/net-work:p@ss#w0rd", "user@znc.in", "identifier", "net-work", "p@ss#w0rd");
59     // clang-format on
60 }
61 
TEST_F(ClientTest,User)62 TEST_F(ClientTest, User) {
63     // clang-format off
64     testUser("user/net-work",                   "user",        "",           "net-work");
65     testUser("user@identifier",                 "user",        "identifier", "");
66     testUser("user@identifier/net-work",        "user",        "identifier", "net-work");
67 
68     testUser("user@znc.in/net-work",            "user@znc.in", "",           "net-work");
69     testUser("user@znc.in@identifier",          "user@znc.in", "identifier", "");
70     testUser("user@znc.in@identifier/net-work", "user@znc.in", "identifier", "net-work");
71     // clang-format on
72 }
73 
TEST_F(ClientTest,AccountNotify)74 TEST_F(ClientTest, AccountNotify) {
75     CMessage msg(":nick!user@host ACCOUNT accountname");
76     EXPECT_FALSE(m_pTestClient->HasAccountNotify());
77     m_pTestClient->PutClient(msg);
78     EXPECT_THAT(m_pTestClient->vsLines, IsEmpty());
79     m_pTestClient->SetAccountNotify(true);
80     EXPECT_TRUE(m_pTestClient->HasAccountNotify());
81     m_pTestClient->PutClient(msg);
82     EXPECT_THAT(m_pTestClient->vsLines, ElementsAre(msg.ToString()));
83 }
84 
TEST_F(ClientTest,AwayNotify)85 TEST_F(ClientTest, AwayNotify) {
86     CMessage msg(":nick!user@host AWAY :message");
87     EXPECT_FALSE(m_pTestClient->HasAwayNotify());
88     m_pTestClient->PutClient(msg);
89     EXPECT_THAT(m_pTestClient->vsLines, IsEmpty());
90     m_pTestClient->SetAwayNotify(true);
91     EXPECT_TRUE(m_pTestClient->HasAwayNotify());
92     m_pTestClient->PutClient(msg);
93     EXPECT_THAT(m_pTestClient->vsLines, ElementsAre(msg.ToString()));
94 }
95 
TEST_F(ClientTest,MultiPrefixWho)96 TEST_F(ClientTest, MultiPrefixWho) {  // aka NAMESX
97     m_pTestSock->ReadLine(
98         ":server 005 guest PREFIX=(qaohv)~&@%+ NAMESX :are supported by this "
99         "server");
100     m_pTestClient->Reset();
101 
102     CMessage msg(
103         ":kenny.chatspike.net 352 guest #test grawity broken.symlink "
104         "*.chatspike.net grawity H@%+ :0 Mantas M.");
105     CMessage extmsg(
106         ":kenny.chatspike.net 352 guest #test grawity broken.symlink "
107         "*.chatspike.net grawity H@%+ :0 Mantas M.");
108     EXPECT_FALSE(m_pTestClient->HasNamesx());
109     m_pTestClient->PutClient(extmsg);
110     EXPECT_THAT(m_pTestClient->vsLines, ElementsAre(msg.ToString()));
111     m_pTestClient->SetNamesx(true);
112     EXPECT_TRUE(m_pTestClient->HasNamesx());
113     m_pTestClient->PutClient(extmsg);
114     EXPECT_THAT(m_pTestClient->vsLines,
115                 ElementsAre(msg.ToString(), extmsg.ToString()));
116 }
117 
TEST_F(ClientTest,MultiPrefixNames)118 TEST_F(ClientTest, MultiPrefixNames) {  // aka NAMESX
119     m_pTestSock->ReadLine(
120         ":server 005 guest PREFIX=(qaohv)~&@%+ NAMESX :are supported by this "
121         "server");
122     m_pTestClient->Reset();
123 
124     CMessage msg(
125         ":hades.arpa 353 guest = #tethys :~aji &Attila @alyx +KindOne Argure");
126     CMessage extmsg(
127         ":hades.arpa 353 guest = #tethys :~&@%+aji &@Attila @+alyx +KindOne "
128         "Argure");
129     EXPECT_FALSE(m_pTestClient->HasNamesx());
130     m_pTestClient->PutClient(extmsg);
131     EXPECT_THAT(m_pTestClient->vsLines, ElementsAre(msg.ToString()));
132     m_pTestClient->SetNamesx(true);
133     EXPECT_TRUE(m_pTestClient->HasNamesx());
134     m_pTestClient->PutClient(extmsg);
135     EXPECT_THAT(m_pTestClient->vsLines,
136                 ElementsAre(msg.ToString(), extmsg.ToString()));
137 }
138 
TEST_F(ClientTest,UserhostInNames)139 TEST_F(ClientTest, UserhostInNames) {  // aka UHNAMES
140     m_pTestSock->ReadLine(
141         ":server 005 guest UHNAMES :are supported by this server");
142     m_pTestClient->Reset();
143 
144     CMessage msg(":irc.bnc.im 353 guest = #atheme :Rylee somasonic");
145     CMessage extmsg(
146         ":irc.bnc.im 353 guest = #atheme :Rylee!rylai@localhost "
147         "somasonic!andrew@somasonic.org");
148     EXPECT_FALSE(m_pTestClient->HasUHNames());
149     m_pTestClient->PutClient(extmsg);
150     EXPECT_THAT(m_pTestClient->vsLines, ElementsAre(msg.ToString()));
151     m_pTestClient->SetUHNames(true);
152     EXPECT_TRUE(m_pTestClient->HasUHNames());
153     m_pTestClient->PutClient(extmsg);
154     EXPECT_THAT(m_pTestClient->vsLines,
155                 ElementsAre(msg.ToString(), extmsg.ToString()));
156 }
157 
TEST_F(ClientTest,ExtendedJoin)158 TEST_F(ClientTest, ExtendedJoin) {
159     m_pTestSock->ReadLine(":server CAP * ACK :extended-join");
160     m_pTestClient->Reset();
161 
162     CMessage msg(":nick!user@host JOIN #channel");
163     CMessage extmsg(":nick!user@host JOIN #channel account :Real Name");
164     EXPECT_FALSE(m_pTestClient->HasExtendedJoin());
165     m_pTestClient->PutClient(extmsg);
166     EXPECT_THAT(m_pTestClient->vsLines, ElementsAre(msg.ToString()));
167     m_pTestClient->SetExtendedJoin(true);
168     EXPECT_TRUE(m_pTestClient->HasExtendedJoin());
169     m_pTestClient->PutClient(extmsg);
170     EXPECT_THAT(m_pTestClient->vsLines,
171                 ElementsAre(msg.ToString(), extmsg.ToString()));
172 }
173 
TEST_F(ClientTest,StatusMsg)174 TEST_F(ClientTest, StatusMsg) {
175     m_pTestSock->ReadLine(
176         ":irc.znc.in 001 me :Welcome to the Internet Relay Network me");
177     m_pTestSock->ReadLine(
178         ":irc.znc.in 005 me CHANTYPES=# PREFIX=(ov)@+ STATUSMSG=@+ :are "
179         "supported by this server");
180 
181     m_pTestUser->SetAutoClearChanBuffer(false);
182     m_pTestClient->ReadLine("PRIVMSG @#chan :hello ops");
183 
184     EXPECT_EQ(m_pTestChan->GetBuffer().Size(), 1u);
185 
186     m_pTestUser->SetTimestampPrepend(false);
187     EXPECT_EQ(m_pTestChan->GetBuffer().GetLine(0, *m_pTestClient),
188               ":me PRIVMSG @#chan :hello ops");
189 }
190 
TEST_F(ClientTest,TagSupport)191 TEST_F(ClientTest, TagSupport) {
192     m_pTestClient->SetTagSupport("test-tag", true);
193     CMessage tagmsg("@test-tag=yes;invalid-tag=no :nick!user@host PRIVMSG #chan :text");
194     m_pTestClient->PutClient(tagmsg);
195 
196     EXPECT_THAT(m_pTestClient->vsLines,
197         ElementsAre("@test-tag=yes :nick!user@host PRIVMSG #chan :text"));
198 
199     m_pTestClient->Reset();
200     m_pTestClient->SetTagSupport("test-tag", false);
201     m_pTestClient->PutClient(tagmsg);
202 
203     EXPECT_THAT(m_pTestClient->vsLines,
204         ElementsAre(":nick!user@host PRIVMSG #chan :text"));
205 }
206 
TEST_F(ClientTest,OnUserCTCPReplyMessage)207 TEST_F(ClientTest, OnUserCTCPReplyMessage) {
208     CMessage msg("NOTICE someone :\001VERSION 123\001");
209     m_pTestModule->eAction = CModule::HALT;
210     m_pTestClient->ReadLine(msg.ToString());
211 
212     CString sReply =
213         "NOTICE someone :\x01VERSION 123 via " + CZNC::GetTag(false) + "\x01";
214 
215     EXPECT_THAT(m_pTestModule->vsHooks, ElementsAre("OnUserCTCPReplyMessage"));
216     EXPECT_THAT(m_pTestModule->vsMessages, ElementsAre(sReply));
217     EXPECT_THAT(m_pTestModule->vNetworks, ElementsAre(nullptr));
218     EXPECT_THAT(m_pTestModule->vClients, ElementsAre(m_pTestClient));
219     EXPECT_THAT(m_pTestModule->vChannels, ElementsAre(nullptr));
220     EXPECT_THAT(m_pTestSock->vsLines, IsEmpty());  // halt
221 
222     m_pTestModule->eAction = CModule::CONTINUE;
223     m_pTestClient->ReadLine(msg.ToString());
224     EXPECT_THAT(m_pTestSock->vsLines, ElementsAre(sReply));
225 }
226 
TEST_F(ClientTest,OnUserCTCPMessage)227 TEST_F(ClientTest, OnUserCTCPMessage) {
228     CMessage msg("PRIVMSG someone :\001VERSION\001");
229     m_pTestModule->eAction = CModule::HALT;
230     m_pTestClient->ReadLine(msg.ToString());
231 
232     EXPECT_THAT(m_pTestModule->vsHooks, ElementsAre("OnUserCTCPMessage"));
233     EXPECT_THAT(m_pTestModule->vsMessages, ElementsAre(msg.ToString()));
234     EXPECT_THAT(m_pTestModule->vNetworks, ElementsAre(nullptr));
235     EXPECT_THAT(m_pTestModule->vClients, ElementsAre(m_pTestClient));
236     EXPECT_THAT(m_pTestModule->vChannels, ElementsAre(nullptr));
237     EXPECT_THAT(m_pTestSock->vsLines, IsEmpty());  // halt
238 
239     m_pTestModule->eAction = CModule::CONTINUE;
240     m_pTestClient->ReadLine(msg.ToString());
241     EXPECT_THAT(m_pTestSock->vsLines, ElementsAre(msg.ToString()));
242 }
243 
TEST_F(ClientTest,OnUserActionMessage)244 TEST_F(ClientTest, OnUserActionMessage) {
245     CMessage msg("PRIVMSG #chan :\001ACTION acts\001");
246     m_pTestModule->eAction = CModule::HALT;
247     m_pTestClient->ReadLine(msg.ToString());
248 
249     EXPECT_THAT(m_pTestModule->vsHooks, ElementsAre("OnUserActionMessage"));
250     EXPECT_THAT(m_pTestModule->vsMessages, ElementsAre(msg.ToString()));
251     EXPECT_THAT(m_pTestModule->vNetworks, ElementsAre(nullptr));
252     EXPECT_THAT(m_pTestModule->vClients, ElementsAre(m_pTestClient));
253     EXPECT_THAT(m_pTestModule->vChannels, ElementsAre(m_pTestChan));
254     EXPECT_THAT(m_pTestSock->vsLines, IsEmpty());  // halt
255 
256     m_pTestModule->eAction = CModule::CONTINUE;
257     m_pTestClient->ReadLine(msg.ToString());
258     EXPECT_THAT(m_pTestSock->vsLines, ElementsAre(msg.ToString()));
259 }
260 
TEST_F(ClientTest,OnUserTextMessage)261 TEST_F(ClientTest, OnUserTextMessage) {
262     CMessage msg("PRIVMSG #chan :text");
263     m_pTestModule->eAction = CModule::HALT;
264     m_pTestClient->ReadLine(msg.ToString());
265 
266     EXPECT_THAT(m_pTestModule->vsHooks, ElementsAre("OnUserTextMessage"));
267     EXPECT_THAT(m_pTestModule->vsMessages, ElementsAre(msg.ToString()));
268     EXPECT_THAT(m_pTestModule->vNetworks, ElementsAre(nullptr));
269     EXPECT_THAT(m_pTestModule->vClients, ElementsAre(m_pTestClient));
270     EXPECT_THAT(m_pTestModule->vChannels, ElementsAre(m_pTestChan));
271     EXPECT_THAT(m_pTestSock->vsLines, IsEmpty());  // halt
272 
273     m_pTestModule->eAction = CModule::CONTINUE;
274     m_pTestClient->ReadLine(msg.ToString());
275     EXPECT_THAT(m_pTestSock->vsLines, ElementsAre(msg.ToString()));
276 }
277 
TEST_F(ClientTest,OnUserNoticeMessage)278 TEST_F(ClientTest, OnUserNoticeMessage) {
279     CMessage msg("NOTICE #chan :text");
280     m_pTestModule->eAction = CModule::HALT;
281     m_pTestClient->ReadLine(msg.ToString());
282 
283     EXPECT_THAT(m_pTestModule->vsHooks, ElementsAre("OnUserNoticeMessage"));
284     EXPECT_THAT(m_pTestModule->vsMessages, ElementsAre(msg.ToString()));
285     EXPECT_THAT(m_pTestModule->vNetworks, ElementsAre(nullptr));
286     EXPECT_THAT(m_pTestModule->vClients, ElementsAre(m_pTestClient));
287     EXPECT_THAT(m_pTestModule->vChannels, ElementsAre(m_pTestChan));
288     EXPECT_THAT(m_pTestSock->vsLines, IsEmpty());  // halt
289 
290     m_pTestModule->eAction = CModule::CONTINUE;
291     m_pTestClient->ReadLine(msg.ToString());
292     EXPECT_THAT(m_pTestSock->vsLines, ElementsAre(msg.ToString()));
293 }
294 
TEST_F(ClientTest,OnUserJoinMessage)295 TEST_F(ClientTest, OnUserJoinMessage) {
296     CMessage msg("JOIN #chan key");
297     m_pTestModule->eAction = CModule::HALT;
298     m_pTestClient->ReadLine(msg.ToString());
299 
300     EXPECT_THAT(m_pTestModule->vsHooks, ElementsAre("OnUserJoinMessage"));
301     EXPECT_THAT(m_pTestModule->vsMessages, ElementsAre(msg.ToString()));
302     EXPECT_THAT(m_pTestModule->vNetworks, ElementsAre(nullptr));
303     EXPECT_THAT(m_pTestModule->vClients, ElementsAre(m_pTestClient));
304     EXPECT_THAT(m_pTestModule->vChannels, ElementsAre(m_pTestChan));
305     EXPECT_THAT(m_pTestSock->vsLines, IsEmpty());  // halt
306 
307     m_pTestModule->eAction = CModule::CONTINUE;
308     m_pTestClient->ReadLine(msg.ToString());
309     EXPECT_THAT(m_pTestSock->vsLines, ElementsAre(msg.ToString()));
310 }
311 
TEST_F(ClientTest,OnUserPartMessage)312 TEST_F(ClientTest, OnUserPartMessage) {
313     m_pTestChan->SetIsOn(true);
314     CMessage msg("PART #chan");
315     m_pTestModule->eAction = CModule::HALT;
316     m_pTestClient->ReadLine(msg.ToString());
317 
318     EXPECT_THAT(m_pTestModule->vsHooks, ElementsAre("OnUserPartMessage"));
319     EXPECT_THAT(m_pTestModule->vsMessages, ElementsAre(msg.ToString()));
320     EXPECT_THAT(m_pTestModule->vNetworks, ElementsAre(nullptr));
321     EXPECT_THAT(m_pTestModule->vClients, ElementsAre(m_pTestClient));
322     EXPECT_THAT(m_pTestModule->vChannels, ElementsAre(m_pTestChan));
323     EXPECT_THAT(m_pTestSock->vsLines, IsEmpty());  // halt
324 
325     m_pTestModule->eAction = CModule::CONTINUE;
326     m_pTestClient->ReadLine(msg.ToString());
327     EXPECT_THAT(m_pTestSock->vsLines, ElementsAre(msg.ToString()));
328 }
329 
TEST_F(ClientTest,OnUserTopicMessage)330 TEST_F(ClientTest, OnUserTopicMessage) {
331     CMessage msg("TOPIC #chan :topic");
332     m_pTestModule->eAction = CModule::HALT;
333     m_pTestClient->ReadLine(msg.ToString());
334 
335     EXPECT_THAT(m_pTestModule->vsHooks, ElementsAre("OnUserTopicMessage"));
336     EXPECT_THAT(m_pTestModule->vsMessages, ElementsAre(msg.ToString()));
337     EXPECT_THAT(m_pTestModule->vNetworks, ElementsAre(nullptr));
338     EXPECT_THAT(m_pTestModule->vClients, ElementsAre(m_pTestClient));
339     EXPECT_THAT(m_pTestModule->vChannels, ElementsAre(m_pTestChan));
340     EXPECT_THAT(m_pTestSock->vsLines, IsEmpty());  // halt
341 
342     m_pTestModule->eAction = CModule::CONTINUE;
343     m_pTestClient->ReadLine(msg.ToString());
344     EXPECT_THAT(m_pTestSock->vsLines, ElementsAre(msg.ToString()));
345 }
346 
TEST_F(ClientTest,OnUserQuitMessage)347 TEST_F(ClientTest, OnUserQuitMessage) {
348     CMessage msg("QUIT :reason");
349     m_pTestModule->eAction = CModule::HALT;
350     m_pTestClient->ReadLine(msg.ToString());
351 
352     EXPECT_THAT(m_pTestModule->vsHooks, ElementsAre("OnUserQuitMessage"));
353     EXPECT_THAT(m_pTestModule->vsMessages, ElementsAre(msg.ToString()));
354     EXPECT_THAT(m_pTestModule->vNetworks, ElementsAre(nullptr));
355     EXPECT_THAT(m_pTestModule->vClients, ElementsAre(m_pTestClient));
356     EXPECT_THAT(m_pTestModule->vChannels, ElementsAre(nullptr));
357     EXPECT_THAT(m_pTestSock->vsLines, IsEmpty());  // halt
358 
359     m_pTestModule->eAction = CModule::CONTINUE;
360     m_pTestClient->ReadLine(msg.ToString());
361     EXPECT_THAT(m_pTestSock->vsLines, IsEmpty());  // quit is never forwarded
362 }
363 
TEST_F(ClientTest,OnSendToClientMessage)364 TEST_F(ClientTest, OnSendToClientMessage) {
365     CMessage msg("PRIVMSG #chan :text");
366     m_pTestModule->eAction = CModule::HALT;
367     m_pTestModule->bSendHooks = true;
368     m_pTestClient->PutClient(msg.ToString());
369 
370     EXPECT_THAT(m_pTestModule->vsHooks, ElementsAre("OnSendToClientMessage"));
371     EXPECT_THAT(m_pTestModule->vsMessages, ElementsAre(msg.ToString()));
372     EXPECT_THAT(m_pTestModule->vNetworks, ElementsAre(m_pTestClient->GetNetwork()));
373     EXPECT_THAT(m_pTestModule->vClients, ElementsAre(m_pTestClient));
374     EXPECT_THAT(m_pTestModule->vChannels, ElementsAre(nullptr));
375     EXPECT_THAT(m_pTestSock->vsLines, IsEmpty());  // halt
376 
377     m_pTestModule->eAction = CModule::CONTINUE;
378     m_pTestClient->ReadLine(msg.ToString());
379 
380     EXPECT_THAT(m_pTestSock->vsLines, ElementsAre(msg.ToString()));
381     m_pTestModule->bSendHooks = false;
382 }
383