diff --git a/README.rst b/README.rst index af7009d..ac672c1 100644 --- a/README.rst +++ b/README.rst @@ -34,6 +34,8 @@ CLI Usage is as follows:: [-L [LANGUAGES [LANGUAGES ...]]] [-N NAME_REGEX] [-H GITHUB_HOST] [-O] [-R REPOSITORY] [-P] [-F] [--prefer-ssh] [-v] + [--keychain-name OSX_KEYCHAIN_ITEM_NAME] + [--keychain-account OSX_KEYCHAIN_ITEM_ACCOUNT] USER Backup a github account @@ -83,6 +85,12 @@ CLI Usage is as follows:: -F, --fork include forked repositories --prefer-ssh Clone repositories using SSH instead of HTTPS -v, --version show program's version number and exit + --keychain-name OSX_KEYCHAIN_ITEM_NAME + OSX ONLY: name field of password item in OSX keychain + that holds the personal access or OAuth token + --keychain-account OSX_KEYCHAIN_ITEM_ACCOUNT + OSX ONLY: account field of password item in OSX + keychain that holds the personal access or OAuth token The package can be used to backup an *entire* organization or repository, including issues and wikis in the most appropriate format (clones for wikis, json files for issues). @@ -91,3 +99,18 @@ Authentication ============== Note: Password-based authentication will fail if you have two-factor authentication enabled. + +Using the Keychain on Mac OSX +============================= +Note: On Mac OSX the token can be stored securely in the user's keychain. To do this: + +1. Open Keychain from "Applications -> Utilities -> Keychain Access" +2. Add a new password item using "File -> New Password Item" +3. Enter a name in the "Keychain Item Name" box. You must provide this name to github-backup using the --keychain-name argument. +4. Enter an account name in the "Account Name" box, enter your Github username as set above. You must provide this name to github-backup using the --keychain-account argument. +5. Enter your Github personal access token in the "Password" box + +Note: When you run github-backup, you will be asked whether you want to allow "security" to use your confidential information stored in your keychain. You have two options: + +1. **Allow:** In this case you will need to click "Allow" each time you run `github-backup` +2. **Always Allow:** In this case, you will not be asked for permission when you run `github-backup` in future. This is less secure, but is required if you want to schedule `github-backup` to run automatically diff --git a/bin/github-backup b/bin/github-backup index 253dc1e..5a2a635 100755 --- a/bin/github-backup +++ b/bin/github-backup @@ -16,6 +16,7 @@ import select import subprocess import sys import time +import platform try: # python 3 from urllib.parse import urlparse @@ -251,13 +252,37 @@ def parse_args(): parser.add_argument('-v', '--version', action='version', version='%(prog)s ' + __version__) + parser.add_argument('--keychain-name', + dest='osx_keychain_item_name', + help='OSX ONLY: name field of password item in OSX keychain that holds the personal access or OAuth token') + parser.add_argument('--keychain-account', + dest='osx_keychain_item_account', + help='OSX ONLY: account field of password item in OSX keychain that holds the personal access or OAuth token') return parser.parse_args() def get_auth(args, encode=True): auth = None - if args.token: + if args.osx_keychain_item_name: + if not args.osx_keychain_item_account: + log_error('You must specify both name and account fields for osx keychain password items') + else: + if platform.system() != 'Darwin': + log_error("Keychain arguments are only supported on Mac OSX") + try: + with open(os.devnull,'w') as devnull: + token = (subprocess.check_output([ + 'security','find-generic-password', + '-s',args.osx_keychain_item_name, + '-a',args.osx_keychain_item_account, + '-w' ], stderr=devnull).strip()) + auth = token + ':' + 'x-oauth-basic' + except: + log_error('No password item matching the provided name and account could be found in the osx keychain.') + elif args.osx_keychain_item_account: + log_error('You must specify both name and account fields for osx keychain password items') + elif args.token: _path_specifier = 'file://' if args.token.startswith(_path_specifier): args.token = open(args.token[len(_path_specifier):],