34 char delimeter='\n'; |
35 char delimeter='\n'; |
35 |
36 |
36 HWNewNet::HWNewNet() : |
37 HWNewNet::HWNewNet() : |
37 isChief(false), |
38 isChief(false), |
38 m_game_connected(false), |
39 m_game_connected(false), |
39 loginStep(0), |
|
40 netClientState(Disconnected) |
40 netClientState(Disconnected) |
41 { |
41 { |
42 m_roomsListModel = new RoomsListModel(this); |
42 m_roomsListModel = new RoomsListModel(this); |
43 |
43 |
44 m_playersModel = new PlayersListModel(this); |
44 m_playersModel = new PlayersListModel(this); |
236 } |
236 } |
237 } |
237 } |
238 |
238 |
239 void HWNewNet::SendPasswordHash(const QString & hash) |
239 void HWNewNet::SendPasswordHash(const QString & hash) |
240 { |
240 { |
241 RawSendNet(QString("PASSWORD%1%2").arg(delimeter).arg(hash)); |
241 // don't send it immediately, only store and check if server asked us for a password |
|
242 m_passwordHash = hash; |
|
243 |
|
244 maybeSendPassword(); |
242 } |
245 } |
243 |
246 |
244 void HWNewNet::ParseCmd(const QStringList & lst) |
247 void HWNewNet::ParseCmd(const QStringList & lst) |
245 { |
248 { |
246 qDebug() << "Server: " << lst; |
249 qDebug() << "Server: " << lst; |
295 RawSendNet(QString("NICK%1%2").arg(delimeter).arg(mynick)); |
298 RawSendNet(QString("NICK%1%2").arg(delimeter).arg(mynick)); |
296 RawSendNet(QString("PROTO%1%2").arg(delimeter).arg(*cProtoVer)); |
299 RawSendNet(QString("PROTO%1%2").arg(delimeter).arg(*cProtoVer)); |
297 netClientState = Connected; |
300 netClientState = Connected; |
298 m_game_connected = true; |
301 m_game_connected = true; |
299 emit adminAccess(false); |
302 emit adminAccess(false); |
|
303 return; |
|
304 } |
|
305 |
|
306 if (lst[0] == "SERVER_AUTH") |
|
307 { |
|
308 if(lst.size() < 2) |
|
309 { |
|
310 qWarning("Net: Malformed SERVER_AUTH message"); |
|
311 return; |
|
312 } |
|
313 |
|
314 if(lst[2] != m_serverHash) |
|
315 { |
|
316 Error("Server authentication error"); |
|
317 Disconnect(); |
|
318 } else |
|
319 { |
|
320 // empty m_serverHash variable means no authentication was performed |
|
321 // or server passed authentication |
|
322 m_serverHash.clear(); |
|
323 } |
|
324 |
300 return; |
325 return; |
301 } |
326 } |
302 |
327 |
303 if (lst[0] == "PING") |
328 if (lst[0] == "PING") |
304 { |
329 { |
513 |
538 |
514 for(int i = 1; i < lst.size(); ++i) |
539 for(int i = 1; i < lst.size(); ++i) |
515 { |
540 { |
516 if (lst[i] == mynick) |
541 if (lst[i] == mynick) |
517 { |
542 { |
|
543 // check if server is authenticated or no authentication was performed at all |
|
544 if(!m_serverHash.isEmpty()) |
|
545 { |
|
546 Error(tr("Server authentication error")); |
|
547 |
|
548 Disconnect(); |
|
549 } |
|
550 |
518 netClientState = InLobby; |
551 netClientState = InLobby; |
519 RawSendNet(QString("LIST")); |
552 RawSendNet(QString("LIST")); |
520 emit connected(); |
553 emit connected(); |
521 } |
554 } |
522 |
555 |
576 return; |
609 return; |
577 } |
610 } |
578 |
611 |
579 if (lst[0] == "ASKPASSWORD") |
612 if (lst[0] == "ASKPASSWORD") |
580 { |
613 { |
|
614 // server should send us salt of at least 16 characters |
|
615 |
|
616 if(lst.size() < 2 || lst[1].size() < 16) |
|
617 { |
|
618 qWarning("Net: Bad ASKPASSWORD message"); |
|
619 return; |
|
620 } |
|
621 |
581 emit NickRegistered(mynick); |
622 emit NickRegistered(mynick); |
582 m_nick_registered = true; |
623 m_nick_registered = true; |
|
624 |
|
625 // store server salt |
|
626 // when this variable is set, it is assumed that server asked us for a password |
|
627 m_serverSalt = lst[1]; |
|
628 m_clientSalt = QUuid::createUuid().toString(); |
|
629 |
|
630 maybeSendPassword(); |
|
631 |
583 return; |
632 return; |
584 } |
633 } |
585 |
634 |
586 if (lst[0] == "NOTICE") |
635 if (lst[0] == "NOTICE") |
587 { |
636 { |
1081 void HWNewNet::roomPasswordEntered(const QString &password) |
1130 void HWNewNet::roomPasswordEntered(const QString &password) |
1082 { |
1131 { |
1083 if(!myroom.isEmpty()) |
1132 if(!myroom.isEmpty()) |
1084 JoinRoom(myroom, password); |
1133 JoinRoom(myroom, password); |
1085 } |
1134 } |
|
1135 |
|
1136 void HWNewNet::maybeSendPassword() |
|
1137 { |
|
1138 /* When we got password hash, and server asked us for a password, perform mutual authentication: |
|
1139 * at this point we have salt chosen by server |
|
1140 * client sends client salt and hash of secret (password hash) salted with client salt, server salt, |
|
1141 * and static salt (predefined string + protocol number) |
|
1142 * server should respond with hash of the same set in different order. |
|
1143 */ |
|
1144 |
|
1145 if(m_passwordHash.isEmpty() || m_serverSalt.isEmpty()) |
|
1146 return; |
|
1147 |
|
1148 QString hash; |
|
1149 |
|
1150 hash = QCryptographicHash::hash( |
|
1151 m_clientSalt.toAscii() |
|
1152 .append(m_serverSalt.toAscii()) |
|
1153 .append(m_passwordHash) |
|
1154 .append(cProtoVer->toAscii()) |
|
1155 .append("!hedgewars") |
|
1156 , QCryptographicHash::Sha1); |
|
1157 |
|
1158 m_serverHash = QCryptographicHash::hash( |
|
1159 m_serverSalt.toAscii() |
|
1160 .append(m_clientSalt.toAscii()) |
|
1161 .append(m_passwordHash) |
|
1162 .append(cProtoVer->toAscii()) |
|
1163 .append("!hedgewars") |
|
1164 , QCryptographicHash::Sha1); |
|
1165 |
|
1166 RawSendNet(QString("PASSWORD%1%2%1%3").arg(delimeter).arg(hash).arg(m_clientSalt)); |
|
1167 } |