« The Easy Bit
Jobs Not Done »

Escaping from Passman

For the last few years I have been keeping my passwords within a password manager called passman. Development of passman has been limited recently and for a while it was blocking me upgrading my nextcloud instance.

As a result I am now begining to worry that passman may not be a suitable password manager. If it takes them six months to release an update, how good are their security checks? I decided to export my passwords and try a different password manager however the password export function was broken. The issue is being tracked on github.

Towards the bottom of the issue, someone showed a way of hacking together some javascript to export all the passwords in the vault into a json file and another bit of code to convert them into a CSV.

I ran into issues with exporting the data from the console where some characters were double escaped. After an evening of playing with code, I combined the two parts into one block of code and included a download function. I also tweaked the CSV code to merge the list of tags into one string.

function download(filename, text) {
  var element = document.createElement('a');
  element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
  element.setAttribute('download', filename);

  element.style.display = 'none';
  document.body.appendChild(element);

  element.click();

  document.body.removeChild(element);
}

mypasswords = []
PassmanExporter.getCredentialsWithFiles = function(credentials, FileService, EncryptService) {
            var t = {
                cred: credentials,
                FS: FileService,
                ES: EncryptService
            };
            return new C_Promise(function() {
                var _this = this.parent
                  , credentials = _this.cred;
                this.parent.total = 0,
                this.parent.finished = 0,
                this.parent.fileGUID_cred = [],
                this.parent.files = [],
                this.parent.step = function(file) {
                    this.parent.finished++,
                    this.call_progress({
                        total: this.parent.total,
                        finished: this.parent.finished
                    });
                    var dta = this.parent.fileGUID_cred[file.guid];
                    file.filename = this.parent.ES.decryptString(file.filename, this.parent.cred[dta.cred_pos].vault_key),
                    file.file_data = this.parent.ES.decryptString(file.file_data, this.parent.cred[dta.cred_pos].vault_key),
                    "files" === dta.on ? this.parent.cred[dta.cred_pos][dta.on][dta.at] = file : this.parent.cred[dta.cred_pos][dta.on][dta.at].value = file,
                    this.parent.total === this.parent.finished && this.call_then(this.parent.cred)
                }
                .bind(this);
                for (var i = 0; i < credentials.length; i++) {
                    var item = credentials[i];
                    for (c = 0; c < item.custom_fields.length; c++) {
                        var cf = item.custom_fields[c];
                        "file" === cf.field_type && (this.parent.total++,
                        this.parent.fileGUID_cred[cf.value.guid] = {
                            cred_pos: i,
                            on: "custom_fields",
                            at: c
                        },
                        this.parent.FS.getFile(cf.value).then(function(data) {
                            this.parent.step(data)
                        }
                        .bind(this)))
                    }
                    mypasswords.push(item)
                }


                b = ''

                mykeys = Object.keys(mypasswords[0])

                mykeys.forEach(function(data) { b = b + data + ',' })

                mypasswords.forEach(function(i) {
                b = b + "\n";
                mykeys.forEach(function(data) {
                    if (i[data] == null){
                      i[data] = "";
                    }
                    if (data == 'otp') {
                    b = b + i.otp.secret + ',';
                    } else if (data == 'tags'){
                      for (j = 0; j < i.tags.length; j++){
                        b = b + i.tags[j]['text'] + " ";    
                      }
                      b = b + ',';
                    } else if (data == 'username' && i[data] == ""){ // some password managers don't want to import emails.
                      b = b + i["email"] + ',';    // this section uses the email adress if no username is supplied.
                    }else {
                    b = b +'"'+ i[data] + '",';
                    }
                })
                })

                b = b + "\n";
                // This is to export as CSV
                download('passman.csv', b)

                // This is to export as json
                //download('passman.json', JSON.stringify(mypasswords) )
            }
            ,t)
        }

To use:

  • Open passman and unlock your vault
  • Navigate to the export vault page
  • Open up the web console (firefox Ctrl+Shift+K)
  • Copy and paste the block of code above
  • Run export as normal (it doesn't matter if you select CSV or JSON, you will get a CSV unless you uncomment the line that includes passman.json towards the bottom).

The CSV can then be imported into whatever password manager you want to try out next.

Updates

2019-02-20: Updated the CSV code to use email address if username is blank and to encapsulate most of the fields with double quotes to escape commas.

2019-04-05: Further updated the CSV code to convert null values into blank strings ("").

Go Top
Previous:
« The Easy Bit
Next:
Jobs Not Done »

Comments

I would love to know what you think. To comment on this article, send me an email

No comments yet.