Merge lp:~widelands-dev/widelands/net-pwd-security into lp:widelands

Proposed by Notabilis
Status: Merged
Merged at revision: 8617
Proposed branch: lp:~widelands-dev/widelands/net-pwd-security
Merge into: lp:widelands
Diff against target: 483 lines (+168/-70)
7 files modified
src/network/internet_gaming.cc (+89/-34)
src/network/internet_gaming.h (+3/-0)
src/network/internet_gaming_protocol.h (+49/-29)
src/network/relay_protocol.h (+2/-1)
src/ui_fsmenu/multiplayer.cc (+12/-3)
src/wlapplication.cc (+13/-2)
src/wui/login_box.cc (+0/-1)
To merge this branch: bzr merge lp:~widelands-dev/widelands/net-pwd-security
Reviewer Review Type Date Requested Status
GunChleoc Approve
Review via email: mp+340540@code.launchpad.net

Commit message

Increasing password security by no longer storing and transmitting it in plaintext.

Description of the change

Increasing password security by using CHAP for transmitting the password instead of sending it in plaintext. With CHAP, a challenge (random value) is send to the connecting client and the client responds by sending back the cryptographic hash of the challenge concatenated with its secret password. A cryptographic hash function converts an input to a fixed length output while it is practically impossible to convert the output back to the input. Since the server also knows the password, it can also calculate the hash and can check the hashes whether they are equal. An attacker which captures the send hash can not do anything with it: Extracting the password is not possible and sending the hash to the server does not work since the server will send another challenge on next connect.

To reduce login time, moved TELL_IP functionality for transmitting the IPv4 address to the metaserver to an own thread.

Passwords are now stored as a cryptographic hash in the configuration file. For now, the plaintext password is left in the configuration file if it exists to allow parallel usage of build19 and trunk builds.

Also, removed "max. number of players" network command parameter when opening a game, which has long been obsolete.

This change should only affect new clients, build19 clients should still work with plaintext passwords. This branch should be merged parallel to the respective metaserver branch.

To post a comment you must log in.
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 3266. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/348394484.
Appveyor build 3075. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_net_pwd_security-3075.

Revision history for this message
GunChleoc (gunchleoc) wrote :

2 little nits, LGTM otherwise.

Which algorithm would sou recommend instead of sha-1? If it's available on Django, we should consider changing the website too.

review: Approve
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 3271. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/348602418.
Appveyor build 3080. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_net_pwd_security-3080.

Revision history for this message
Notabilis (notabilis27) wrote :

Thanks for the review. Reading the config has been fixed. Dropping the close() call is on purpose, it is done automatically in the desctructor of the class.

As secure hash algorithms we could use SHA-2 (over 10 years old but unbroken) or SHA-3 (relatively new, uses different approach). For the website we are using hashlib which seems to support both. Updating the database would probably be messy, though.

A C++ implementation is more of a problem. There are some small repositories where the algorithms are implemented in single files which could easily be integrated into widelands. The problem here is that I guess they never received any review so it might not be secure to use them. Preferably would be a tested library like OpenSSL but that would mean a further dependency for widelands. I haven't tried to extract the needed files out of it yet. (One advantage of SHA-1: It is included in boost.)

Revision history for this message
GunChleoc (gunchleoc) wrote :

OK, let's go with sha-1 for now then. We can always revisit this at some other time.

Changing it on the website would mean that everybody would need to use the "I have lost my password" function, I guess.

Revision history for this message
kaputtnik (franku) wrote :

I guess the password in this case is the password for Online gaming: https://wl.widelands.org/ggz/changepw which can be accessed through https://wl.widelands.org/profile/edit/ (the last link)

The related model is in wlggz: https://bazaar.launchpad.net/~widelands-dev/widelands-website/trunk/view/head:/wlggz/models.py

Django provides some default hashers for passwords, see https://docs.djangoproject.com/en/1.8/topics/auth/passwords/

I have no idea about creating passwords..., but it think the online gaming password could also be encrypted using django: https://docs.djangoproject.com/en/1.8/topics/auth/passwords/#module-django.contrib.auth.hashers

Maybe there is also a possibility to automatically convert old, not encrypted, passwords to encrypted ones?

Revision history for this message
Notabilis (notabilis27) wrote :

Forcing all users to reset their passwords would be a clean but uncomfortable migration step. Other possibilities would include keeping the old password until it is changed (which would probably be not anytime soon) or hashing the already hashed passwords again (would require more complicated code and no idea how secure this is).

Thanks for the links. The password I am talking about is indeed the one for online gaming, though we could consider only using one password for gaming and the website when we store it securely in the configuration file.

Based on https://bazaar.launchpad.net/~widelands-dev/widelands-website/trunk/view/head:/wlggz/forms.py and the code of the metaserver the password seems to be protected by SHA-1 currently.
From your link, Django seems to support SHA-1 and SHA-2/SHA256 but is using an different storage format from what we are using currently. We are simply storing SHA1(password) while the Django-Methods are storing "SHA1"|"salt"|sha1(password|salt) ( "|" being a string concatenation). Wouldn't be a problem but I don't know whether there is an advantage of using the Django methods over using hashlib directly.

A short explanation: Encryption and hashing are two completely different things. With Encryption you have a secret key and can later on decrypt the encrypted message by again using the key. So no information is lost by encryption, but the encrypted data is protected against everyone not owning the secret key.
With hashing, you are "compressing" your data into a byte sequence of fixed length. Naturally, information is lost this way and for cryptographic hash functions it is considered (practically) impossible to find some data which results in the same hash value. So you can calculate hash("text")=>abc but you can't do magic(abc)=>"text". Additionally, it is not feasible to find a string so hash("text1532")=>abc. Also note that there is no key involved.

At least the passwords for internet gaming are stored as SHA1 hashes in the database and I guess the passwords for the forum will also be hashed. So it is not possible to extract the password the user entered from the database and hash it again with a more secure algorithm.
What would be possible: The user is entering its password in plaintext when logging in (forum as well as lobby). We could use this plaintext password to update the database entry. This wouldn't help with inactive users, so we would need to run a ... hybrid ... system for quite some time.

Revision history for this message
Notabilis (notabilis27) wrote :

@bunnybot merge

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/network/internet_gaming.cc'
2--- src/network/internet_gaming.cc 2018-02-04 11:41:45 +0000
3+++ src/network/internet_gaming.cc 2018-03-11 10:02:09 +0000
4@@ -20,6 +20,7 @@
5 #include "network/internet_gaming.h"
6
7 #include <memory>
8+#include <thread>
9
10 #include <boost/algorithm/string.hpp>
11 #include <boost/format.hpp>
12@@ -159,7 +160,7 @@
13 s.string(clientname_);
14 s.string(build_id());
15 s.string(bool2str(reg_));
16- s.string(authenticator_);
17+ s.string(reg_ ? "" : authenticator_);
18 net->send(s);
19
20 // Now let's see, whether the metaserver is answering
21@@ -337,34 +338,76 @@
22 }
23
24 void InternetGaming::create_second_connection() {
25- NetAddress addr;
26- net->get_remote_address(&addr);
27- if (!addr.is_ipv6()) {
28+ NetAddress addr_net;
29+ net->get_remote_address(&addr_net);
30+ if (!addr_net.is_ipv6()) {
31 // Primary connection already is IPv4, abort
32 return;
33 }
34
35- if (!NetAddress::resolve_to_v4(&addr, meta_, port_)) {
36- // Could not get the IPv4 address of the metaserver? Strange :-/
37- return;
38- }
39-
40- std::unique_ptr<NetClient> tmpNet = NetClient::connect(addr);
41- if (!tmpNet || !tmpNet->is_connected()) {
42- // Connecting by IPv4 doesn't work? Well, nothing to do then
43- return;
44- }
45-
46- // Okay, we have a connection. Send the login message and terminate the connection
47- SendPacket s;
48- s.string(IGPCMD_TELL_IP);
49- s.string(boost::lexical_cast<std::string>(kInternetGamingProtocolVersion));
50- s.string(clientname_);
51- s.string(authenticator_);
52- tmpNet->send(s);
53-
54- // Close the connection
55- tmpNet->close();
56+ // Do real work in thread to reduce freezing of GUI
57+ // $this cannot become invalid since it is a global variable
58+ // Member variables of $this might change their values but it does not really matter if the thread fails
59+ std::thread([this]() {
60+
61+ NetAddress addr;
62+ if (!NetAddress::resolve_to_v4(&addr, meta_, port_)) {
63+ // Could not get the IPv4 address of the metaserver? Strange :-/
64+ return;
65+ }
66+
67+ std::unique_ptr<NetClient> tmpNet = NetClient::connect(addr);
68+ if (!tmpNet || !tmpNet->is_connected()) {
69+ // Connecting by IPv4 doesn't work? Well, nothing to do then
70+ return;
71+ }
72+
73+ // Okay, we have a connection. Send the login message and terminate the connection
74+ SendPacket s;
75+ s.string(IGPCMD_TELL_IP);
76+ s.string(boost::lexical_cast<std::string>(kInternetGamingProtocolVersion));
77+ s.string(clientname_);
78+ s.string(reg_ ? "" : authenticator_);
79+ tmpNet->send(s);
80+ if (!reg_) {
81+ // Not registered: We are done here
82+ return;
83+ }
84+
85+ // Wait for the challenge
86+ uint32_t const secs = time(nullptr);
87+ try {
88+ while (kInternetGamingTimeout > time(nullptr) - secs) {
89+ // Check if the connection is still open
90+ if (!tmpNet->is_connected()) {
91+ return;
92+ }
93+ // Try to get a packet
94+ std::unique_ptr<RecvPacket> packet = tmpNet->try_receive();
95+ if (!packet) {
96+ continue;
97+ }
98+ const std::string cmd = packet->string();
99+ if (cmd != IGPCMD_PWD_CHALLENGE) {
100+ // Wrong command, abort
101+ return;
102+ }
103+ const std::string challenge = packet->string();
104+ // Got a challenge. Calculate the response and send it
105+ SendPacket s2;
106+ s2.string(IGPCMD_PWD_CHALLENGE);
107+ s2.string(crypto::sha1(challenge + authenticator_));
108+ tmpNet->send(s2);
109+ // Our work is done
110+ return;
111+ }
112+ } catch (const std::exception& e) {
113+ log("InternetGaming: Error when trying to transmit secondary IP.\n");
114+ return;
115+ }
116+
117+ log("InternetGaming: Timeout when trying to transmit secondary IP.\n");
118+ }).detach();
119 }
120
121 /// Handle one packet received from the metaserver.
122@@ -389,7 +432,15 @@
123
124 // Are we already online?
125 if (state_ == CONNECTING) {
126- if (cmd == IGPCMD_LOGIN) {
127+ if (cmd == IGPCMD_PWD_CHALLENGE) {
128+ const std::string nonce = packet.string();
129+ SendPacket s;
130+ s.string(IGPCMD_PWD_CHALLENGE);
131+ s.string(crypto::sha1(nonce + authenticator_));
132+ net->send(s);
133+ return;
134+
135+ } else if (cmd == IGPCMD_LOGIN) {
136 // Clients request to login was granted
137 const std::string assigned_name = packet.string();
138 if (clientname_ != assigned_name) {
139@@ -401,10 +452,11 @@
140 }
141 clientname_ = assigned_name;
142 clientrights_ = packet.string();
143- if (clientrights_ == INTERNET_CLIENT_UNREGISTERED) {
144- // Might happen that we log in with less rights than we wanted to.
145+ if (reg_ && clientrights_ == INTERNET_CLIENT_UNREGISTERED) {
146+ // Permission downgrade: We logged in with less rights than we wanted to.
147 // Happens when we are already logged in with another client.
148 reg_ = false;
149+ authenticator_ = crypto::sha1(clientname_ + authenticator_);
150 }
151 state_ = LOBBY;
152 log("InternetGaming: Client %s logged in.\n", clientname_.c_str());
153@@ -412,7 +464,7 @@
154
155 } else if (cmd == IGPCMD_ERROR) {
156 std::string errortype = packet.string();
157- if (errortype != "LOGIN" && errortype != "RELOGIN") {
158+ if (errortype != IGPCMD_LOGIN && errortype != IGPCMD_PWD_CHALLENGE) {
159 log("InternetGaming: Strange ERROR in connecting state: %s\n", errortype.c_str());
160 throw WLWarning(
161 _("Mixed up"), _("The metaserver sent a strange ERROR during connection"));
162@@ -425,11 +477,12 @@
163 } else {
164 logout();
165 set_error();
166+ log("InternetGaming: Expected a LOGIN, PWD_CHALLENGE or ERROR packet from server, but received "
167+ "command %s. Maybe the metaserver is using a different protocol version?", cmd.c_str());
168 throw WLWarning(
169 _("Unexpected packet"),
170- _("Expected a LOGIN, RELOGIN or REJECTED packet from server, but received command "
171- "%s. Maybe the metaserver is using a different protocol version ?"),
172- cmd.c_str());
173+ _("Received an unexpected network packet from the metaserver. The metaserver could be "
174+ "using a different protocol version. If the error persists, try updating your game."));
175 }
176 }
177 try {
178@@ -589,6 +642,9 @@
179 if (waitcmd_ == IGPCMD_GAME_OPEN) {
180 waitcmd_ = "";
181 }
182+ // Get the challenge
183+ std::string challenge = packet.string();
184+ relay_password_ = crypto::sha1(challenge + authenticator_);
185 // Save the received IP(s), so the client can connect to the game
186 NetAddress::parse_ip(&gameips_.first, packet.string(), kInternetRelayPort);
187 // If the next value is true, a secondary IP follows
188@@ -666,7 +722,7 @@
189 }
190
191 const std::string InternetGaming::relay_password() {
192- return authenticator_;
193+ return relay_password_;
194 }
195
196 /// called by a client to join the game \arg gamename
197@@ -701,7 +757,6 @@
198 SendPacket s;
199 s.string(IGPCMD_GAME_OPEN);
200 s.string(gamename_);
201- s.string("1024"); // Used to be maxclients, no longer used.
202 net->send(s);
203 log("InternetGaming: Client opened a game with the name %s.\n", gamename_.c_str());
204
205
206=== modified file 'src/network/internet_gaming.h'
207--- src/network/internet_gaming.h 2017-11-28 20:39:35 +0000
208+++ src/network/internet_gaming.h 2018-03-11 10:02:09 +0000
209@@ -218,6 +218,9 @@
210 std::string authenticator_;
211 bool reg_;
212
213+ /// Password for connecting as host to a game on the relay server
214+ std::string relay_password_;
215+
216 std::string meta_;
217 uint16_t port_;
218
219
220=== modified file 'src/network/internet_gaming_protocol.h'
221--- src/network/internet_gaming_protocol.h 2017-11-29 20:43:35 +0000
222+++ src/network/internet_gaming_protocol.h 2018-03-11 10:02:09 +0000
223@@ -36,9 +36,10 @@
224 * 2: Between build 19 and build 20 - Added UUID to allow reconnect with same username after
225 * crashes. When logging twice with a registered account, the second connection gets a free
226 * username assigned. Dropping RELOGIN command.
227- * 3: Between build 19 and build 20 - Added network relay for internet games [supported]
228+ * 3: Between build 19 and build 20 - Added network relay for internet games
229+ * 4: Between build 19 and build 20 - Using CHAP for password authentication [supported]
230 */
231-constexpr unsigned int kInternetGamingProtocolVersion = 3;
232+constexpr unsigned int kInternetGamingProtocolVersion = 4;
233
234 /**
235 * The default timeout time after which the client tries to resend a package or even finally closes
236@@ -110,10 +111,8 @@
237 * 1) Linking connections with IPv4 and IPv6
238 * The UUID is used on the metaserver to link multiple connections by the same client. This
239 * normally happens when the client supports IPv4 and IPv6 and connects with both protocol versions.
240- * This
241- * way, the metaserver knows that the client supports both versions and can show games / offer its
242- * game
243- * of/for clients with both protocol versions.
244+ * This way, the metaserver knows that the client supports both versions and can show games / offer its
245+ * game of/for clients with both protocol versions.
246 *
247 * When a network client connects to the metaserver with (RE)LOGIN it also sends the UUID.
248 * When "another" netclient connects to the metaserver and sends TELL_IP containing the same UUID,
249@@ -122,11 +121,9 @@
250 *
251 * 2) Reconnect after crash / network problems.
252 * When Widelands breaks the connection without logging out, the server still assumes that the old
253- * connection is active. So when the player reconnects, another name is chosen. Sending the UUID
254- * allows
255+ * connection is active. So when the player reconnects, another name is chosen. Sending the UUID allows
256 * to reclaim the old name, since the server recognizes that there isn't a second player trying to
257- * use
258- * the same name.
259+ * use the same name.
260 */
261
262 /**
263@@ -144,8 +141,7 @@
264 *
265 * \note If you want to change the payload of this command, change it only by appending new items.
266 * The reason is that this is the only command that can be sent by the metaserver even when
267- * the
268- * protocol versions differ.
269+ * the protocol versions differ.
270 *
271 */
272 static const std::string IGPCMD_DISCONNECT = "DISCONNECT";
273@@ -153,25 +149,30 @@
274 /**
275 * Initiate a connection.
276 *
277- * The first communication across the network stream is a LOGIN command
278+ * The first communication across the network stream is a IGPCMD_LOGIN command
279 * sent by the client, with the following payload:
280- * \li string: protocol version
281+ * \li string: protocol version (see kInternetGamingProtocolVersion)
282 * \li string: client name
283 * \li string: build_id of the client
284 * \li string: whether the client wants to login in to a registered account
285 * ("true" or "false" as string)
286- * \li string: for registered accounts: password in clear text
287+ * \li string: for registered accounts: string of length 0
288 * for unregistered users the UUID to recognize the matching IPv4 and IPv6
289 * connections or to reclaim the username after a unintended disconnect.
290 * For an explanation of the UUID, see above.
291 *
292- * If the metaserver accepts, it replies with a LOGIN command with the following payload:
293- * \li string: client name (might be different to the previously chosen one, if the client did
294- * NOT login to a registered account and either the chosen is registered or already
295- * used.)
296- * \li string: clients rights (see client rights section above)
297- *
298- * If no answer is received in \ref kInternetGamingTimeout s the client will again try to login
299+ * If the user tries to login to a registered account, a IGPCMD_PWD_CHALLENGE exchange follows before
300+ * the server replies with a IGPCMD_LOGIN or IGPCMD_ERROR message.
301+ *
302+ * If the metaserver accepts, it replies with a IGPCMD_LOGIN command with the following payload:
303+ * \li string: client name. Might be different to the previously chosen one, if the chosen
304+ * name already used or is registered (and the connecting client is not registered).
305+ * \li string: clients rights (see client rights section above)
306+ *
307+ * When the client is downgraded to an unregistered user on login, a special UUID value
308+ * of sha1(assignedName | passwordHash) has to be used on reconnects.
309+ *
310+ * If no answer is received in \ref kInternetGamingTimeout seconds the client will again try to login
311 * \ref INTERNET_GAMING_RETRIES times until it finally bails out something like "server does not
312 * answer"
313 *
314@@ -184,19 +185,37 @@
315 *
316 * Assuming the client already has a connection over IPv6 and tries to establish a secondary
317 * connection over IPv4, this is the only message sent.
318- * It should be sent as soon as a connection is established, immediately followed by closing
319- * the connection. No answer from the server should be expected.
320+ * It should be sent as soon as a connection is established.
321+ * For unregistered users, the connection should be closed immediately following the command. No
322+ * answer from the server should be expected.
323+ * For registered users, an exchange of IGPCMD_PWD_CHALLENGE commands is done before closing the
324+ * connection.
325 *
326 * Is sent by the client, with the following payload:
327- * \li string: protocol version
328+ * \li string: protocol version (see kInternetGamingProtocolVersion)
329 * \li string: client name - the one the metaserver replied at the first login
330- * \li string: for registered accounts: password in clear text
331+ * \li string: for registered accounts: string of length 0
332 * for unregistered users the UUID used on login
333 * for an explanation of the UUID, see above.
334 */
335 static const std::string IGPCMD_TELL_IP = "TELL_IP";
336
337 /**
338+ * This is sent by the metaserver after a IGPCMD_LOGIN or IGPCMD_TELL_IP by a registered client.
339+ * This is the first message of the a protocol similar to the challenge handshake authentication
340+ * protocol (CHAP) for secure transmission of the users password.
341+ * The server sends the nonce for hashing:
342+ * \li string: a nonce for hashing
343+ *
344+ * The client should answer the message by an own IGPCMD_PWD_CHALLENGE containing the hashed password:
345+ * \li string: HASH_SHA1(nonce | HASH_SHA1(password))
346+ *
347+ * If the transmitted value is correct, the normal IGPCMD_LOGIN/IGPCMD_TELL_IP sequence continues. If the
348+ * value is wrong (e.g., wrong password) the connection is terminated by the servers IGPCMD_DISCONNECT.
349+ */
350+static const std::string IGPCMD_PWD_CHALLENGE = "PWD_CHALLENGE";
351+
352+/**
353 * This command is sent by the metaserver if something went wrong.
354 * At least the following payload:
355 * \li string: IGPCMD code of the message that lead to the ERROR message or ERROR
356@@ -321,11 +340,12 @@
357
358 /**
359 * Sent by the client to announce the startup of a game with following payload:
360- * \li string: name
361- * \li string: number of maximal clients
362- * \note build_id is not necessary, as this is in every way the build_id of the hosting client.
363+ * \li string: name of the game
364+ * \note build_id is not necessary, as this is the build_id of the hosting client anyway.
365 *
366 * Sent by the metaserver to acknowledge the startup of a new game with the following payload:
367+ * \li string: a challenge that has to be "solved" to work as host of the new game.
368+ * See IGPCMD_PWD_CHALLENGE. The response is send to the relay
369 * \li string: primary ip of relay server for the game.
370 * \li string: whether a secondary ip for the relay follows ("true" or "false" as string)
371 * \li string: secondary ip of the relay - only valid if previous was true
372
373=== modified file 'src/network/relay_protocol.h'
374--- src/network/relay_protocol.h 2017-12-17 14:45:23 +0000
375+++ src/network/relay_protocol.h 2018-03-11 10:02:09 +0000
376@@ -123,7 +123,8 @@
377 * Has the following payload:
378 * \li unsigned_8: Protocol version.
379 * \li string: Game name.
380- * \li string: For the host: Password that was set on start of the relay.
381+ * \li string: For the host: Password that was set on start of the relay. Is the "solution"
382+ * for the challenge send by the metaserver on IGPCMD_GAME_OPEN
383 * For clients/observers: String "client".
384 *
385 * Is answered by kWelcome or kDisconnect (if a parameter is wrong/unknown).
386
387=== modified file 'src/ui_fsmenu/multiplayer.cc'
388--- src/ui_fsmenu/multiplayer.cc 2017-11-28 20:54:16 +0000
389+++ src/ui_fsmenu/multiplayer.cc 2018-03-11 10:02:09 +0000
390@@ -105,13 +105,22 @@
391 Section& s = g_options.pull_section("global");
392 if (auto_log_) {
393 nickname_ = s.get_string("nickname", _("nobody"));
394- password_ = s.get_string("password", "nobody");
395+ password_ = s.get_string("password_sha1", "nobody");
396 register_ = s.get_bool("registered", false);
397 } else {
398 LoginBox lb(*this);
399 if (lb.run<UI::Panel::Returncodes>() == UI::Panel::Returncodes::kOk) {
400 nickname_ = lb.get_nickname();
401- password_ = lb.get_password();
402+ /// NOTE: The password is only stored (in memory and on disk) and transmitted (over the network
403+ /// to the metaserver) as cryptographic hash. This does NOT mean that the password is stored
404+ /// securely on the local disk. While the password should be secure while transmitted to the
405+ /// metaserver (no-one can use the transmitted data to log in as the user) this is not the case
406+ /// for local storage. The stored hash of the password makes it hard to look at the configuration
407+ /// file and figure out the plaintext password to, e.g., log in on the forum. However, the
408+ /// stored hash can be copied to another system and used to log in as the user on the metaserver.
409+ // Further note: SHA-1 is considered broken and shouldn't be used anymore. But since the
410+ // passwords on the server are protected by SHA-1 we have to use it here, too
411+ password_ = crypto::sha1(lb.get_password());
412 register_ = lb.registered();
413
414 s.set_bool("registered", lb.registered());
415@@ -139,7 +148,7 @@
416
417 // Reset InternetGaming and passwort and show internet login again
418 InternetGaming::ref().reset();
419- s.set_string("password", "");
420+ s.set_string("password_sha1", "");
421 show_internet_login();
422 }
423 }
424
425=== modified file 'src/wlapplication.cc'
426--- src/wlapplication.cc 2017-12-14 09:02:31 +0000
427+++ src/wlapplication.cc 2018-03-11 10:02:09 +0000
428@@ -71,6 +71,7 @@
429 #include "logic/single_player_game_controller.h"
430 #include "logic/single_player_game_settings_provider.h"
431 #include "map_io/map_loader.h"
432+#include "network/crypto.h"
433 #include "network/gameclient.h"
434 #include "network/gamehost.h"
435 #include "network/internet_gaming.h"
436@@ -747,7 +748,10 @@
437 s.get_string("uuid");
438 s.get_string("registered");
439 s.get_string("nickname");
440+ // TODO(Notabilis): Remove next line after build 20.
441+ // Currently left in to avoid removing stored passwords for users of both build 19 and trunk
442 s.get_string("password");
443+ s.get_string("password_sha1");
444 s.get_string("emailadd");
445 s.get_string("auto_log");
446 s.get_string("lasthost");
447@@ -765,6 +769,12 @@
448 }
449 s.set_int("last_start", time(nullptr));
450
451+ // Replace the stored plaintext password with its SHA-1 hashed version
452+ // Used to upgrade the stored password when upgrading widelands
453+ if (strlen(s.get_string("password", "")) > 0 && strlen(s.get_string("password_sha1", "")) == 0) {
454+ s.set_string("password_sha1", crypto::sha1(s.get_string("password")));
455+ }
456+
457 // Save configuration now. Otherwise, the UUID is not saved
458 // when the game crashes, loosing part of its advantage
459 try {
460@@ -1175,8 +1185,9 @@
461 Section& s = g_options.pull_section("global");
462 s.set_string("nickname", playername);
463 // Only change the password if we use a registered account
464- if (registered)
465- s.set_string("password", password);
466+ if (registered) {
467+ s.set_string("password_sha1", password);
468+ }
469
470 // reinitalise in every run, else graphics look strange
471 FullscreenMenuInternetLobby ns(playername.c_str(), password.c_str(), registered);
472
473=== modified file 'src/wui/login_box.cc'
474--- src/wui/login_box.cc 2017-02-26 12:16:09 +0000
475+++ src/wui/login_box.cc 2018-03-11 10:02:09 +0000
476@@ -63,7 +63,6 @@
477
478 Section& s = g_options.pull_section("global");
479 eb_nickname->set_text(s.get_string("nickname", _("nobody")));
480- eb_password->set_text(s.get_string("password", ""));
481 cb_register->set_state(s.get_bool("registered", false));
482 eb_nickname->focus();
483 }

Subscribers

People subscribed via source and target branches

to status/vote changes: