New implementation of password export

In the previous version the username was only available as part of the
password store identifier. Now it is also part of the content of the
store. The current version outputs the password as first line and the
username as second line. So it's now possible to use the "-c" option of
pass to selectively copy the first or second line to clipboard.

In addition the username is now only used as part of the password
identifier if more than one set of credentials exist for the same
address/url.

Keep in mind that exporting passwords will overwrite any existing
credentials that match the generated identifiers without prompting.
This commit is contained in:
Renato Alves
2016-04-17 19:32:01 +02:00
parent 4de4547135
commit 00a6e6d96d
+41 -19
View File
@@ -265,6 +265,8 @@ class NSSInteraction(object):
credentials = obtain_credentials(profile)
to_export = {}
for host, user, passw, enctype in credentials:
got_password = True
@@ -305,28 +307,16 @@ class NSSInteraction(object):
LOG.debug("Decoding username '%s' and password '%s' for website '%s'", type(user), type(passw), type(host))
if export:
# Keep track of web-address, username and passwords
# If more than one username exists for the same web-address
# the username will be used as name of the file
address = urlparse(host)
passname = u"web/{0}/{1}".format(address.netloc, user)
data = u"{0}".format(passw)
LOG.debug("Inserting pass '%s' '%s'", passname, data)
if address.netloc not in to_export:
to_export[address.netloc] = {user: passw}
# NOTE --force is used. Existing passwords will be overwritten
# NOTE --echo is used so that only one line is read from user input
cmd = ["pass", "insert", "--force", "--echo", passname]
# password twice because pass asks for confirmation
LOG.debug("Running command '%s' with stdin '%s'", cmd, data)
p = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE)
out, err = p.communicate(data.encode("utf8"))
if p.returncode != 0:
LOG.error("ERROR: passwordstore exited with non-zero: %s", p.returncode)
LOG.error("Stdout/Stderr was '%s' '%s'", out, err)
raise Exit(Exit.PASSSTORE_ERROR)
LOG.debug("Successfully exported '%s'", passname)
else:
to_export[address.netloc][user] = passw
else:
sys.stdout.write(u"Website: {0}\n".format(host))
@@ -336,6 +326,38 @@ class NSSInteraction(object):
credentials.done()
self.NSS.NSS_Shutdown()
if export:
# Save all passwords to passwordstore
for address in to_export:
for user, passw in to_export[address].items():
if len(to_export[address]) > 1:
passname = u"web/{0}/{1}".format(address, user)
else:
passname = u"web/{0}".format(address)
LOG.debug("Exporting credentials for '%s'", passname)
data = u"{0}\n{1}\n".format(passw, user)
LOG.debug("Inserting pass '%s' '%s'", passname, data)
# NOTE --force is used. Existing passwords will be overwritten
cmd = ["pass", "insert", "--force", "--multiline", passname]
# password twice because pass asks for confirmation
LOG.debug("Running command '%s' with stdin '%s'", cmd, data)
p = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE)
out, err = p.communicate(data.encode("utf8"))
if p.returncode != 0:
LOG.error("ERROR: passwordstore exited with non-zero: %s", p.returncode)
LOG.error("Stdout/Stderr was '%s' '%s'", out, err)
raise Exit(Exit.PASSSTORE_ERROR)
LOG.debug("Successfully exported '%s'", passname)
if not got_password:
LOG.warn("No passwords found in selected profile")