# Import passwords from Dashlane's CSV-export into pass # Note: you might need to manually clean up the typically malformatted Dashlane CSV export import sys import csv import argparse import subprocess def main(argv=None): parser = argparse.ArgumentParser() parser.add_argument('filename', type=str) parser.add_argument('--ignore_rows', default=9, type=int) args = parser.parse_args() accounts = {} # Read accounts with open(args.filename, newline='', encoding='utf-8') as f: try: reader = csv.reader(f, quoting=csv.QUOTE_ALL, strict=True) rowcount = 0 for row in reader: if (rowcount > args.ignore_rows): # print(':', row) if len(row) < 4: print('Skipping invalid row.') continue site = row[0] account = { 'user': row[2], 'pass': row[3] } assert account['user'], row assert account['pass'], row print('Importing: {0}@{1}'.format(account['user'], site)) if site in accounts: # Add to list accounts[site].append(account) else: # Create new list accounts[site] = [account] rowcount += 1 except csv.Error as e: sys.exit('CSV read error in file {}, line {}: {}\n\nYou might have to replace " in passwords by "".'.format(args.filename, reader.line_num, e)) # Write to pass for (site, accounts) in accounts.items(): for account in accounts: name = '{0}/{1}'.format(site, account['user']) print('Adding ', name) proc = subprocess.Popen(['pass', 'insert', '-e', name], stdin=subprocess.PIPE, stderr=subprocess.STDOUT) proc.communicate(input=account['pass'].encode('UTF-8')) if proc.wait(): sys.exit('Error saving password!') if __name__ == "__main__": sys.exit(main())