100 lines
2.8 KiB
Python
100 lines
2.8 KiB
Python
|
#!/usr/bin/python
|
||
|
# Originally taken from: http://stevelosh.com/blog/2012/10/the-homely-mutt/
|
||
|
# by Steve Losh
|
||
|
# Modified by Lorenzo Grespan on Jan, 2014
|
||
|
|
||
|
import re
|
||
|
import subprocess
|
||
|
from sys import argv
|
||
|
import logging
|
||
|
from os.path import expanduser
|
||
|
import unittest
|
||
|
import os
|
||
|
import sys
|
||
|
|
||
|
logging.basicConfig(level=logging.INFO)
|
||
|
|
||
|
|
||
|
DEFAULT_PASSWORDS_FILE = os.path.join(
|
||
|
os.path.expanduser('~/Mail'),
|
||
|
'passwords.gpg')
|
||
|
|
||
|
|
||
|
def get_keychain_pass(account=None, server=None):
|
||
|
'''Mac OSX keychain password extraction'''
|
||
|
params = {
|
||
|
'security': '/usr/bin/security',
|
||
|
'command': 'find-internet-password',
|
||
|
'account': account,
|
||
|
'server': server,
|
||
|
'keychain': expanduser('~') + '/Library/Keychains/login.keychain',
|
||
|
}
|
||
|
command = ("%(security)s -v %(command)s"
|
||
|
" -g -a %(account)s -s %(server)s %(keychain)s" % params)
|
||
|
output = subprocess.check_output(
|
||
|
command, shell=True, stderr=subprocess.STDOUT)
|
||
|
outtext = [l for l in output.splitlines()
|
||
|
if l.startswith('password: ')][0]
|
||
|
return find_password(outtext)
|
||
|
|
||
|
|
||
|
def find_password(text):
|
||
|
'''Helper method for osx password extraction'''
|
||
|
# a non-capturing group
|
||
|
r = re.match(r'password: (?:0x[A-F0-9]+ )?"(.*)"', text)
|
||
|
if r:
|
||
|
return r.group(1)
|
||
|
else:
|
||
|
logging.warn("Not found")
|
||
|
return None
|
||
|
|
||
|
|
||
|
def get_gpg_pass(account, storage):
|
||
|
'''GPG method'''
|
||
|
command = ("gpg", "-d", storage)
|
||
|
# get attention
|
||
|
print '\a' # BEL
|
||
|
output = subprocess.check_output(command)
|
||
|
# p = subprocess.Popen(command, stdout=subprocess.PIPE)
|
||
|
# output, err = p.communicate()
|
||
|
for line in output.split('\n'):
|
||
|
r = re.match(r'{} ([a-zA-Z0-9]+)'.format(account), line)
|
||
|
if r:
|
||
|
return r.group(1)
|
||
|
return None
|
||
|
|
||
|
|
||
|
def get_pass(account=None, server=None, passwd_file=None):
|
||
|
'''Main method'''
|
||
|
if not passwd_file:
|
||
|
storage = DEFAULT_PASSWORDS_FILE
|
||
|
else:
|
||
|
storage = os.path.join(
|
||
|
os.path.expanduser('~/Mail'),
|
||
|
passwd_file)
|
||
|
if os.path.exists('/usr/bin/security'):
|
||
|
return get_keychain_pass(account, server)
|
||
|
if os.path.exists(storage):
|
||
|
logging.info("Using {}".format(storage))
|
||
|
return get_gpg_pass(account, storage)
|
||
|
else:
|
||
|
logging.warn("No password file found")
|
||
|
sys.exit(1)
|
||
|
return None
|
||
|
|
||
|
|
||
|
# test with: python -m unittest <this module name>
|
||
|
# really basic tests.. nothing to see. move along
|
||
|
class Tester(unittest.TestCase):
|
||
|
def testMatchSimple(self):
|
||
|
text = 'password: "exampleonetimepass "'
|
||
|
self.assertTrue(find_password(text))
|
||
|
|
||
|
def testMatchComplex(self):
|
||
|
text = r'password: 0x74676D62646D736B646970766C66696B0A "anotherexamplepass\012"'
|
||
|
self.assertTrue(find_password(text))
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
print get_pass(argv[1], argv[2], argv[3])
|