somewhat clearing the multiplayer login dialog mess:
- added the possibility to provide a password in the mp method selection dialog - merged all dialogs that displayed erros or allowed entering the username or password into one dialog. - password is now saved in preferences (todo: add option to turn this off)
This commit is contained in:
parent
51fa967ce8
commit
61fc432f9b
8 changed files with 282 additions and 146 deletions
|
@ -55,6 +55,59 @@
|
|||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
grow_factor = 1
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
|
||||
horizontal_grow = "true"
|
||||
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
grow_factor = 1
|
||||
|
||||
[column]
|
||||
grow_factor = 0
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[label]
|
||||
definition = "default"
|
||||
|
||||
label = _ "Login:"
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "right"
|
||||
|
||||
[text_box]
|
||||
id = "user_name"
|
||||
definition = "default"
|
||||
history = "mp_user_name_history"
|
||||
|
||||
label = ""
|
||||
[/text_box]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
grow_factor = 1
|
||||
|
||||
|
@ -88,7 +141,7 @@
|
|||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_grow = "true"
|
||||
horizontal_alignment = "right"
|
||||
|
||||
[text_box]
|
||||
id = "password"
|
||||
|
@ -111,8 +164,8 @@
|
|||
grow_factor = 0
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
horizontal_grow = "true"
|
||||
grow_factor = 0
|
||||
horizontal_alignment = "right"
|
||||
|
||||
[grid]
|
||||
|
||||
|
@ -133,20 +186,6 @@
|
|||
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "right"
|
||||
|
||||
[button]
|
||||
definition = "default"
|
||||
id = "change_username"
|
||||
|
||||
label = _ "Change username"
|
||||
[/button]
|
||||
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
border = "all"
|
||||
border_size = 5
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_grow = "true"
|
||||
horizontal_alignment = "right"
|
||||
|
||||
[text_box]
|
||||
id = "user_name"
|
||||
|
@ -88,6 +88,59 @@
|
|||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
grow_factor = 1
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
|
||||
horizontal_grow = "true"
|
||||
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
grow_factor = 1
|
||||
|
||||
[column]
|
||||
grow_factor = 0
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[label]
|
||||
definition = "default"
|
||||
|
||||
label = _ "Password:"
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "right"
|
||||
|
||||
[text_box]
|
||||
id = "password"
|
||||
definition = "default"
|
||||
|
||||
label = ""
|
||||
[/text_box]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
|
||||
[row]
|
||||
grow_factor = 1
|
||||
vertical_grow = "true"
|
||||
|
|
|
@ -337,11 +337,21 @@ std::string login()
|
|||
return res;
|
||||
}
|
||||
|
||||
std::string password()
|
||||
{
|
||||
return preferences::get("password");
|
||||
}
|
||||
|
||||
void set_login(const std::string& username)
|
||||
{
|
||||
preferences::set("login", username);
|
||||
}
|
||||
|
||||
void set_password(const std::string& password)
|
||||
{
|
||||
preferences::set("password", password);
|
||||
}
|
||||
|
||||
bool turn_dialog()
|
||||
{
|
||||
return utils::string_bool(preferences::get("turn_dialog"), false);
|
||||
|
|
|
@ -73,6 +73,9 @@ namespace preferences {
|
|||
std::string login();
|
||||
void set_login(const std::string& username);
|
||||
|
||||
std::string password();
|
||||
void set_password(const std::string& password);
|
||||
|
||||
bool turn_dialog();
|
||||
void set_turn_dialog(bool ison);
|
||||
|
||||
|
|
|
@ -193,6 +193,7 @@ void tmp_connect::show_server_list(twindow& window)
|
|||
* This shows the dialog to log in to the MP server
|
||||
*
|
||||
* @start_table = container
|
||||
* user_name (text_box) the login user name
|
||||
* password (text_box) the password
|
||||
* [password_reminder] (button) Request a password reminder
|
||||
* [change_username] (button) Use a different username
|
||||
|
@ -201,7 +202,7 @@ void tmp_connect::show_server_list(twindow& window)
|
|||
* @end_table
|
||||
*/
|
||||
|
||||
tmp_login::tmp_login(const t_string& label) : password_(), label_(label) { }
|
||||
tmp_login::tmp_login(const t_string& label) : label_(label) { }
|
||||
|
||||
twindow* tmp_login::build_window(CVideo& video)
|
||||
{
|
||||
|
@ -210,10 +211,16 @@ twindow* tmp_login::build_window(CVideo& video)
|
|||
|
||||
void tmp_login::pre_show(CVideo& /*video*/, twindow& window)
|
||||
{
|
||||
ttext_box* username =
|
||||
dynamic_cast<ttext_box*>(window.find_widget("user_name", false));
|
||||
VALIDATE(username, missing_widget("user_name"));
|
||||
username->set_value(preferences::login());
|
||||
window.keyboard_capture(username);
|
||||
|
||||
ttext_box* password =
|
||||
dynamic_cast<ttext_box*>(window.find_widget("password", false));
|
||||
VALIDATE(password, missing_widget("password"));
|
||||
window.keyboard_capture(password);
|
||||
password->set_value(preferences::password());
|
||||
|
||||
tbutton *password_reminder =
|
||||
dynamic_cast<tbutton*>(window.find_widget("password_reminder", false));
|
||||
|
@ -231,10 +238,17 @@ void tmp_login::pre_show(CVideo& /*video*/, twindow& window)
|
|||
|
||||
void tmp_login::post_show(twindow& window)
|
||||
{
|
||||
ttext_box* username =
|
||||
dynamic_cast<ttext_box*>(window.find_widget("user_name", false));
|
||||
assert(username);
|
||||
|
||||
preferences::set_login(username->get_value());
|
||||
|
||||
ttext_box* password =
|
||||
dynamic_cast<ttext_box*>(window.find_widget("password", false));
|
||||
VALIDATE(password, missing_widget("password"));
|
||||
password_ = password->get_value();
|
||||
assert(password);
|
||||
|
||||
preferences::set_password(password->get_value());
|
||||
}
|
||||
|
||||
} // namespace gui2
|
||||
|
|
|
@ -50,8 +50,6 @@ class tmp_login : public tdialog
|
|||
public:
|
||||
tmp_login(const t_string& label);
|
||||
|
||||
const std::string& password() const { return password_; }
|
||||
|
||||
private:
|
||||
/** Inherited from tdialog. */
|
||||
twindow* build_window(CVideo& video);
|
||||
|
@ -62,7 +60,6 @@ private:
|
|||
/** Inherited from tdialog. */
|
||||
void post_show(twindow& window);
|
||||
|
||||
std::string password_;
|
||||
t_string label_;
|
||||
};
|
||||
|
||||
|
|
|
@ -53,6 +53,11 @@ void tmp_method_selection::pre_show(CVideo& /*video*/, twindow& window)
|
|||
user_widget->set_maximum_length(mp::max_login_size);
|
||||
window.keyboard_capture(user_widget);
|
||||
|
||||
ttext_box* password_widget = dynamic_cast<ttext_box*>(window.find_widget("password", false));
|
||||
VALIDATE(password_widget, missing_widget("password"));
|
||||
|
||||
password_widget->set_value(preferences::password());
|
||||
|
||||
tlistbox* list = dynamic_cast<tlistbox*>(window.find_widget("method_list", false));
|
||||
VALIDATE(list, missing_widget("method_list"));
|
||||
|
||||
|
@ -67,13 +72,19 @@ void tmp_method_selection::post_show(twindow& window)
|
|||
ttext_box* user_widget = dynamic_cast<ttext_box*>(window.find_widget("user_name", false));
|
||||
assert(user_widget);
|
||||
|
||||
ttext_box* password_widget = dynamic_cast<ttext_box*>(window.find_widget("password", false));
|
||||
assert(password_widget);
|
||||
|
||||
tlistbox* list = dynamic_cast<tlistbox*>(window.find_widget("method_list", false));
|
||||
assert(list);
|
||||
|
||||
choice_ = list->get_selected_row();
|
||||
|
||||
user_widget->save_to_history();
|
||||
user_name_= user_widget->get_value();
|
||||
preferences::set_login(user_name_);
|
||||
|
||||
preferences::set_password(password_widget->get_value());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -176,134 +176,17 @@ static server_type open_connection(game_display& disp, const std::string& origin
|
|||
|
||||
//if we got a direction to login
|
||||
if(data.child("mustlogin")) {
|
||||
bool first_time = true;
|
||||
config* error = NULL;
|
||||
|
||||
do {
|
||||
std::string login = preferences::login();
|
||||
std::string password = "";
|
||||
for(;;) {
|
||||
std::string password_reminder = "";
|
||||
|
||||
if(!first_time) {
|
||||
|
||||
//Somewhat hacky implementation, including a goto of death
|
||||
|
||||
/** @todo A fancy textbox that displays characters as dots or asterisks would nice. */
|
||||
if(!((*error)["password_request"].empty())) {
|
||||
|
||||
gui2::tmp_login dlg((*error)["message"]);
|
||||
dlg.show(disp.video());
|
||||
|
||||
password = dlg.password();
|
||||
|
||||
switch(dlg.get_retval()) {
|
||||
//Log in with password
|
||||
case gui2::twindow::OK:
|
||||
break;
|
||||
//Request a password reminder
|
||||
case 1:
|
||||
password_reminder = "yes";
|
||||
break;
|
||||
//Choose a different username
|
||||
case 2:
|
||||
password = "";
|
||||
goto new_username;
|
||||
break;
|
||||
default: return ABORT_SERVER;
|
||||
}
|
||||
|
||||
} else {
|
||||
new_username:
|
||||
|
||||
const int res = gui::show_dialog(disp, NULL, "",
|
||||
(*error)["message"], gui::OK_CANCEL,
|
||||
NULL, NULL, _("Login: "), &login, mp::max_login_size);
|
||||
if(res != 0 || login.empty()) {
|
||||
return ABORT_SERVER;
|
||||
}
|
||||
preferences::set_login(login);
|
||||
}
|
||||
}
|
||||
|
||||
first_time = false;
|
||||
std::string login = preferences::login();
|
||||
|
||||
config response ;
|
||||
config &sp = response.add_child("login") ;
|
||||
sp["username"] = login ;
|
||||
sp["password_reminder"] = password_reminder;
|
||||
|
||||
// If password is not empty start hashing
|
||||
|
||||
std::string result;
|
||||
if(!(password.empty())) {
|
||||
|
||||
// Check if we have everything we need
|
||||
if((*error)["salt"].empty() || (*error)["hash_seed"].empty()) {
|
||||
return ABORT_SERVER;
|
||||
}
|
||||
|
||||
std::string itoa64("./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
|
||||
|
||||
std::string salt = (*error)["salt"];
|
||||
int hash_seed;
|
||||
try {
|
||||
hash_seed = lexical_cast_default<int>((*error)["hash_seed"]);
|
||||
} catch (bad_lexical_cast) {
|
||||
std::cerr << "Bad lexical cast reading hash_seed\n";
|
||||
return ABORT_SERVER;
|
||||
}
|
||||
|
||||
// Start the MD5 hashing
|
||||
salt.append(password);
|
||||
MD5 md5_worker;
|
||||
md5_worker.update((unsigned char *)salt.c_str(),salt.length());
|
||||
md5_worker.finalize();
|
||||
unsigned char * output = (unsigned char *) malloc (sizeof(unsigned char) * 16);
|
||||
output = md5_worker.raw_digest();
|
||||
std::string temp_hash;
|
||||
do {
|
||||
temp_hash = std::string((char *) output, (char *) output + 16);
|
||||
temp_hash.append(password);
|
||||
md5_worker.~MD5();
|
||||
MD5 md5_worker;
|
||||
md5_worker.update((unsigned char *)temp_hash.c_str(),temp_hash.length());
|
||||
md5_worker.finalize();
|
||||
output = md5_worker.raw_digest();
|
||||
} while (--hash_seed);
|
||||
temp_hash = std::string((char *) output, (char *) output + 16);
|
||||
|
||||
// Now encode the resulting mix
|
||||
std::string encoded_hash;
|
||||
unsigned int i = 0, value;
|
||||
do {
|
||||
value = output[i++];
|
||||
encoded_hash.append(itoa64.substr(value & 0x3f,1));
|
||||
if(i < 16)
|
||||
value |= (int)output[i] << 8;
|
||||
encoded_hash.append(itoa64.substr((value >> 6) & 0x3f,1));
|
||||
if(i++ >= 16)
|
||||
break;
|
||||
if(i < 16)
|
||||
value |= (int)output[i] << 16;
|
||||
encoded_hash.append(itoa64.substr((value >> 12) & 0x3f,1));
|
||||
if(i++ >= 16)
|
||||
break;
|
||||
encoded_hash.append(itoa64.substr((value >> 18) & 0x3f,1));
|
||||
} while (i < 16);
|
||||
free (output);
|
||||
|
||||
// Now mix the resulting hash with the random seed
|
||||
result = encoded_hash + (*error)["random_salt"];
|
||||
|
||||
MD5 md5_worker2;
|
||||
md5_worker2.update((unsigned char *)result.c_str(), result.size());
|
||||
md5_worker2.finalize();
|
||||
|
||||
result = std::string(md5_worker2.hex_digest());
|
||||
}
|
||||
|
||||
sp["password"] = result;
|
||||
|
||||
// Login and enable selective pings -- saves server bandwidth
|
||||
// If ping_timeout has a non-zero value, do not enable
|
||||
// selective pings as this will cause clients to falsely
|
||||
|
@ -318,13 +201,139 @@ static server_type open_connection(game_display& disp, const std::string& origin
|
|||
}
|
||||
network::send_data(response, 0, true);
|
||||
|
||||
// Get response for our login request...
|
||||
network::connection data_res = network::receive_data(data, 0, 3000);
|
||||
if(!data_res) {
|
||||
throw network::error(_("Connection timed out"));
|
||||
}
|
||||
|
||||
error = data.child("error");
|
||||
} while(error != NULL);
|
||||
config* error = data.child("error");
|
||||
|
||||
// ... and get us out of here if the server did not complain
|
||||
if(!error) break;
|
||||
|
||||
do {
|
||||
std::string password = preferences::password();
|
||||
|
||||
// If the server asks for a password, provide one if we can,
|
||||
// otherwise go directly to the username/password dialog
|
||||
if(!((*error)["password_request"].empty()) && !(password.empty())) {
|
||||
|
||||
// start the hashing
|
||||
std::string result;
|
||||
|
||||
// Check if we have everything we need
|
||||
if((*error)["salt"].empty() || (*error)["hash_seed"].empty()) {
|
||||
return ABORT_SERVER;
|
||||
}
|
||||
|
||||
std::string itoa64("./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
|
||||
|
||||
std::string salt = (*error)["salt"];
|
||||
int hash_seed;
|
||||
try {
|
||||
hash_seed = lexical_cast_default<int>((*error)["hash_seed"]);
|
||||
} catch (bad_lexical_cast) {
|
||||
std::cerr << "Bad lexical cast reading hash_seed\n";
|
||||
return ABORT_SERVER;
|
||||
}
|
||||
|
||||
// Start the MD5 hashing
|
||||
salt.append(password);
|
||||
MD5 md5_worker;
|
||||
md5_worker.update((unsigned char *)salt.c_str(),salt.length());
|
||||
md5_worker.finalize();
|
||||
unsigned char * output = (unsigned char *) malloc (sizeof(unsigned char) * 16);
|
||||
output = md5_worker.raw_digest();
|
||||
std::string temp_hash;
|
||||
do {
|
||||
temp_hash = std::string((char *) output, (char *) output + 16);
|
||||
temp_hash.append(password);
|
||||
md5_worker.~MD5();
|
||||
MD5 md5_worker;
|
||||
md5_worker.update((unsigned char *)temp_hash.c_str(),temp_hash.length());
|
||||
md5_worker.finalize();
|
||||
output = md5_worker.raw_digest();
|
||||
} while (--hash_seed);
|
||||
temp_hash = std::string((char *) output, (char *) output + 16);
|
||||
|
||||
// Now encode the resulting mix
|
||||
std::string encoded_hash;
|
||||
unsigned int i = 0, value;
|
||||
do {
|
||||
value = output[i++];
|
||||
encoded_hash.append(itoa64.substr(value & 0x3f,1));
|
||||
if(i < 16)
|
||||
value |= (int)output[i] << 8;
|
||||
encoded_hash.append(itoa64.substr((value >> 6) & 0x3f,1));
|
||||
if(i++ >= 16)
|
||||
break;
|
||||
if(i < 16)
|
||||
value |= (int)output[i] << 16;
|
||||
encoded_hash.append(itoa64.substr((value >> 12) & 0x3f,1));
|
||||
if(i++ >= 16)
|
||||
break;
|
||||
encoded_hash.append(itoa64.substr((value >> 18) & 0x3f,1));
|
||||
} while (i < 16);
|
||||
free (output);
|
||||
|
||||
// Now mix the resulting hash with the random seed
|
||||
result = encoded_hash + (*error)["random_salt"];
|
||||
|
||||
MD5 md5_worker2;
|
||||
md5_worker2.update((unsigned char *)result.c_str(), result.size());
|
||||
md5_worker2.finalize();
|
||||
|
||||
result = std::string(md5_worker2.hex_digest());
|
||||
|
||||
sp["password"] = result;
|
||||
|
||||
// Once again send our request...
|
||||
network::send_data(response, 0, true);
|
||||
|
||||
network::connection data_res = network::receive_data(data, 0, 3000);
|
||||
if(!data_res) {
|
||||
throw network::error(_("Connection timed out"));
|
||||
}
|
||||
|
||||
error = data.child("error");
|
||||
|
||||
// ... and get us out of here if the server is happy now
|
||||
if(!error) break;
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Providing a password either was not attempted because we did not
|
||||
// have any or failed:
|
||||
// Now show a dialog that displays the error and allows to
|
||||
// enter a new user name and/or password
|
||||
|
||||
/** @todo A fancy textbox that displays characters as dots or asterisks would nice. */
|
||||
|
||||
gui2::tmp_login dlg((*error)["message"]);
|
||||
dlg.show(disp.video());
|
||||
|
||||
switch(dlg.get_retval()) {
|
||||
//Log in with password
|
||||
case gui2::twindow::OK:
|
||||
break;
|
||||
//Request a password reminder
|
||||
case 1:
|
||||
password_reminder = "yes";
|
||||
break;
|
||||
// Cancel
|
||||
default: return ABORT_SERVER;
|
||||
}
|
||||
|
||||
// If we have got a new username we have to start all over again
|
||||
} while(login == preferences::login());
|
||||
|
||||
// Somewhat hacky...
|
||||
// If we broke out of the do-while loop above error
|
||||
// is still going to be NULL
|
||||
if(!error) break;
|
||||
} // end login loop
|
||||
}
|
||||
} while(!(data.child("join_lobby") || data.child("join_game")));
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue