Commit | Line | Data |
---|---|---|
a2916c06 MW |
1 | ### -*-python-*- |
2 | ### | |
3 | ### User commands | |
4 | ### | |
5 | ### (c) 2013 Mark Wooding | |
6 | ### | |
7 | ||
8 | ###----- Licensing notice --------------------------------------------------- | |
9 | ### | |
10 | ### This file is part of Chopwood: a password-changing service. | |
11 | ### | |
12 | ### Chopwood is free software; you can redistribute it and/or modify | |
13 | ### it under the terms of the GNU Affero General Public License as | |
14 | ### published by the Free Software Foundation; either version 3 of the | |
15 | ### License, or (at your option) any later version. | |
16 | ### | |
17 | ### Chopwood is distributed in the hope that it will be useful, | |
18 | ### but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | ### GNU Affero General Public License for more details. | |
21 | ### | |
22 | ### You should have received a copy of the GNU Affero General Public | |
23 | ### License along with Chopwood; if not, see | |
24 | ### <http://www.gnu.org/licenses/>. | |
25 | ||
26 | from __future__ import with_statement | |
27 | ||
28 | import getpass as GP | |
29 | import sys as SYS | |
30 | ||
31 | import cmdutil as CU | |
32 | import dbmaint as D | |
33 | import operation as OP | |
34 | from output import PRINT | |
35 | import service as S | |
36 | import subcommand as SC | |
37 | import util as U | |
38 | ||
39 | OMSG = [None, | |
40 | "Partial failure", | |
41 | "Operation failed", | |
42 | "No services selected"] | |
43 | ||
44 | def operate(op, accts, *args, **kw): | |
45 | """ | |
46 | Perform a request as indicated by the arguments (see `operation.operate' | |
47 | for the full details), and report the results. | |
48 | """ | |
49 | ||
50 | ## Collect the results. | |
51 | o, ii, rq, ops = OP.operate(op, accts, *args, **kw) | |
52 | ||
53 | ## Report any additional information collected. | |
54 | if o.nwin and ii: | |
55 | CU.format_list(ii, | |
56 | [CU.column('RESULT', "~={0.desc}A"), | |
57 | CU.column('VALUE', "~={0.value}A")]) | |
58 | PRINT() | |
59 | ||
60 | ## Report the outcomes of the indvidual operations. | |
61 | if ops: | |
62 | CU.format_list(ops, | |
63 | [CU.column('SERVICE', | |
64 | "~={0.svc.friendly}A"), | |
65 | CU.column('RESULT', "~={0.error}:[" | |
66 | "OK~={0.result}@[ ~A~]~;" | |
67 | "FAILED: ~={0.error.msg}A~]")]) | |
68 | ||
69 | ## If it failed, report an appropriate error. | |
70 | if o.rc: | |
71 | if o.nlose: PRINT() | |
72 | raise U.ExpectedError, (400, OMSG[o.rc]) | |
73 | ||
74 | @SC.subcommand( | |
75 | 'set', ['userv'], | |
76 | """Sets the password for the SERVICES to a given string. If standard input | |
77 | is a terminal, read the password interactively, with prompts, disabling echo, | |
78 | and asking for confirmation to catch typos. Otherwise, just read one line | |
79 | and use the result as the password.""", | |
80 | rparam = SC.Arg('services')) | |
81 | def cmd_set_userv(services): | |
82 | accts = CU.resolve_accounts(CU.USER, services) | |
83 | if not SYS.stdin.isatty(): | |
84 | new = U.readline('new password') | |
85 | else: | |
86 | first = GP.getpass('Enter new password: ') | |
87 | second = GP.getpass('Confirm new password: ') | |
88 | if first != second: raise U.ExpectedError, (400, "Passwords don't match") | |
89 | new = first | |
90 | operate('set', accts, new) | |
91 | ||
92 | @SC.subcommand( | |
93 | 'reset', ['userv'], | |
94 | """Resets the password for the SERVICES.""", | |
95 | rparam = SC.Arg('services')) | |
96 | def cmd_reset_userv(services): | |
97 | accts = CU.resolve_accounts(CU.USER, services) | |
98 | operate('reset', accts) | |
99 | ||
100 | @SC.subcommand( | |
101 | 'clear', ['userv'], | |
102 | """Clears the password for the SERVICES, preventing access. This doesn't | |
103 | work for all services, depending on how passwords are represented.""", | |
104 | rparam = SC.Arg('services')) | |
105 | def cmd_clear_userv(services): | |
106 | accts = CU.resolve_accounts(CU.USER, services) | |
107 | operate('clear', accts) | |
108 | ||
109 | @SC.subcommand('list', ['userv'], 'List available accounts') | |
110 | def cmd_list_userv(): | |
111 | CU.format_list(CU.list_accounts(CU.USER), | |
112 | [CU.column('NAME', "~={0.service}A"), | |
113 | CU.column('DESCRIPTION', "~={0.friendly}A"), | |
114 | CU.column('LOGIN', "~={0.alias}:[---~;~={0.alias}A~]")]) | |
115 | ||
116 | ###----- That's all, folks -------------------------------------------------- |