157 lines
4.6 KiB
Python
157 lines
4.6 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import argparse
|
|
import csv
|
|
import json
|
|
import os
|
|
import subprocess as sp
|
|
import tempfile
|
|
from collections import namedtuple
|
|
|
|
OP_BIN = 'op'
|
|
GPG_BIN = 'gpg'
|
|
TAR_BIN = 'tar'
|
|
|
|
Record = namedtuple('Record', [
|
|
"folder",
|
|
"favorite",
|
|
"type",
|
|
"name",
|
|
"notes",
|
|
"fields",
|
|
"reprompt",
|
|
"login_uri",
|
|
"login_username",
|
|
"login_password",
|
|
"login_totp"
|
|
])
|
|
|
|
Vault = namedtuple('Vault', ['title', 'records'])
|
|
|
|
|
|
def main():
|
|
args = parse_args()
|
|
output_file_name = os.path.abspath(args.file_name)
|
|
vaults = [process_vault(v) for v in retrieve_vaults()]
|
|
|
|
with tempfile.TemporaryDirectory(suffix='-one-password-export') as dir_path:
|
|
print('Store temp files in {}'.format(dir_path))
|
|
for vault in vaults:
|
|
save_vault(dir_path, vault)
|
|
if args.password:
|
|
export_encrypted(dir_path, output_file_name, args.password)
|
|
else:
|
|
export_plain(dir_path, output_file_name)
|
|
print('Done')
|
|
|
|
|
|
def parse_args():
|
|
parser = argparse.ArgumentParser(description='Export 1password logins')
|
|
parser.add_argument('file_name', type=str,
|
|
help='output file name')
|
|
parser.add_argument('--password', dest='password',
|
|
help='encrypt data')
|
|
return parser.parse_args()
|
|
|
|
|
|
def process_vault(vault):
|
|
vault_uuid = vault['id']
|
|
vault_name = vault['name']
|
|
str_v = lambda v, m: '\rVault "{}": {:20}'.format(v, m)
|
|
str_vr = lambda v, i, t: str_v(v, '{}/{}'.format(i, t))
|
|
print(str_v(vault_name, 'fetch items'), end='')
|
|
items = retrieve_items(vault_uuid)
|
|
records = []
|
|
records.append(Record("folder","favorite","type","name","notes","fields","reprompt","login_uri","login_username","login_password","login_totp"))
|
|
print(str_vr(vault_name, 0, len(items)), end='')
|
|
for index, item in enumerate(items):
|
|
item_data = retrieve_item(item['id'])
|
|
extracted = extract_item_fields(item_data)
|
|
records.append(extracted)
|
|
print(str_vr(vault_name, index + 1, len(items)), end='')
|
|
print('')
|
|
return Vault(title=vault_name, records=records)
|
|
|
|
|
|
def save_vault(base_dir, vault):
|
|
file_name = os.path.join(base_dir, vault.title.lower())
|
|
with open(file_name, 'w') as csv_file:
|
|
record_writer = csv.writer(csv_file)
|
|
for record in vault.records:
|
|
record_writer.writerow([
|
|
record.folder,
|
|
record.favorite,
|
|
record.type,
|
|
record.name,
|
|
record.notes,
|
|
record.fields,
|
|
record.login_uri,
|
|
record.login_username,
|
|
record.login_password,
|
|
record.login_totp
|
|
])
|
|
|
|
|
|
def export_plain(dir_path, file_name):
|
|
sp.run([TAR_BIN, '-cf', file_name + '.tar', '-C', dir_path, '.'])
|
|
|
|
|
|
def export_encrypted(dir_path, file_name, password):
|
|
gpg_name = file_name + '.tar.gpg'
|
|
with tempfile.TemporaryDirectory(suffix='-one-password-export') as tar_dir_path:
|
|
tar_name = os.path.join(tar_dir_path, os.path.basename(file_name) + '.tar')
|
|
print('Store temp tar in ' + tar_name)
|
|
sp.run([TAR_BIN, '-cf', tar_name, '-C', dir_path, '.'])
|
|
sp.run([GPG_BIN, '--symmetric', '--batch', '--yes', '--passphrase', password,
|
|
'--output', gpg_name, tar_name])
|
|
|
|
|
|
def retrieve_vaults():
|
|
print('Fetch vault list')
|
|
data = catch_op_json([OP_BIN, 'vault', 'list', '--format=json'])
|
|
return data
|
|
|
|
|
|
def retrieve_items(vault_uuid):
|
|
data = catch_op_json([OP_BIN, 'item', 'list', '--vault=' + vault_uuid, '--format=json'])
|
|
return data
|
|
|
|
|
|
def retrieve_item(item_uuid):
|
|
data = catch_op_json([OP_BIN, 'item', 'get', item_uuid, '--format=json'])
|
|
return data
|
|
|
|
|
|
def extract_item_fields(item_data):
|
|
fields = item_data.get('fields', [])
|
|
return Record(
|
|
folder=(item_data.get('vault', {})).get('name', ''),
|
|
favorite="",
|
|
type=item_data.get('category', '').lower(),
|
|
name=item_data.get('title', ''),
|
|
notes=value_from_fields(fields, 'notesPlain'),
|
|
fields="",
|
|
reprompt=0,
|
|
login_uri=item_data.get('urls', [])[0].get("href", ""),
|
|
login_username=value_from_fields(fields, 'username').strip(),
|
|
login_password=value_from_fields(fields, 'password').strip(),
|
|
login_totp=""
|
|
)
|
|
|
|
|
|
def value_from_fields(item_fields, key):
|
|
for f in item_fields:
|
|
if f.get('id', '') == key:
|
|
return f.get('value', '')
|
|
return ''
|
|
|
|
|
|
def catch_op_json(args):
|
|
output = sp.run(args, check=True, stdout=sp.PIPE).stdout
|
|
return json.loads(output.decode('utf-8'))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|