Skip to content

Instantly share code, notes, and snippets.

@bysse
Created November 29, 2021 12:46
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 bysse/c374b31dc69ef8ef1cd0f08843adaa95 to your computer and use it in GitHub Desktop.
Save bysse/c374b31dc69ef8ef1cd0f08843adaa95 to your computer and use it in GitHub Desktop.
Convert Dashlane CSV to Bitwarden CSV format
#!/bin/python3
import sys
import urllib.parse
# Folder for uncategorized credentials
import_folder = "Dashlane"
with open("credentials.csv") as fp:
data = [[y.strip() for y in x.strip().split(",")] for x in fp.readlines()]
dashlane_cols = ["username","username2","username3","title","password","note","url","category","otpSecret"]
bitwarden_cols = ["folder","favorite","type","name","notes","fields","reprompt","login_uri","login_username","login_password","login_totp"]
def validate(description, valid):
print("# {:50} [{}]".format(description, "OK" if valid else "ERROR"))
if not valid:
raise Exception("Validation failed: " + description)
def col(name):
return dashlane_cols.index(name)
def writeCSV(fp, array):
fp.write(",".join(array))
fp.write("\n")
def main():
# verify CSV headers
header = data[0]
validate("Byte order in CSV export", header[0][0] == "\ufeff")
header[0] = header[0][1:]
validate("Dashlane CSV column names", header == dashlane_cols)
# convert each line
result = []
print("# Converting records")
for record in data[1:]:
converted = {}
title = record[col("title")]
entryurl = record[col("url")]
if not title and entryurl:
# use the hostname when the title is missing but a url is present
try:
title = urllib.parse.urlparse(entryurl).netloc
except Exception as e:
pass
converted["name"] = title
converted["login_uri"] = entryurl
converted["login_username"] = record[col("username")]
# Convert the username2 fild
if username2 := record[col("username2")]:
converted["fields"] = "username2:" + username2
if username3 := record[col("username3")]:
print("WARNING: username3 is not supported by this converter")
# Convert password, notes and OTP
converted["login_password"] = record[col("password")]
converted["notes"] = record[col("note")]
converted["login_totp"] = record[col("otpSecret")]
# Convert the category and use the default if it's missing
if category := record[col("category")]:
converted["folder"] = category
else:
converted["folder"] = import_folder
# Add missing columns
converted["favorite"] = 0
converted["type"] = "login"
converted["reprompt"] = 0
if not "fields" in converted:
converted["fields"] = ""
# Add the line to the converted data set
result.append(converted)
print(" -", len(result), "records")
# Export the converted CSV
print("# Writing records")
with open("bitwarden_credentials.csv", "w") as fp:
writeCSV(fp, bitwarden_cols)
for record in sorted(result, key = lambda x: x["name"].lower()):
line = []
for column in bitwarden_cols:
line.append(str(record[column]))
writeCSV(fp, line)
print(" -", len(result), "records")
try:
main()
except Exception as e:
print("ERROR: Conversion failed with message", e)
sys.exit(1)
#!/bin/python3
import sys
# Folder for ntoes
import_folder = "Dashlane"
with open("securenotes.csv") as fp:
data = [[y.strip() for y in x.strip().split(",")] for x in fp.readlines()]
dashlane_cols = ["title","note"]
bitwarden_cols = ["folder","favorite","type","name","notes","fields","reprompt","login_uri","login_username","login_password","login_totp"]
def validate(description, valid):
print("# {:50} [{}]".format(description, "OK" if valid else "ERROR"))
if not valid:
raise Exception("Validation failed: " + description)
def col(name):
return dashlane_cols.index(name)
def writeCSV(fp, array):
fp.write(",".join(array))
fp.write("\n")
def main():
# verify CSV headers
header = data[0]
validate("Byte order in CSV export", header[0][0] == "\ufeff")
header[0] = header[0][1:]
validate("Dashlane CSV column names", header == dashlane_cols)
# convert each line
result = []
print("# Converting records")
for record in data[1:]:
converted = {}
# create all columns
for column in bitwarden_cols:
converted[column] = ""
converted["type"] = "note"
converted["name"] = record[col("title")]
converted["notes"] = record[col("note")]
# Add the line to the converted data set
result.append(converted)
print(" -", len(result), "records")
# Export the converted CSV
print("# Writing records")
with open("bitwarden_securenotes.csv", "w") as fp:
writeCSV(fp, bitwarden_cols)
for record in sorted(result, key = lambda x: x["name"].lower()):
line = []
for column in bitwarden_cols:
line.append(str(record[column]))
writeCSV(fp, line)
print(" -", len(result), "records")
try:
main()
except Exception as e:
print("ERROR: Conversion failed with message", e)
sys.exit(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment