97154419e7e3b9293cc1c936fcfe62f971521a72
[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 gnupg_setup (arguments):
74     gnupg_home = os.path.expanduser (arguments.gnupg_home)
75     gnupg_secring = os.path.join (gnupg_home, "secring.gpg")
76
77     if os.path.exists (gnupg_secring):
78         print ("GnuPG secret keyring already exists at {!r}."
79                .format (gnupg_secring))
80         return
81
82     print (filled ("""
83     No default GnuPG key available.  Please enter your information to
84     create a new key."""))
85
86     default_name = os.getenv ("FULLNAME")
87     name = read_input_string ("What is your name? ", default_name)
88
89     default_email = os.getenv ("EMAIL")
90     email = read_input_string ("What is your email address? ", default_email)
91
92     comment = read_input_string ("What is your comment phrase, if any (e.g. 'key for 2014')? ")
93
94     if not os.path.exists (gnupg_home):
95         ensure_directories (gnupg_home, 0o700)
96
97     with tempfile.NamedTemporaryFile () as tmp:
98         batch_key = dedented ("""
99         %ask-passphrase
100         Key-Type: DSA
101         Key-Length: 2048
102         Subkey-Type: ELG-E
103         Subkey-Length: 2048
104         Name-Real: {}
105         Name-Email: {}
106         Expire-Date: 0
107         """).format (name, email)
108
109         if comment != "":
110             batch_key += "\nName-Comment: {}\n".format (comment)
111
112         tmp.write (batch_key)
113         tmp.flush ()
114
115         batch_env = dict(os.environ)
116         del batch_env["DISPLAY"]
117
118         gnupg_process = subprocess.Popen (["gpg2", "--homedir", gnupg_home, "--batch", "--gen-key", tmp.name],
119                                         env = batch_env)
120         gnupg_process.wait ()
121
122         if gnupg_process.returncode != 0:
123             raise Exception ("Couldn't create GnuPG key.")
124
125
126 def ensure_directories (path, mode = 0o777):
127     try:
128         os.makedirs (path, mode)
129     except OSError as exception:
130         if exception.errno != errno.EEXIST:
131             raise
132
133
134 def openssh_setup (arguments):
135     openssh_home = os.path.expanduser (arguments.openssh_home)
136     openssh_config = os.path.join (openssh_home, "config")
137
138     if not os.path.exists (openssh_config):
139         ensure_directories (openssh_home, 0o700)
140
141         with open (openssh_config, "w") as config:
142             config.write (dedented ("""
143             ForwardAgent yes
144             ForwardX11 yes
145             """))
146
147     openssh_key = os.path.join (openssh_home, "id_rsa")
148
149     if os.path.exists (openssh_key):
150         print("OpenSSH key already exists at {!r}.".format (openssh_key))
151         return
152
153     print (filled ("No OpenSSH key available.  Generating new key."))
154
155     openssh_process = subprocess.Popen (["ssh-keygen", "-f", openssh_key])
156     openssh_process.wait ()
157
158     if openssh_process.returncode != 0:
159         raise Exception ("Couldn't create OpenSSH key.")
160
161
162 def main ():
163     arguments = parse_arguments ()
164
165     if arguments.gnupg:
166         gnupg_setup (arguments)
167
168     if arguments.openssh:
169         openssh_setup (arguments)
170
171
172 if __name__ == "__main__":
173     main ()