Support for multiple OTP secrets per 1P-record.

This commit is contained in:
Markus Birth 2021-08-20 16:37:14 +02:00
parent 90fc1e3d24
commit 4bf76d1b30
Signed by: mbirth
GPG Key ID: A9928D7A098C3A9A
3 changed files with 27 additions and 11 deletions

View File

@ -88,6 +88,11 @@ for item in opif:
# Tags
kp.set_tags(item.get_tags())
# TOTP
totps = item.get_totps()
if totps:
for totp in totps:
kp.add_totp(totp[0], title=totp[1])
@ -110,10 +115,6 @@ for item in opif:
if new_password:
entry.password = new_password
# TOTP
totp = item.get_totp()
if totp:
kp.add_totp(totp)
# Other web fields
if "fields" in secure:

View File

@ -32,12 +32,21 @@ class KpWriter:
def set_tags(self, tag_list):
self.current_entry.tags = tag_list
def add_totp(self, init_string, otp_url=None):
def add_totp(self, init_string, otp_url=None, title=""):
if not otp_url:
otp_url = "otpauth://totp/Sample:username?secret={}&algorithm=SHA1&digits=6&period=30&issuer=Sample".format(quote_plus(init_string))
# TODO: Support multiple / don't overwrite
self.set_prop("TimeOtp-Secret-Base32", init_string, True)
self.set_prop("otp", otp_url)
# It's possible to define multiple OTP-secrets in 1P7, so let's not lose one
suffix = ""
suffix_ctr = 1
while self.current_entry.get_custom_property("otp{}".format(suffix)):
suffix_ctr += 1
suffix = "_{}".format(suffix_ctr)
self.set_prop("TimeOtp-Secret-Base32{}".format(suffix), init_string, True)
self.set_prop("otp{}".format(suffix), otp_url)
if len(title) > 0:
self.set_prop("otp_title{}".format(suffix), title)
def set_prop(self, key, value, protected=False):
self.current_entry.set_custom_property(key, value)

View File

@ -41,15 +41,21 @@ class OnepifEntry():
return []
return self.raw["openContents"]["tags"]
def get_totp(self):
def get_totps(self):
totp_fields = []
if "sections" in self.raw["secureContents"]:
for section in self.raw["secureContents"]["sections"]:
if "fields" not in section:
continue
for field in section["fields"]:
if field["n"][:5] == "TOTP_":
return field["v"]
return None
totp_fields.append([
field["v"],
field["t"], # Custom title, if set (isn't displayed in 1P)
])
if len(totp_fields) == 0:
return None
return totp_fields
def is_trash(self):
if "trashed" in self.raw: