Skip to content

Instantly share code, notes, and snippets.

@dechilders
Last active June 14, 2022 21:50
Show Gist options
  • Save dechilders/325dc681bd3d463c89b217a028c48761 to your computer and use it in GitHub Desktop.
Save dechilders/325dc681bd3d463c89b217a028c48761 to your computer and use it in GitHub Desktop.
enpass2icloud.py: Convert Enpass passwords to iCloud format
#!/usr/bin/env python3
#
# enpass2icloud.py
# Created By: Dustin Childers <dchilders@gmail.com>
# Created On: 10/24/2021
# --
# Convert Enpass Passwords (CSV) to iCloud CSV format for importing.
# After converting, simply import output.csv through Safari or System Preferences->Passwords.
# --
#
# IMPORTANT: This was made for my personal use and was not meant to be perfect. It will likely
# require some manual data manipulation and some fields may not convert over as I was not
# using those in my Enpass database. It should serve as a good starting point to get your data
# converted, though. You may have to modify this script to get the specific results you are looking for.
# Requirements: python3
# Third Party Library: tldextract (pip3 install tldextract)
# CONDITIONS:
# Username OR E-mail must exist or it will abort.
# URL must exist or it will abort.
# Password must exist or it will abort.
# If username AND e-mail are the same, then it uses username.
# If username and e-mail are different, it will ask which to use.
import csv
import os
from urllib.parse import urlparse
from urllib.parse import parse_qs
from tldextract import extract
if os.path.isfile('output.csv'):
print('There is currently an output.csv file in this directory.\nIt must be deleted or moved before continuing.')
exit()
dir_list = os.listdir('.')
print('Files in current directory:\n')
for filename in dir_list:
print(filename, end=' ')
print(' ')
password_csv = input('\nWhich file contains your passwords exported from Enpass in CSV format? ')
with open(password_csv) as csv_file:
with open('output.csv', mode='w') as output_csv:
csv_reader = csv.reader(csv_file, delimiter=',')
csv_writer = csv.writer(output_csv, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
csv_writer.writerow(['Title', 'Url', 'Username', 'Password', 'OTPAuth'])
line_count = 1
pw_count = 0
for row in csv_reader:
line_count = line_count + 1
if row[1] == 'Username':
#
# URL
#
subdomain, domain, suffix = extract(row[8])
scheme, _, _, _, _, _ = urlparse(row[8])
url = scheme + '://' + domain + '.' + suffix
if url == '.':
print('empty url on line {}'.format(line_count))
break
#
# Username
#
if ((row[2] == '') and (row[4] == '')):
print('Empty username for {}, aborting.'.format(url))
break
if (row[2] == row[4]):
username = row[2]
else:
if ((row[2] != '') and (row[4] != '')):
print('Detected [1] username ({}) and [2] e-mail ({}) for {} ({})'.format(row[2], row[4], row[0], url))
x = input("Which one would you like to use for the username? (1 or 2): ")
if x == '1':
username = row[2]
elif x == '2':
username = row[4]
else:
print('Invalid selection. Aborting.')
break
else:
if row[2] == '':
username = row[4]
else:
username = row[2]
if username == '':
print('Unknown error processing username. Aborting.')
break
username = username.strip()
#
# Password
#
password = row[6]
if password == '':
print('empty password on line {}'.format(line_count))
break
#
# OTPAuth
#
otpauth_raw = row[14].lower()
otpsecret = ''
otpauth = ''
if (otpauth_raw[0:10] == 'otpauth://'):
otpauth_parsed = urlparse(otpauth_raw)
otpsecret = parse_qs(otpauth_parsed.query)['secret'][0]
otpsecret = otpsecret.upper()
else:
if otpauth_raw != '':
otpauth_raw = otpauth_raw.replace(' ', '')
otpsecret = otpauth_raw.upper()
if (otpsecret != ''):
otpauth = 'otpauth://totp/' + domain + '.' + suffix + ':' + username + '?secret=' + otpsecret + '&issuer=' + domain + '.' + suffix + '&algorithm=SHA1&digits=6&period=30'
#
# Title
#
title = row[0] + ' (' + username + ')'
csv_writer.writerow([title,url,username,password,otpauth])
pw_count = pw_count + 1
print('\nProcessed {} passwords to output.csv.\nImport to iCloud using Safari or System Preferences->Passwords.\n'.format(pw_count))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment