-
Notifications
You must be signed in to change notification settings - Fork 0
/
cli.py
256 lines (209 loc) · 8.79 KB
/
cli.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
The entry point for the easy-vault command.
"""
from __future__ import absolute_import, print_function
import os
import sys
import getpass
import click
from ._common_options import add_options, help_option, quiet_option
from .._version import __version__ as cli_version
from .._keyring import Keyring, KeyringNotAvailable, KeyringException
from .._easy_vault import EasyVault, EasyVaultException
from .._password import get_password, set_password
@click.group()
@click.version_option(
message='%(prog)s, version %(version)s'.format(cli_version),
help=u'Show the version of this command.')
@add_options(help_option)
@click.pass_context
def cli(ctx):
"""
The easy-vault command is used to encrypt and decrypt vault files.
The passwords for the vault files are stored in the keyring service
of the local system.
"""
pass
# Command will be executed automatically
@cli.command('encrypt')
@click.argument('vaultfile', type=str, metavar='VAULTFILE', required=True)
@click.option('-p', '--set-password', is_flag=True, default=False,
help=u'Set a new password if the file needs to be encrypted. '
u'Mutually exclusive with --no-keyring')
@click.option('-n', '--no-keyring', is_flag=True, default=False,
help=u'Do not use the keyring service. '
u'Mutually exclusive with --set-password')
@add_options(quiet_option)
@add_options(help_option)
def cli_encrypt(vaultfile, **options):
"""
Encrypt a vault file, if not yet encrypted.
If the vault file is already encrypted, nothing is done.
If the vault file is currently decrypted, by default the keyring service is
contacted to see whether it has a password stored for this vault file.
If so, that password is used for encrypting the vault file.
Otherwise, a password is prompted for, and that password is used for
encrypting the vault file and is stored in the keyring service for future
use as the password for this vault file.
If the keyring service is chosen not to be used, the password is always
prompted for and the keyring service is not contacted at all.
If a new password is chosen to be set, that password is used for encrypting
the vault file and is stored in the keyring service for future use as the
password for this vault file, overwriting a possibly existing previous
password.
Note that these two choices are mutually exclusive.
"""
verbose = not options['quiet']
set_pass = options['set_password']
no_keyring = options['no_keyring']
if set_pass and no_keyring:
raise click.ClickException(
"The --set-password and --no-keyring options are mutually "
"exclusive")
check_exists(vaultfile)
if EasyVault(vaultfile).is_encrypted():
if verbose:
click.echo("Success! Vault file had already been encrypted")
return
if set_pass:
password = get_password(vaultfile, use_keyring=False,
verbose=verbose, echo=click.echo)
else:
password = get_password(vaultfile, use_keyring=not no_keyring,
verbose=verbose, echo=click.echo)
vault = EasyVault(vaultfile, password)
try:
vault.encrypt()
except EasyVaultException as exc:
raise click.ClickException(str(exc))
if verbose:
click.echo("Success! Vault file has just been encrypted")
set_password(vaultfile, password, use_keyring=not no_keyring,
verbose=verbose, echo=click.echo)
@cli.command('decrypt')
@click.argument('vaultfile', type=str, metavar='VAULTFILE', required=True)
@click.option('-p', '--set-password', is_flag=True, default=False,
help=u'Set a new password if the file needs to be decrypted. '
u'Mutually exclusive with --no-keyring')
@click.option('-n', '--no-keyring', is_flag=True, default=False,
help=u'Do not use the keyring service. '
u'Mutually exclusive with --set-password')
@add_options(help_option)
@add_options(quiet_option)
def cli_decrypt(vaultfile, **options):
"""
Decrypt a vault file, if encrypted.
If the vault file is already decrypted, nothing is done.
If the vault file is currently encrypted, by default the keyring service is
contacted to see whether it has a password stored for this vault file.
If so, that password is used for decrypting the vault file.
Otherwise, a password is prompted for, and that password is used for
decrypting the vault file and is stored in the keyring service for future
use as the password for this vault file.
If the keyring service is chosen not to be used, the password is always
prompted for and the keyring service is not contacted at all.
If a new password is chosen to be set, that password is used for decrypting
the vault file and is stored in the keyring service for future use as the
password for this vault file, overwriting a possibly existing previous
password.
Note that these two choices are mutually exclusive.
"""
verbose = not options['quiet']
set_pass = options['set_password']
no_keyring = options['no_keyring']
if set_pass and no_keyring:
raise click.ClickException(
"The --set-password and --no-keyring options are mutually "
"exclusive")
check_exists(vaultfile)
if not EasyVault(vaultfile).is_encrypted():
if verbose:
click.echo("Success! Vault file had already been decrypted")
return
if set_pass:
password = get_password(vaultfile, use_keyring=False,
verbose=verbose, echo=click.echo)
else:
password = get_password(vaultfile, use_keyring=not no_keyring,
verbose=verbose, echo=click.echo)
vault = EasyVault(vaultfile, password)
try:
vault.decrypt()
except EasyVaultException as exc:
raise click.ClickException(str(exc))
if verbose:
click.echo("Success! Vault file has just been decrypted")
set_password(vaultfile, password, use_keyring=not no_keyring,
verbose=verbose, echo=click.echo)
@cli.command('check-encrypted')
@click.argument('vaultfile', type=str, metavar='VAULTFILE', required=True)
@add_options(quiet_option)
@add_options(help_option)
def cli_check_encrypted(vaultfile, **options):
"""
Check whether the vault file is encrypted.
If encrypted, the command exits with 0.
If not encrypted, the command exits with 1.
"""
verbose = not options['quiet']
check_exists(vaultfile)
if not EasyVault(vaultfile).is_encrypted():
if verbose:
click.echo("Error: Vault file is not encrypted")
click.get_current_context().exit(1)
if verbose:
click.echo("Success! Vault file is encrypted")
@cli.command('check-keyring')
@add_options(quiet_option)
@add_options(help_option)
def cli_check_keyring(**options):
"""
Check whether the keyring service is available.
If available, the command exits with 0.
If not available, the command prints an error message with some information
about the reasons, and exits with 1.
"""
verbose = not options['quiet']
kr = Keyring()
try:
kr.check_available()
except KeyringNotAvailable as exc:
if verbose:
click.echo("Error: {}".format(exc))
click.get_current_context().exit(1)
if verbose:
click.echo("Success! Keyring service is available")
@cli.command('delete-password')
@click.argument('vaultfile', type=str, metavar='VAULTFILE', required=True)
@add_options(quiet_option)
@add_options(help_option)
def cli_delete_password(vaultfile, **options):
"""
Delete the password for a vault file in the keyring service.
"""
verbose = not options['quiet']
kr = Keyring()
try:
existed = kr.delete_password(vaultfile)
except KeyringException as exc:
raise click.ClickException(exc)
if verbose:
if existed:
click.echo("Success! Password in keyring service has been deleted")
else:
click.echo("Success! Password in keyring service does not exist")
def check_exists(vaultfile):
if not os.path.exists(vaultfile):
raise click.ClickException(
"Vault file does not exist: {fn}".format(fn=vaultfile))