diff --git a/docs/ios/backup/check.md b/docs/ios/backup/check.md index 551205c..b51e074 100644 --- a/docs/ios/backup/check.md +++ b/docs/ios/backup/check.md @@ -41,9 +41,10 @@ In case you have an encrypted backup, you will need to decrypt it first. This ca -d, --destination TEXT Path to the folder where to store the decrypted backup [required] - -p, --password TEXT Password to use to decrypt the backup NOTE: This - argument is mutually exclusive with arguments: - [key_file]. + -p, --password TEXT Password to use to decrypt the backup (or, set + MVT_IOS_BACKUP_PASSWORD environment variable) + NOTE: This argument is mutually exclusive with + arguments: [key_file]. -k, --key-file PATH File containing raw encryption key to use to decrypt the backup NOTE: This argument is mutually exclusive @@ -51,10 +52,10 @@ In case you have an encrypted backup, you will need to decrypt it first. This ca --help Show this message and exit. -You can specify either a password via command-line or pass a key file, and you need to specify a destination path where the decrypted backup will be stored. If `-p` is omitted, MVT will ask for a password. Following is an example usage of `decrypt-backup`: +You can specify the password in the environment variable `MVT_IOS_BACKUP_PASSWORD`, or via command-line argument, or you can pass a key file. You need to specify a destination path where the decrypted backup will be stored. If a password cannot be found and no key file is specified, MVT will ask for a password. Following is an example usage of `decrypt-backup` sending the password via an environment variable: ```bash -mvt-ios decrypt-backup -p password -d /path/to/decrypted /path/to/backup +MVT_IOS_BACKUP_PASSWORD="mypassword" mvt-ios decrypt-backup -d /path/to/decrypted /path/to/backup ``` ## Run `mvt-ios` on a Backup diff --git a/mvt/ios/cli.py b/mvt/ios/cli.py index 78b1793..c8897c2 100644 --- a/mvt/ios/cli.py +++ b/mvt/ios/cli.py @@ -4,6 +4,7 @@ # https://github.com/mvt-project/mvt/blob/main/LICENSE import errno +import getpass import logging import os import sys @@ -28,6 +29,8 @@ log = logging.getLogger(__name__) # Help messages of repeating options. OUTPUT_HELP_MESSAGE = "Specify a path to a folder where you want to store JSON results" +# set this environment variable to a password if needed +PASSWD_ENV = 'MVT_IOS_BACKUP_PASSWORD' #============================================================================== # Main @@ -44,8 +47,7 @@ def cli(): @click.option("--destination", "-d", required=True, help="Path to the folder where to store the decrypted backup") @click.option("--password", "-p", cls=MutuallyExclusiveOption, - help="Password to use to decrypt the backup", - prompt="Enter backup password", hide_input=True, prompt_required=False, + help=f"Password to use to decrypt the backup (or, set {PASSWD_ENV} environment variable)", mutually_exclusive=["key_file"]) @click.option("--key-file", "-k", cls=MutuallyExclusiveOption, type=click.Path(exists=True), @@ -55,13 +57,21 @@ def cli(): def decrypt_backup(destination, password, key_file, backup_path): backup = DecryptBackup(backup_path, destination) - if password: - backup.decrypt_with_password(password) - elif key_file: + if key_file: + if PASSWD_ENV in os.environ: + log.warning(f"Ignoring {PASSWD_ENV} environment variable, using --key-file '{key_file}' instead") backup.decrypt_with_key_file(key_file) + elif password: + log.warning("Your password may be visible in the process table because it was supplied on the command line!") + if PASSWD_ENV in os.environ: + log.warning(f"Ignoring {PASSWD_ENV} environment variable, using --password argument instead") + backup.decrypt_with_password(password) + elif PASSWD_ENV in os.environ: + log.info(f"Using password from {PASSWD_ENV} environment variable") + backup.decrypt_with_password(os.environ[PASSWD_ENV]) else: - raise click.ClickException("Missing required option. Specify either " - "--password or --key-file.") + sekrit = getpass.getpass(prompt='Enter iOS backup password: ') + backup.decrypt_with_password(sekrit) backup.process_backup() @@ -71,9 +81,7 @@ def decrypt_backup(destination, password, key_file, backup_path): #============================================================================== @cli.command("extract-key", help="Extract decryption key from an iTunes backup") @click.option("--password", "-p", - help="Password to use to decrypt the backup", - prompt="Enter backup password", - hide_input=True, prompt_required=False, required=True) + help=f"Password to use to decrypt the backup (or, set {PASSWD_ENV} environment variable)") @click.option("--key-file", "-k", help="Key file to be written (if unset, will print to STDOUT)", required=False, @@ -81,6 +89,17 @@ def decrypt_backup(destination, password, key_file, backup_path): @click.argument("BACKUP_PATH", type=click.Path(exists=True)) def extract_key(password, backup_path, key_file): backup = DecryptBackup(backup_path) + + if password: + log.warning("Your password may be visible in the process table because it was supplied on the command line!") + if PASSWD_ENV in os.environ: + log.warning(f"Ignoring {PASSWD_ENV} environment variable, using --password argument instead") + elif PASSWD_ENV in os.environ: + log.info(f"Using password from {PASSWD_ENV} environment variable") + password = os.environ[PASSWD_ENV] + else: + password = getpass.getpass(prompt='Enter iOS backup password: ') + backup.decrypt_with_password(password) backup.get_key()