Log directory creation.
[crypto-install.git] / crypto-install.py
1 #!/usr/bin/env python
2 # -*- mode: python; coding: utf-8-unix; -*-
3
4
5 import argparse, errno, os, readline, subprocess, sys, tempfile, textwrap
6
7
8 if sys.version_info[0] == 2:
9     def input_string (prompt=""):
10         return raw_input (prompt)
11 elif sys.version_info[0] > 2:
12     def input_string (prompt=""):
13         return input (prompt)
14 else:
15     raise Exception ("Unsupported Python version {}".format (sys.version_info))
16
17
18 def dedented (text):
19     return textwrap.dedent (text).strip ()
20
21
22 def filled (text):
23     return textwrap.fill (dedented (text), width = 72)
24
25
26 def read_input_string (prompt="", default=""):
27     if default != "":
28         readline.set_startup_hook (lambda: readline.insert_text (default))
29
30     try:
31         return input_string(prompt)
32     finally:
33         readline.set_startup_hook()
34
35
36 def parse_arguments ():
37     parser = argparse.ArgumentParser ()
38     parser.add_argument (
39         "-v", "--version",
40         dest = "version",
41         action = "version",
42         version = "crypto-install.py version GIT-TAG (GIT-COMMIT/GIT-BRANCH)",
43         help = "Display version.")
44     gnupg_group = parser.add_argument_group ("GnuPG",
45         "Options related to the GnuPG setup.")
46     gnupg_group.add_argument (
47         "--no-gpg",
48         dest = "gnupg",
49         action = "store_false",
50         help = "Disable GnuPG setup.")
51     gnupg_group.add_argument (
52         "--gpg-home",
53         dest = "gnupg_home",
54         default = "~/.gnupg",
55         metavar = "PATH",
56         help = "Default directory for GnuPG files.")
57     openssh_group = parser.add_argument_group ("OpenSSH",
58         "Options related to the OpenSSH setup.")
59     openssh_group.add_argument (
60         "--no-ssh",
61         dest = "openssh",
62         action = "store_false",
63         help = "Disable OpenSSH setup.")
64     openssh_group.add_argument (
65         "--ssh-home",
66         dest = "openssh_home",
67         default = "~/.ssh",
68         metavar = "PATH",
69         help = "Default directory for OpenSSH files.")
70     return parser.parse_args ()
71
72
73 def ensure_directories (path, mode = 0o777):
74     try:
75         os.makedirs (path, mode)
76     except OSError as exception:
77         if exception.errno != errno.EEXIST:
78             raise
79
80
81 def gnupg_setup (arguments):
82     gnupg_home = os.path.expanduser (arguments.gnupg_home)
83     gnupg_secring = os.path.join (gnupg_home, "secring.gpg")
84
85     if os.path.exists (gnupg_secring):
86         print ("GnuPG secret keyring already exists at {!r}."
87                .format (gnupg_secring))
88         return
89
90     print (filled ("""
91     No default GnuPG key available.  Please enter your information to
92     create a new key."""))
93
94     default_name = os.getenv ("FULLNAME")
95     name = read_input_string ("What is your name? ", default_name)
96
97     default_email = os.getenv ("EMAIL")
98     email = read_input_string ("What is your email address? ", default_email)
99
100     comment = read_input_string ("What is your comment phrase, if any (e.g. 'key for 2014')? ")
101
102     if not os.path.exists (gnupg_home):
103         print ("Creating GnuPG directory at {!r}.".format (gnupg_home))
104         ensure_directories (gnupg_home, 0o700)
105
106     with tempfile.NamedTemporaryFile () as tmp:
107         batch_key = dedented ("""
108         %ask-passphrase
109         Key-Type: DSA
110         Key-Length: 2048
111         Subkey-Type: ELG-E
112         Subkey-Length: 2048
113         Name-Real: {}
114         Name-Email: {}
115         Expire-Date: 0
116         """).format (name, email)
117
118         if comment != "":
119             batch_key += "\nName-Comment: {}\n".format (comment)
120
121         tmp.write (batch_key)
122         tmp.flush ()
123
124         batch_env = dict(os.environ)
125         del batch_env["DISPLAY"]
126
127         gnupg_process = subprocess.Popen (["gpg2", "--homedir", gnupg_home, "--batch", "--gen-key", tmp.name],
128                                         env = batch_env)
129         gnupg_process.wait ()
130
131         if gnupg_process.returncode != 0:
132             raise Exception ("Couldn't create GnuPG key.")
133
134
135 def openssh_setup (arguments):
136     openssh_home = os.path.expanduser (arguments.openssh_home)
137     openssh_config = os.path.join (openssh_home, "config")
138
139     if not os.path.exists (openssh_config):
140         print ("Creating OpenSSH directory at {!r}.".format (openssh_home))
141         ensure_directories (openssh_home, 0o700)
142
143         print ("Creating OpenSSH configuration at {!r}.".format (openssh_config))
144         with open (openssh_config, "w") as config:
145             config.write (dedented ("""
146             ForwardAgent yes
147             ForwardX11 yes
148             """))
149
150     openssh_key = os.path.join (openssh_home, "id_rsa")
151
152     if os.path.exists (openssh_key):
153         print ("OpenSSH key already exists at {!r}.".format (openssh_key))
154         return
155
156     print (filled ("No OpenSSH key available.  Generating new key."))
157
158     openssh_process = subprocess.Popen (["ssh-keygen", "-f", openssh_key])
159     openssh_process.wait ()
160
161     if openssh_process.returncode != 0:
162         raise Exception ("Couldn't create OpenSSH key.")
163
164
165 def main ():
166     arguments = parse_arguments ()
167
168     if arguments.gnupg:
169         gnupg_setup (arguments)
170
171     if arguments.openssh:
172         openssh_setup (arguments)
173
174
175 if __name__ == "__main__":
176     main ()