From 66a1ee3e27f04f8e73958c71bc29c530265b9f24 Mon Sep 17 00:00:00 2001 From: Markus Birth <130302+mbirth@users.noreply.github.com> Date: Wed, 18 Aug 2021 18:35:03 +0200 Subject: [PATCH] Add support for TOTP tokens. --- README.md | 14 +++++++++++++- convert.py | 20 +++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9ba3902..06fbad2 100644 --- a/README.md +++ b/README.md @@ -1 +1,13 @@ -Quick hack to export a 1pif (1Password export) to kdbx (KeePass). +Improved quick hack to convert a 1pif (1Password export) to kdbx (KeePass). + + +Install dependencies +-------------------- + + pipenv install + + +Run converter +------------- + + pipenv run ./convert.py infile.1pif diff --git a/convert.py b/convert.py index 9bf1a33..e1fdd53 100755 --- a/convert.py +++ b/convert.py @@ -7,7 +7,7 @@ import onepif from os.path import splitext from pykeepass import create_database -from urllib.parse import urlparse +from urllib.parse import urlparse, quote_plus parser = argparse.ArgumentParser(description="Convert 1Password 1PIF exports into a KeePass KDBX file.") parser.add_argument("inpath", metavar="input.1pif", help="1Password export file/folder") @@ -65,6 +65,18 @@ def getField(item, designation): return None +def getTotp(item): + secure = item["secureContents"] + if "sections" in secure: + for section in secure["sections"]: + if not "fields" in section: + continue + for field in section["fields"]: + if field["t"] == "totp": + return field["v"] + return None + + opif = onepif.OnepifReader("{}/data.1pif".format(args.inpath)) for item in opif: @@ -94,6 +106,12 @@ for item in opif: if new_password: entry.password = new_password + # TOTP + totp = getTotp(item) + if totp: + entry.set_custom_property("TimeOtp-Secret-Base32", totp) + entry.set_custom_property("otp", "otpauth://totp/Sample:username?secret={}&algorithm=SHA1&digits=6&period=30&issuer=Sample".format(quote_plus(totp))) + # Other web fields if "fields" in secure: for field in secure["fields"]: