Denilson uses a password manager, like one should. Except there was a router which simply would not let the password manager fill the password field. Sure, Denilson could just copy and paste, but the question of why remained.
And that meant checking the HTML and JavaScript code the router served up. Just pulling up the dev tools brought up all sorts of "fun" discoveries. For example, the application was built in Vue, a front-end framework. But in addition to using Vue, it also used jQuery for some DOM manipulations. But it didn't just use jQuery. It loaded jquery-3.5.1.slim.min.js directly from its static files. It also loaded vendor.js which also contained the same version of jQuery. At least it was the same version.
While browsing, Denilson found a function called reloadOnF5, which raises an interesting question: isn't that just what the browser does anyway?
function reloadOnF5(router) {
document.onkeydown = function (event) {
if (
event.key == 'F5' ||
event.code == 'F5' ||
event.which == 116 ||
event.keyCode == 116
) {
event.returnValue = false;
//router.push('/');
router.go(router.currentRoute)
}
};
}
The best part of this is that at one point they used router.push('/') to navigate, which wouldn't refresh the page, but simply re-render the root page of the app and add an entry to the browser history.
var MD5 = function(d){result = M(/*a bunch of minified stuff*/);
That they include a minified md5 function isn't a WTF, but what's notable is that this is the only piece of their own code that is minified. It's mixed in with a file that has no other minified functions, which implies that someone copy/pasted this function out of a minified library.
Now, a common piece of validation you might want for a router is requiring inputs to be hexadecimal numbers. Now, for most of us, that'd be a short regex one liner. But if you're getting paid by the line, you can bloat that out to 30 lines without breaking a sweat:
function isHexaDigit(digit) {
var hexVals = new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"A", "B", "C", "D", "E", "F", "a", "b", "c", "d", "e", "f");
var len = hexVals.length;
var i = 0;
var ret = false;
for ( i = 0; i < len; i++ )
if ( digit == hexVals[i] ) break;
if ( i < len )
ret = true;
return ret;
}
function isValidHexKey(val, size) {
var ret = false;
if (val.length == size) {
for ( i = 0; i < val.length; i++ ) {
if ( isHexaDigit(val.charAt(i)) == false ) {
break;
}
}
if ( i == val.length ) {
ret = true;
}
}
return ret;
}
None of that explains why Denilson's password manager didn't work, but it's a pretty clear example of the overall level of code quality. Note how in isHexaDigit they are using i as a function-scoped variable, and then use that i to determine if the validation passes- if we found a match before the end of the list, it must be a hex digit.
So why didn't the password manager work? Well, we have a snippet of the generated DOM, that points at what's going on:
<label for="userpassword">Password</label>
<div class="zypasswordBox">
<input maxlength="64" maskctrl="true" id="userpassword" type="text" autocomplete="off" errorinline="true" class="maskPassword">
<input maxlength="64" maskctrl="true" id="userpassword" type="text" autocomplete="off" errorinline="true" class="unmaskPassword" style="display: none;">
<i id="userpassword_maskCheck" class="icon-visibility-on"></i>
</div>
Now, you'll first notice that there are two inputs with the same id. That's not valid HTML, which is likely enough to throw a password manager for a loop. But it's actually even worse than that. Notice how one is classed maskPassword and the other is unmaskPassword, and the unmasked one is set to display: none. The way this actually works is that JavaScript intercepts your key events in the maskPassword box, appends the key to the unmaskPassword box, and then replaces the key with a "*" and puts that in the maskPassword box.
So, instead of using input=type="password", which automatically masks a password, they just made up their own version. But this version is special, since it only detects input events, it doesn't let you do radical things, like use "backspace" or "navigate with arrow keys". In fact, because that would cause some unexpected behavior, the page actually clears the password box entirely if you use backspace or arrow keys.
Denilson writes:
And this is the quality of code that gets shipped into our homes. This is not the exception, this is the norm.
I think we all understand how bad the UI to pretty much every router is. Not to defend it, but to explain it, most of the router control interfaces for commodity routers are often written by the same networking engineers who are writing the network stack on the router. These are folks who are really good in low-level networking in C, suddenly being tossed a pile of HTML and JavaScript and being told, "Make this work."
Which is to say, it's not the programmers' fault, but the organization that thinks "enh, programmer is programmer, make software go brrrr".