Skip to content

Instantly share code, notes, and snippets.

@charlieman
Created August 15, 2011 22:34
Show Gist options
  • Save charlieman/1148050 to your computer and use it in GitHub Desktop.
Save charlieman/1148050 to your computer and use it in GitHub Desktop.
One file command line version of oplop (http://oplop.googlecode.com/), added option to generate passphrases with -p
#!/usr/bin/env python
# "Generate account passwords based on an account name and a master password."
from __future__ import print_function
try:
import argparse
except ImportError:
from . import argparse
try:
import win32clipboard
except ImportError:
win32clipboard = None
from getpass import getpass
import subprocess
import sys
## __init__.py
try:
from hashlib import md5
except ImportError:
from md5 import md5
import base64
import re
_length = 8
def make_counter(start=0):
def get_next():
get_next.count += 1
return get_next.count
get_next.count = start
return get_next
def iter_pairs(iterable):
loop = iter(iterable)
first = loop.next()
for second in loop:
yield (first, second)
first = second
def _raw_hash(label, password):
"""Generate a unique hash from a label and master password."""
hash_object = md5()
hash_object.update(password)
hash_object.update(label)
return base64.urlsafe_b64encode(hash_object.digest())
def _raw_hash_sha512(label, password):
"""Generate a unique hash from a label and master password."""
from hashlib import sha512
hash_object = sha512()
hash_object.update(password)
hash_object.update(label)
return base64.urlsafe_b64encode(hash_object.digest())
def create(label, master):
"""Create a password from a label and master password."""
encoded_label = label.encode("utf-8")
encoded_master = master.encode("utf-8")
hash_ = _raw_hash(encoded_label, encoded_master).decode("ascii")
found = re.search(r"\d+", hash_)
if not found:
hash_ = '1' + hash_
elif found.start() >= _length:
hash_ = found.group() + hash_
return hash_[:_length]
def create_phrase(label, master, parts=4):
"""Create a passphrase from a label and master password."""
encoded_label = label.encode("utf-8")
encoded_master = master.encode("utf-8")
hash_ = _raw_hash_sha512(encoded_label, encoded_master).decode("ascii")
counter = make_counter(1)
size = len(hash_)
ranges = range(0, size, _length)[:parts + 1]
regex = re.compile(r"\d+")
phrase = []
for start, end in iter_pairs(ranges):
part = hash_[start:end]
found = regex.search(part)
if not found:
part = str(counter()) + part
elif found.start() >= _length:
part = found.group() + part
phrase.append(part)
return ' '.join(phrase)
##
# Python 2.6 compat along with ease of mocking.
try:
from builtins import input
except ImportError:
input = raw_input
def get_account_name():
print("Nickname = ", end="", file=sys.stderr)
return input()
def get_master_password(verifying=False):
return getpass('Master password {0}(not echoed) ... '.format(
['', 'again '][verifying]))
def print_account_password(account_password):
"""Print the account password to stdout."""
print('', file=sys.stderr)
sys.stderr.flush()
print(account_password, end="", file=sys.stdout)
sys.stdout.flush()
print('', file=sys.stderr)
sys.stderr.flush()
return True
def clipboard(command, account_password):
try:
clipboard = subprocess.Popen(command, stdin=subprocess.PIPE)
except OSError as exc:
if exc.errno == 2:
print("{0} does not exist.".format(command[0]), file=sys.stderr)
else:
raise
return False
account_password_bytes = account_password.encode(sys.stdin.encoding)
out, err = clipboard.communicate(account_password_bytes)
if out or err:
print("Unexpected output when using {0!r}:".format(' '.join(command)),
file=sys.stderr)
if out:
print("stdout:\n", out, sep=" ", file=sys.stderr)
if err:
print("stderr:\n", err, sep=" ", file=sys.stderr)
return False
else:
print("\nAccount password copied to the clipboard "
"using {0!r}".format(' '.join(command)), file=sys.stderr)
return True
def osx_clipboard(account_password):
"""Set the clipboard to the account password under OS X."""
return clipboard(['pbcopy'], account_password)
def x11_clipboard(account_password):
"""Use the X11 clipboard through xclip to set the account password."""
return clipboard(['xclip', '-selection', 'clipboard'], account_password)
def win32_clipboard(account_password):
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(account_password)
win32clipboard.CloseClipboard()
print("\nAccount password copied to the clipboard", file=sys.stderr)
return True
def set_account_password(account_password, clipboard=True, stdout=True):
if clipboard:
if sys.platform == 'darwin':
if osx_clipboard(account_password):
return True
elif sys.platform == 'win32' and win32clipboard is not None:
if win32_clipboard(account_password):
return True
elif x11_clipboard(account_password):
return True
if stdout:
# Fallback if no clipboard works.
print_account_password(account_password)
return True
else:
return False
def main(cmd_line_args=[]):
parser = argparse.ArgumentParser(prog="oplop", description=__doc__)
parser.add_argument("--passphrase", "-p", action='store_true',
help="Create a passphrase rather than a password")
parser.add_argument("--stdout", "-o", action='store_true',
help="Print account password to stdout; do not use the clipboard")
parser.add_argument("--clipboard", "-c", action='store_true',
help="Only use the clipboard")
parser.add_argument("--verify", "-v", action='store_true',
help='Double-check the master password by entering it twice')
parser.add_argument("nickname", nargs='?', help="Account nickname")
parser.add_argument("master_password", nargs='?', help="Master password")
args = parser.parse_args(cmd_line_args)
if args.nickname:
label = args.nickname
else:
label = get_account_name()
if args.master_password:
master = args.master_password
else:
master = get_master_password()
if args.verify:
master_again = get_master_password(verifying=True)
if master != master_again:
print("\nMaster password verification failed!", file=sys.stderr)
sys.exit(1)
if args.passphrase:
password = create_phrase(label, master)
else:
password = create(label, master)
use_clipboard = not args.stdout
use_stdout = not args.clipboard
if not set_account_password(password, clipboard=use_clipboard,
stdout=use_stdout):
sys.exit(1)
if __name__ == '__main__':
main(sys.argv[1:])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment