Skip to content

Instantly share code, notes, and snippets.

@melissaboiko
Created August 25, 2021 17:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save melissaboiko/7d6d651a360c13995f5b9150381605af to your computer and use it in GitHub Desktop.
Save melissaboiko/7d6d651a360c13995f5b9150381605af to your computer and use it in GitHub Desktop.
Alternative Bitwarden importer for Firefox Lockwise passwords, keeps everything into a separate folder
#!/usr/bin/env python3
'''lockwise2bitwarden.py:
Converts a Firefox Lockwise export CSV into a Bitwarden-format CSV.
Compared to using the built-in Firefox importer, this will:
- Save everything into a Lockwise-{timestamp} folder, and
- Save some extra Firefox stuff in the Notes field.
(Would be nice to use custom fields for those, but then we need
.json, and then we need to create folders, and then we need API
access...)
Usage: lockwise2bitwarden.py < from-firefox.csv > to-bitwarden.csv
Remember to import it using the Bitwarden importer, not the Firefox one!
'''
import sys
import csv
from datetime import datetime
import re
bitwarden_csv_columns=[
'folder',
'favorite',
'type',
'name',
'notes',
'fields',
'reprompt',
'login_uri',
'login_username',
'login_password',
'login_totp',
]
lockwise_csv_columns=[
'url',
'username',
'password',
'httpRealm',
'formActionOrigin',
'guid',
'timeCreated',
'timeLastUsed',
'timePasswordChanged',
]
def epoch2timestamp(epoch):
'''Firefox epoch (with milisecs) to timestamp string.'''
epoch = int(epoch)
epoch = round(epoch / 1000)
time = datetime.fromtimestamp(epoch)
return time.isoformat()
folder = 'Lockwise ' + datetime.now().strftime('%Y-%m-%dT%H:%M:%S')
reader = csv.DictReader(sys.stdin, delimiter=',', quotechar='"')
writer = csv.DictWriter(sys.stdout, bitwarden_csv_columns, delimiter=',', quotechar='"')
writer.writeheader()
for firefox in reader:
bitwarden={
'folder': folder,
'favorite': '',
'type': 'login',
'fields': '',
'reprompt': '',
'login_totp': '',
}
domain=re.sub('https?://', '', firefox['url'])
domain=re.sub('/.*', '', domain)
bitwarden['name'] = firefox['username'] + '@' + domain
bitwarden['login_uri'] = firefox['url']
bitwarden['login_username'] = firefox['username']
bitwarden['login_password'] = firefox['password']
timec = epoch2timestamp(firefox['timeCreated'])
timea = epoch2timestamp(firefox['timeLastUsed'])
timem = epoch2timestamp(firefox['timePasswordChanged'])
bitwarden['notes'] = "\n".join([
f"http realm: {firefox['httpRealm']}",
f"form action origin: {firefox['formActionOrigin']}",
f"guid: {firefox['guid']}",
f"time created: {timec}",
f"time accessed: {timea}",
f"time modified: {timem}",
])
writer.writerow(bitwarden)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment