From: Torsten Grote Date: Tue, 11 Apr 2017 19:34:49 +0000 (-0300) Subject: Eliminate the need for password files X-Git-Tag: 0.8~81^2 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=4d25113fa0f6ad923b6b71ff9c8cb139042b1f9e;p=fdroidserver.git Eliminate the need for password files The passwords are now passed as private environment variables to the processes that need them. --- diff --git a/fdroidserver/common.py b/fdroidserver/common.py index 0c12c3f9..02d8aceb 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -254,10 +254,6 @@ def read_config(opts, config_file='config.py'): fill_config_defaults(config) - for k in ["keystorepass", "keypass"]: - if k in config: - write_password_file(k) - for k in ["repo_description", "archive_description"]: if k in config: config[k] = clean_description(config[k]) @@ -381,21 +377,6 @@ def ensure_build_tools_exists(thisconfig): sys.exit(3) -def write_password_file(pwtype, password=None): - ''' - writes out passwords to a protected file instead of passing passwords as - command line argments - ''' - filename = '.fdroid.' + pwtype + '.txt' - fd = os.open(filename, os.O_CREAT | os.O_TRUNC | os.O_WRONLY, 0o600) - if password is None: - os.write(fd, config[pwtype].encode('utf-8')) - else: - os.write(fd, password.encode('utf-8')) - os.close(fd) - config[pwtype + 'file'] = filename - - def get_local_metadata_files(): '''get any metadata files local to an app's source repo @@ -1744,12 +1725,13 @@ def SdkToolsPopen(commands, cwd=None, output=True): cwd=cwd, output=output) -def FDroidPopenBytes(commands, cwd=None, output=True, stderr_to_stdout=True): +def FDroidPopenBytes(commands, cwd=None, envs=None, output=True, stderr_to_stdout=True): """ Run a command and capture the possibly huge output as bytes. :param commands: command and argument list like in subprocess.Popen :param cwd: optionally specifies a working directory + :param envs: a optional dictionary of environment variables and their values :returns: A PopenResult. """ @@ -1757,6 +1739,10 @@ def FDroidPopenBytes(commands, cwd=None, output=True, stderr_to_stdout=True): if env is None: set_FDroidPopen_env() + process_env = env.copy() + if envs is not None and len(envs) > 0: + process_env.update(envs) + if cwd: cwd = os.path.normpath(cwd) logging.debug("Directory: %s" % cwd) @@ -1766,7 +1752,7 @@ def FDroidPopenBytes(commands, cwd=None, output=True, stderr_to_stdout=True): result = PopenResult() p = None try: - p = subprocess.Popen(commands, cwd=cwd, shell=False, env=env, + p = subprocess.Popen(commands, cwd=cwd, shell=False, env=process_env, stdout=subprocess.PIPE, stderr=stderr_param) except OSError as e: raise BuildException("OSError while trying to execute " + @@ -1806,15 +1792,16 @@ def FDroidPopenBytes(commands, cwd=None, output=True, stderr_to_stdout=True): return result -def FDroidPopen(commands, cwd=None, output=True, stderr_to_stdout=True): +def FDroidPopen(commands, cwd=None, envs=None, output=True, stderr_to_stdout=True): """ Run a command and capture the possibly huge output as a str. :param commands: command and argument list like in subprocess.Popen :param cwd: optionally specifies a working directory + :param envs: a optional dictionary of environment variables and their values :returns: A PopenResult. """ - result = FDroidPopenBytes(commands, cwd, output, stderr_to_stdout) + result = FDroidPopenBytes(commands, cwd, envs, output, stderr_to_stdout) result.output = result.output.decode('utf-8', 'ignore') return result @@ -2180,18 +2167,19 @@ def genkeystore(localconfig): if not os.path.exists(keystoredir): os.makedirs(keystoredir, mode=0o700) - write_password_file("keystorepass", localconfig['keystorepass']) - write_password_file("keypass", localconfig['keypass']) + env_vars = { + 'FDROID_KEY_STORE_PASS': localconfig['keystorepass'], + 'FDROID_KEY_PASS': localconfig['keypass'], + } p = FDroidPopen([config['keytool'], '-genkey', '-keystore', localconfig['keystore'], '-alias', localconfig['repo_keyalias'], '-keyalg', 'RSA', '-keysize', '4096', '-sigalg', 'SHA256withRSA', '-validity', '10000', - '-storepass:file', config['keystorepassfile'], - '-keypass:file', config['keypassfile'], - '-dname', localconfig['keydname']]) - # TODO keypass should be sent via stdin + '-storepass:env', 'FDROID_KEY_STORE_PASS', + '-keypass:env', 'FDROID_KEY_PASS', + '-dname', localconfig['keydname']], envs=env_vars) if p.returncode != 0: raise BuildException("Failed to generate key", p.output) os.chmod(localconfig['keystore'], 0o0600) @@ -2200,15 +2188,15 @@ def genkeystore(localconfig): p = FDroidPopen([config['keytool'], '-list', '-v', '-keystore', localconfig['keystore'], '-alias', localconfig['repo_keyalias'], - '-storepass:file', config['keystorepassfile']]) + '-storepass:env', 'FDROID_KEY_STORE_PASS'], envs=env_vars) logging.info(p.output.strip() + '\n\n') # get the public key p = FDroidPopenBytes([config['keytool'], '-exportcert', '-keystore', localconfig['keystore'], '-alias', localconfig['repo_keyalias'], - '-storepass:file', config['keystorepassfile']] + '-storepass:env', 'FDROID_KEY_STORE_PASS'] + config['smartcardoptions'], - output=False, stderr_to_stdout=False) + envs=env_vars, output=False, stderr_to_stdout=False) if p.returncode != 0 or len(p.output) < 20: raise BuildException("Failed to get public key", p.output) pubkey = p.output diff --git a/fdroidserver/index.py b/fdroidserver/index.py index e029fc50..44b1a1b9 100644 --- a/fdroidserver/index.py +++ b/fdroidserver/index.py @@ -69,10 +69,10 @@ def make(apps, sortedids, apks, repodir, archive): if 'keystore' not in common.config: nosigningkey = True logging.critical("'keystore' not found in config.py!") - if 'keystorepass' not in common.config and 'keystorepassfile' not in common.config: + if 'keystorepass' not in common.config: nosigningkey = True logging.critical("'keystorepass' not found in config.py!") - if 'keypass' not in common.config and 'keypassfile' not in common.config: + if 'keypass' not in common.config: nosigningkey = True logging.critical("'keypass' not found in config.py!") if not os.path.exists(common.config['keystore']): @@ -501,12 +501,13 @@ def extract_pubkey(): if 'repo_pubkey' in common.config: pubkey = unhexlify(common.config['repo_pubkey']) else: + env_vars = {'FDROID_KEY_STORE_PASS': common.config['keystorepass']} p = FDroidPopenBytes([common.config['keytool'], '-exportcert', '-alias', common.config['repo_keyalias'], '-keystore', common.config['keystore'], - '-storepass:file', common.config['keystorepassfile']] + '-storepass:env', 'FDROID_KEY_STORE_PASS'] + common.config['smartcardoptions'], - output=False, stderr_to_stdout=False) + envs=env_vars, output=False, stderr_to_stdout=False) if p.returncode != 0 or len(p.output) < 20: msg = "Failed to get repo pubkey!" if common.config['keystore'] == 'NONE': diff --git a/fdroidserver/publish.py b/fdroidserver/publish.py index bf4aa2dc..622de59c 100644 --- a/fdroidserver/publish.py +++ b/fdroidserver/publish.py @@ -72,12 +72,9 @@ def main(): logging.warning("No unsigned directory - nothing to do") sys.exit(1) - for f in [config['keystorepassfile'], - config['keystore'], - config['keypassfile']]: - if not os.path.exists(f): - logging.error("Config error - missing '{0}'".format(f)) - sys.exit(1) + if not os.path.exists(config['keystore']): + logging.error("Config error - missing '{0}'".format(config['keystore'])) + sys.exit(1) # It was suggested at # https://dev.guardianproject.info/projects/bazaar/wiki/FDroid_Audit @@ -175,9 +172,13 @@ def main(): # See if we already have a key for this application, and # if not generate one... + env_vars = { + 'FDROID_KEY_STORE_PASS': config['keystorepass'], + 'FDROID_KEY_PASS': config['keypass'], + } p = FDroidPopen([config['keytool'], '-list', '-alias', keyalias, '-keystore', config['keystore'], - '-storepass:file', config['keystorepassfile']]) + '-storepass:env', 'FDROID_KEY_STORE_PASS'], envs=env_vars) if p.returncode != 0: logging.info("Key does not exist - generating...") p = FDroidPopen([config['keytool'], '-genkey', @@ -185,20 +186,18 @@ def main(): '-alias', keyalias, '-keyalg', 'RSA', '-keysize', '2048', '-validity', '10000', - '-storepass:file', config['keystorepassfile'], - '-keypass:file', config['keypassfile'], - '-dname', config['keydname']]) - # TODO keypass should be sent via stdin + '-storepass:env', 'FDROID_KEY_STORE_PASS', + '-keypass:env', 'FDROID_KEY_PASS', + '-dname', config['keydname']], envs=env_vars) if p.returncode != 0: raise BuildException("Failed to generate key") # Sign the application... p = FDroidPopen([config['jarsigner'], '-keystore', config['keystore'], - '-storepass:file', config['keystorepassfile'], - '-keypass:file', config['keypassfile'], '-sigalg', + '-storepass:env', 'FDROID_KEY_STORE_PASS', + '-keypass:env', 'FDROID_KEY_PASS', '-sigalg', 'SHA1withRSA', '-digestalg', 'SHA1', - apkfile, keyalias]) - # TODO keypass should be sent via stdin + apkfile, keyalias], envs=env_vars) if p.returncode != 0: raise BuildException("Failed to sign application") diff --git a/fdroidserver/signindex.py b/fdroidserver/signindex.py index 4f0ac678..58c7e91f 100644 --- a/fdroidserver/signindex.py +++ b/fdroidserver/signindex.py @@ -40,14 +40,18 @@ def sign_jar(jar): https://code.google.com/p/android/issues/detail?id=38321 """ args = [config['jarsigner'], '-keystore', config['keystore'], - '-storepass:file', config['keystorepassfile'], + '-storepass:env', 'FDROID_KEY_STORE_PASS', '-digestalg', 'SHA1', '-sigalg', 'SHA1withRSA', jar, config['repo_keyalias']] if config['keystore'] == 'NONE': args += config['smartcardoptions'] else: # smardcards never use -keypass - args += ['-keypass:file', config['keypassfile']] - p = common.FDroidPopen(args) + args += ['-keypass:env', 'FDROID_KEY_PASS'] + env_vars = { + 'FDROID_KEY_STORE_PASS': config['keystorepass'], + 'FDROID_KEY_PASS': config['keypass'], + } + p = common.FDroidPopen(args, envs=env_vars) if p.returncode != 0: logging.critical("Failed to sign %s!" % jar) sys.exit(1)