Juerd / ESP-WiFiSettings

WiFi Manager for the ESP32 Arduino environment
Other
166 stars 34 forks source link

Having custom password fields in the AP config replace password with ***********s #33

Open Valdez-x opened 6 months ago

Valdez-x commented 6 months ago

Is there a way to make it so when you have a custom password input string field in the AP configuration page, like an MQTT password it ****'s out the password when a user logs into the AP Configuration page like it does the WiFi password. Or is there any easy way to add this functionality to the WiFiSettings.cpp file to have another function like WiFiSettings.passwordstring() in addition to the .string() and .integer() functions?

Juerd commented 6 months ago

Valdez skribis 2024-01-06 16:42 (-0800):

Is there a way to make it so when you have a custom password input string field in the AP configuration page, like an MQTT password it ****'s out the password when a user logs into the AP Configuration page like it does the WiFi password.

Currently that feature does not exist except for the WiFi password, which is handled separately from the custom fields.

Or is there any easy way to add this functionality to the WiFiSettings.cpp file to have another function like WiFiSettings.passwordstring() in addition to the .string() and .integer() functions?

Displaying it as a password field would be easy: just copy WiFiSettingsString to a new class, e.g. WiFiSettingsPasswordString, and add type=password to the <input> element.

However, this would still leak the password in the value. For the WiFi password, the value is set to ##**##**##** in the HTML. Upon saving the settings, the new value is only stored if it is unequal to that hardcoded value. A similar thing would be needed for the new class.

The nice way to do that would be to override store() with a wrapper, but it would also be feasible to just add it to the loop over params, line 410.

I don't have time to write and test this right now, but I would be open to a well written and tested pull request that adds this feature.

Valdez-x commented 6 months ago

Thanks for the quick response Juerd. I think I got it working. This is what I did.

In WiFiSettings.cpp I copied the "struct WiFiSettingsString" to a new "struct WiFiSettingsPasswordString" and manually entered, value = '**' into h, and I also removed the h.replace("{value}", html_entities(value)); so it would not attempt to update the html value. So the WiFiSettingsPasswordString struct code added looks like this:

struct WiFiSettingsPasswordString : WiFiSettingsParameter {
virtual void set(const String& v) { value = v; }
String html() { 
String h = F("<p><label>{label}:<br><input name='{name}' value='**********' placeholder='{init}' minlength={min}
maxlength={max}></label>");
h.replace("{name}", html_entities(name));
h.replace("{init}", html_entities(init));
h.replace("{label}", html_entities(label));
h.replace("{min}", String(min));
h.replace("{max}", String(max));
return h;
}
};

Then I copied "String WiFiSettingsClass::string..." to a new "WiFiSettingsClass::passwordstring..." and changed the struct references to the struct WiFiSettingsPasswordString, so the new class added looks like this:

String WiFiSettingsClass::passwordstring(const String& name, const String& init, const String& label) {
begin();
struct WiFiSettingsPasswordString* x = new WiFiSettingsPasswordString();
x->name = name;
x->label = label.length() ? label : name;
x->init = init;
x->fill();

params.push_back(x);
return x->value.length() ? x->value : x->init;
}

Editted as per below - I also changed the loop at line 410 to check if the value is "**" so that it only stores it if it has been changed. The loop now looks like this:

for (auto& p : params) {
    String pwstring = http.arg(p->name);
    if (pwstring != "**********"){
        p->set(http.arg(p->name));
        if (! p->store()) ok = false;
    }
}

Lastly in WiFiSettings.h I added: String passwordstring(const String& name, const String& init = "", const String& label = "");

In my code where I declare the custom variable fields for the AP Config I declare String mqttpassword = WiFiSettings.passwordstring("MQTT Password"); and use the mqttpassword variable in other code to login to the mqtt server. It works and when I check the AP Configuration page it shows ** in the mqttt password box now and the page source doesnt show the actual password value anywhere so I think it is working good and is secure.

Valdez-x commented 6 months ago

Nevermind... I see a problem with my code. It hides the value of the password but any time you re-save the Config without re-entering the custom password it updates your your custom password to "**" as its hardcoded into the value. Need to put in a check to see if its ** and ignore it if so. I also see you tried explaining that to me 🥴! Working on it now.

Valdez-x commented 6 months ago

Now it works!

Changed the loop at line 410 in WiFiSettings.cpp to check if the value is "**" before storing:

        for (auto& p : params) {
            String pwstring = http.arg(p->name);
            if (pwstring != "**********"){
            p->set(http.arg(p->name));
            if (! p->store()) ok = false;
            }
          }

Updated the post above with this code. I'll probably change the password mask to ##**##**##** in my final version for consistency with the wifi password.