Skip to content

Instantly share code, notes, and snippets.

@mdoering
Created March 1, 2025 12:37
Show Gist options
  • Save mdoering/4d6712871a807eaad8ce2225526c72db to your computer and use it in GitHub Desktop.
Save mdoering/4d6712871a807eaad8ce2225526c72db to your computer and use it in GitHub Desktop.
1Password importer script for unencrypted Bitwarden JSON exports
#!/usr/bin/python3
import json, asyncio, os, re, sys
from onepassword.client import Client
from onepassword import *
VAULT_ID="XXX" # your 1Password vault identifier to import to
FILE="bitwarden.json" # local bitwarden json export filename, unencrypted
skip=0 # 1Password has rate limiting. You can call this script several times and skip the ones you already imported before
counter=0
def appendCardField(fields, card, id, title, key, type):
if card[key]:
fields.append( ItemField(id=id, title=title, value=card[key], field_type=type, section_id="") )
# I had many fields in Bitwarden taken from some registration forms which were just noise. This ignore the bulk of them
def isGoodField(key, val):
if val in [None, "✓","×","Senden","Registrieren","Anmelden"]:
return False
if key in ["remember_me","no_name","os_cookie","OptinAgb","OptinDs","wp-submit","guest-account","submit","shippingTo","describe_yourself","regtype","interested_in"]:
return False
for pre in ["form[","default_options[","signup_form[","register[","orderhead[","invadr[","default_address[","data[","customer.","address.","address[","dnn$ctr31","userfield[","textButton","registration["]:
if key.startswith(pre):
return False
return True
async def importItem(client, obj):
global counter
oid=obj['id']
title=obj['name']
notes=obj['notes']
# not imported
fav=obj['favorite']
modified=obj['revisionDate']
sites=[]
fields=[]
sections=[ItemSection(id="", title="")]
counter+=1
if (counter == skip+1):
print('\n +++ Start adding from here!\n')
print(counter, title)
if (counter <= skip):
return
if 'login' in obj:
login=obj['login']
sites=[Website(label="Website",url=x["uri"],autofill_behavior=AutofillBehavior.ANYWHEREONWEBSITE) for x in login['uris'] if 'uri' in x]
if login['username']:
fields.append( ItemField(id='username', title='username', value=login['username'], field_type=ItemFieldType.TEXT) )
if login['password']:
fields.append( ItemField(id='password', title='password', value=login['password'], field_type=ItemFieldType.CONCEALED) )
if 'card' in obj:
card=obj['card']
appendCardField(fields, card, id='cardholder', title='Cardholder Name', key='cardholderName', type=ItemFieldType.TEXT)
appendCardField(fields, card, id='type', title='Type', key='brand', type=ItemFieldType.CREDITCARDTYPE)
appendCardField(fields, card, id='ccnum', title='Number', key='number', type=ItemFieldType.CREDITCARDNUMBER)
appendCardField(fields, card, id='cvv', title='Verification Number', key='code', type=ItemFieldType.CONCEALED)
if card['expMonth'] and card['expYear']:
fields.append( ItemField(id='expiry', title='Expiry Date', value=card['expMonth']+" / "+card['expYear'], section_id="", field_type=ItemFieldType.TEXT) )
if 'fields' in obj:
sections.append( ItemSection(id="other", title="Other") )
fields.extend( [ItemField(id="field"+str(i), title=x["name"], value=x["value"], section_id="other", field_type=ItemFieldType.TEXT) for i,x in enumerate(obj['fields'], 1) if isGoodField(x["name"], x["value"])] )
match obj['type']:
case 1:
category = ItemCategory.LOGIN
case 2:
category = ItemCategory.SECURENOTE
case 3:
category = ItemCategory.CREDITCARD
case _:
raise Exception("Unknown bitwarden category: " + str(obj['type']))
to_create = ItemCreateParams(
title=title,
category=category,
vault_id=VAULT_ID,
fields=fields,
sections=sections,
notes=notes,
websites=sites,
)
created_item = await client.items.create(to_create)
async def main():
# Gets your service account token from the OP_SERVICE_ACCOUNT_TOKEN environment variable.
token = os.getenv("OP_SERVICE_ACCOUNT_TOKEN")
# Connects to 1Password. Fill in your own integration name and version.
client = await Client.authenticate(auth=token, integration_name="Bitwarden Importer", integration_version="v1.0.0")
print("\n +++ Read Bitwarden JSON from " + FILE)
with open(FILE) as f:
data = json.load(f)
if skip>0:
print('\n +++ Skip first ' + str(skip) + ' entries\n')
for obj in data['items']:
await importItem(client, obj)
if __name__ == '__main__':
if len(sys.argv)>1:
skip=int(sys.argv[1])
asyncio.run(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment