chiark / gitweb /
Eliminate the need for password files
authorTorsten Grote <t@grobox.de>
Tue, 11 Apr 2017 19:34:49 +0000 (16:34 -0300)
committerTorsten Grote <t@grobox.de>
Tue, 11 Apr 2017 19:34:49 +0000 (16:34 -0300)
The passwords are now passed as private environment variables to the
processes that need them.

fdroidserver/common.py
fdroidserver/index.py
fdroidserver/publish.py
fdroidserver/signindex.py

index 0c12c3f9b9875d9228cc54919964dcabdcb1da45..02d8acebda431e244028e6c344629ccc336cb3ba 100644 (file)
@@ -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
index e029fc507f03b6b1d8d1f88ff86564c308bc6260..44b1a1b9b4140b5db6d7813a1523328a2a240bd6 100644 (file)
@@ -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':
index bf4aa2dc88f9e860fdef19b3e9af3acf4208857b..622de59c4c14a9c49f794f3adc1d45f110f5fb43 100644 (file)
@@ -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")
 
index 4f0ac6785047f3490a35f59a84c562f6e6de98d1..58c7e91fd940bd5ac64604c989f4308e5ccdd621 100644 (file)
@@ -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)