Some enhancements in server interface :

* Display PHP parsed URL in new URL case, not raw URL
	* Add a filter for unciphered passwords (supports regular expressions)
	* Add a button to copy unciphered password into clipboard
	* Don't clear URL and login when adding a new password
This commit is contained in:
Gregory Soutade 2022-02-09 21:10:13 +01:00
parent 2def010612
commit 42142cbca9
3 changed files with 107 additions and 45 deletions

View File

@ -180,7 +180,7 @@ else
} }
} }
echo "</select>\n"; echo "</select>\n";
echo ' <b>Master key </b> <input id="master_key" type="password" onkeypress="if (event.keyCode == 13) update_master_key(true);"/>'; echo ' <b>Master key </b> <input id="master_key" type="password" onchange="update_master_key(true);"/>';
echo "<input type=\"button\" value=\"See\" onclick=\"update_master_key(true);\" />" . "\n"; echo "<input type=\"button\" value=\"See\" onclick=\"update_master_key(true);\" />" . "\n";
if (!isset($_SERVER['HTTPS'])) if (!isset($_SERVER['HTTPS']))
@ -197,10 +197,10 @@ if ($user != "")
{ {
echo "<div class=\"title\">Add a new password</div>\n"; echo "<div class=\"title\">Add a new password</div>\n";
echo 'URL <input type="text" id="new_url" name="url" value="' . (filter_input(INPUT_GET, "url", FILTER_SANITIZE_SPECIAL_CHARS) ?: "") . '"/>'; echo 'URL <input type="text" id="new_url" name="url" value="' . (parse_url(filter_input(INPUT_GET, "url", FILTER_SANITIZE_SPECIAL_CHARS))['host'] ?: "") . '"/>';
echo 'login <input type="text" id="new_login" name="login" value="' . (filter_input(INPUT_GET, "user", FILTER_SANITIZE_SPECIAL_CHARS) ?: "") . '"/>'; echo 'login <input type="text" id="new_login" name="login" value="' . (filter_input(INPUT_GET, "user", FILTER_SANITIZE_SPECIAL_CHARS) ?: "") . '"/>';
echo 'password <input id="new_password" type="text" name="password"/>'; echo 'password <input id="new_password" type="text" name="password"/>';
echo 'master key <input type="text" name="mkey" id="new_mkey" onkeypress="if (event.keyCode == 13) add_password();" onkeyup="chkPass(this.value);"/>'; echo 'master key <input type="text" name="mkey" id="new_mkey" onchange="add_password();" onkeyup="chkPass(this.value);"/>';
echo '<input type="button" value="Generate password" onClick="generate_password();"/>'; echo '<input type="button" value="Generate password" onClick="generate_password();"/>';
echo '<input type="button" value="Generate simple password" onClick="generate_simple_password();"/>'; echo '<input type="button" value="Generate simple password" onClick="generate_simple_password();"/>';
echo "<input type=\"button\" name=\"add\" value=\"Add\" onclick=\"add_password();\"/>"; echo "<input type=\"button\" name=\"add\" value=\"Add\" onclick=\"add_password();\"/>";
@ -237,8 +237,13 @@ if ($user != "")
} }
?> ?>
</div> </div>
<div id="passwords"> <div id="filter">
</div> Filter <input id='password_filter' value=<?php echo "'" . (parse_url(filter_input(INPUT_GET, "url", FILTER_SANITIZE_SPECIAL_CHARS))['host'] ?: "") . "'" ?> onchange='password_filter_changed();'/>
</div> <input type="button" onclick="password_filter_changed();" value="Apply"/>
<input type="button" onclick="document.getElementById('password_filter').value = '';password_filter_changed();" value="Clear"/>
</div>
<div id="passwords"></div>
</div>
</body> </body>
</html> </html>

View File

@ -124,6 +124,10 @@ input {
visibility:hidden; visibility:hidden;
} }
#filter {
font-weight:bold;
}
.error { .error {
text-align:center; text-align:center;
color:red; color:red;

View File

@ -161,6 +161,8 @@ var current_mkey = "";
var clearTimer = null; var clearTimer = null;
var global_iv = null; var global_iv = null;
var server_url = window.location.href.split('?')[0]; var server_url = window.location.href.split('?')[0];
var clear_passwords = new Array();
var block_filter = true;
function PasswordEntry (ciphered_login, ciphered_password, salt, shadow_login) { function PasswordEntry (ciphered_login, ciphered_password, salt, shadow_login) {
this.ciphered_login = ciphered_login; this.ciphered_login = ciphered_login;
@ -426,6 +428,51 @@ async function get_ciphered_credentials(masterkey)
req.send("get_secure_passwords=1&user=" + current_user + "&access_tokens=" + access_tokens); req.send("get_secure_passwords=1&user=" + current_user + "&access_tokens=" + access_tokens);
} }
function password_filter_changed()
{
if (block_filter) return;
filter = document.getElementById('password_filter').value ;
if (filter !== '')
filter = '.*' + filter + '.*';
password_div = document.getElementById("clear_passwords");
password_div.removeAllChilds();
for (idx in clear_passwords)
{
div = clear_passwords[idx];
if (typeof(div) === 'function')
continue;
if (filter === '')
password_div.appendChild(div);
else
{
childs = clear_passwords[idx].children;
for (elem_idx in childs)
{
elem = childs[elem_idx];
if (elem.name == 'url')
{
// Remove * for wildcards domains
target_url = elem.value.replace('*', '') ;
try {
if (target_url.match(filter))
password_div.appendChild(div);
}
/* Forgive re errors */
catch(error)
{
// console.log(error);
}
break;
}
}
}
}
}
async function change_master_key(warning_unciphered) async function change_master_key(warning_unciphered)
{ {
var nb_unciphered = 0; var nb_unciphered = 0;
@ -439,9 +486,6 @@ async function change_master_key(warning_unciphered)
nb_unciphered++; nb_unciphered++;
} }
if (!nb_unciphered && warning_unciphered)
alert("No password unciphered with this master key !");
password_div = document.getElementById("passwords"); password_div = document.getElementById("passwords");
password_div.removeAllChilds(); password_div.removeAllChilds();
@ -449,6 +493,11 @@ async function change_master_key(warning_unciphered)
div.setAttribute("id", "nb_unciphered_passwords"); div.setAttribute("id", "nb_unciphered_passwords");
password_div.appendChild(div); password_div.appendChild(div);
div = document.createElement("div");
div.setAttribute("id", "clear_passwords");
password_div.appendChild(div);
clear_passwords = new Array();
for(i=0; i<passwords.length; i++) for(i=0; i<passwords.length; i++)
{ {
if (passwords[i].isUnciphered(current_mkey)) if (passwords[i].isUnciphered(current_mkey))
@ -497,10 +546,19 @@ async function change_master_key(warning_unciphered)
update_button.setAttribute("onclick", "update_entry(\"unciph_entry_" + i + "\");"); update_button.setAttribute("onclick", "update_entry(\"unciph_entry_" + i + "\");");
div.appendChild(update_button); div.appendChild(update_button);
password_div.appendChild(div); clipboard_button = document.createElement("input");
clipboard_button.setAttribute("type", "button");
clipboard_button.setAttribute("value", "Copy password");
clipboard_button.setAttribute("onclick", "copy_clipboard(\"unciph_entry_" + i + "\");");
div.appendChild(clipboard_button);
clear_passwords.push(div);
} }
} }
if (warning_unciphered && !nb_unciphered)
alert("No password unciphered with this master key !");
div = document.createElement("div"); div = document.createElement("div");
div.setAttribute("id", "nb_ciphered_passwords"); div.setAttribute("id", "nb_ciphered_passwords");
password_div.appendChild(div); password_div.appendChild(div);
@ -557,41 +615,12 @@ async function change_master_key(warning_unciphered)
} }
} }
cur_url = document.getElementById("new_url").value;
/* If we have a current URL in add form and we have a password entry that match this URL, go to the last */
/* Can't do this before, because everything is not displayed from browser */
if (cur_url !== "")
{
cur_url = url_domain(cur_url);
for(i=0; i<passwords.length; i++)
{
if (!passwords[i].isUnciphered(current_mkey))
continue;
url_elem = document.getElementById("unciph_url_" + i);
target_url = url_elem.value;
// Replace wildcard domain by .*<domain>
if (target_url[0] == "*")
target_url = "." + target_url;
try {
if (cur_url.match(target_url))
{
window.scrollTo(0, url_elem.offsetTop);
break;
}
}
/* Forgive re errors */
catch(error)
{
//console.log(error);
}
}
}
input = document.getElementById("master_key"); input = document.getElementById("master_key");
input.value = ""; input.value = "";
update_stats(); update_stats();
block_filter = false;
password_filter_changed();
} }
function update_master_key(warning_unciphered) function update_master_key(warning_unciphered)
@ -783,16 +812,14 @@ function add_password()
for(i=0; i<inputs.length; i++) for(i=0; i<inputs.length; i++)
{ {
if (inputs[i].getAttribute("type") == "text" || name = inputs[i].getAttribute("name");
inputs[i].getAttribute("type") == "password") if (name === "password" || name === "mkey")
inputs[i].value = ""; inputs[i].value = "";
} }
startClearTimer(); startClearTimer();
}); });
window.scrollTo(0,document.body.scrollHeight);
return true; return true;
} }
@ -988,6 +1015,32 @@ async function update_masterkey()
} }
} }
function copy_clipboard(entry_number)
{
var password = "";
entry = document.getElementById(entry_number);
if (entry == null) {
alert(entry_number + " not found");
return;
}
inputs = entry.getElementsByTagName("input");
for(i=0; i<inputs.length; i++)
{
if (inputs[i].getAttribute("name") == "password")
{
inputs[i].select();
document.execCommand('copy');
inputs[i].setSelectionRange(0,0); // Unselect
alert('Password copied into clipboard');
break;
}
}
}
function makeText(text) { function makeText(text) {
var data = new Blob([text], {type: 'application/xml'}); var data = new Blob([text], {type: 'application/xml'});