Skip to content

Instantly share code, notes, and snippets.

@mdaniel
Created January 6, 2016 08:15
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 mdaniel/059294c298ad6c89397c to your computer and use it in GitHub Desktop.
Save mdaniel/059294c298ad6c89397c to your computer and use it in GitHub Desktop.
Driver for https://github.com/Roguelazer/onepasswordpy.git; ```mkdir onepassword/cli; touch onepassword/cli/__init__.py``` then put this `__main__.py` into `onepassword/cli` and invoke it with `python -m onepassword.cli -k path/to/my/keystore --list`
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import, print_function, unicode_literals
import json
import sys
from getopt import getopt
from getpass import getpass
# this is a factory method that one can find in "keychain.patch" below
from ..keychain import load_keychain
def main(argv):
opts, args = getopt(argv[1:], 'k:lv', ['keychain=', 'list', 'verbose'])
keychain_path = None
verbose = False
do_list = False
for optval, optarg in opts:
if optval in ('-k', '--keychain'):
keychain_path = optarg
elif optval in ('-l', '--list'):
do_list = True
elif optval in ('-v', '--verbose'):
verbose = True
if not keychain_path:
print('Usage: {0} [-l|--list] -k|--keychain path/to/keychain'.format(argv[0]),
file=sys.stderr)
return 1
kc = load_keychain(keychain_path)
if do_list:
p = getpass()
kc.unlock(p)
out_fh = sys.stdout
if verbose:
print('Keys:', file=out_fh)
for k in kc.keys:
print(' "{0}"'.format(k), file=out_fh)
def to_dict(i):
result = {d: unicode(getattr(i, d)) for d in dir(i)
if d != 'keychain' and
not d.startswith('__') and
not callable(getattr(i, d))}
result['__open__'] = i.decrypt()
return result
#: :type: list[onepassword.item.AItem]
the_items = kc.items
open_items = [to_dict(i) for i in the_items]
json.dump(open_items, out_fh, sort_keys=True, indent=2)
out_fh.flush()
out_fh.close()
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv))
diff --git a/onepassword/keychain.py b/onepassword/keychain.py
index be62c69..6c28649 100644
--- a/onepassword/keychain.py
+++ b/onepassword/keychain.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
import base64
import glob
import os.path
@@ -5,8 +6,8 @@ import os.path
import simplejson
from . import crypt_util
-from . import padding
from .item import AItem, CItem
+__docformat__ = 'reStructuredText'
EXPECTED_VERSION_MIN = 30000
EXPECTED_VERSION_MAX = 40000
@@ -14,6 +15,8 @@ EXPECTED_VERSION_MAX = 40000
class _AbstractKeychain(object):
"""Implementation of common keychain logic (MP design, etc)."""
+ items = None
+ keys = None
def __init__(self, path):
self._open(path)
@@ -63,8 +66,8 @@ class AKeychain(_AbstractKeychain):
))
def unlock(self, password):
- keys = self._load_keys(password)
- self._load_items(keys)
+ self._load_keys(password)
+ self._load_items()
def _load_keys(self, password):
self.keys = {}
@@ -79,7 +82,7 @@ class AKeychain(_AbstractKeychain):
self.keys[identifier] = crypt_util.a_decrypt_key(key, password)
self.levels = levels
- def _load_items(self, keys):
+ def _load_items(self):
items = []
for f in glob.glob(os.path.join(self.base_path, 'data', 'default', '*.1password')):
items.append(AItem.new_from_file(f, self))
@@ -176,3 +179,19 @@ class CKeychain(_AbstractKeychain):
key,
hmac
)
+
+
+def load_keychain(keychain_path):
+ """
+ :type keychain_path: str|unicode
+ :param keychain_path: the filesystem path to the keychain
+ :return: the appropriate kind of keychain for that path
+ :rtype: AKeychain|CKeychain
+ :raises ValueError: if unable to recognize the provided path
+ """
+ if keychain_path.endswith('.agilekeychain'):
+ return AKeychain(keychain_path)
+ elif keychain_path.endswith('.cloudkeychain'):
+ return CKeychain(keychain_path)
+ else:
+ raise ValueError('Unrecognized keychain path: "{0}"'.format(keychain_path))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment