Remove all "FileHasObject" edge reads and writes
[phabricator.git] / src / applications / auth / management / PhabricatorAuthManagementRevokeWorkflow.php
blob67ee746c2c8a885c9ac53d2ee280b4b934f1133a
1 <?php
3 final class PhabricatorAuthManagementRevokeWorkflow
4 extends PhabricatorAuthManagementWorkflow {
6 protected function didConstruct() {
7 $this
8 ->setName('revoke')
9 ->setExamples(
10 "**revoke** --list\n".
11 "**revoke** --type __type__ --from __@user__\n".
12 "**revoke** --everything --everywhere")
13 ->setSynopsis(
14 pht(
15 'Revoke credentials which may have been leaked or disclosed.'))
16 ->setArguments(
17 array(
18 array(
19 'name' => 'from',
20 'param' => 'object',
21 'help' => pht(
22 'Revoke credentials for the specified object. To revoke '.
23 'credentials for a user, use "@username".'),
25 array(
26 'name' => 'type',
27 'param' => 'type',
28 'help' => pht('Revoke credentials of the given type.'),
30 array(
31 'name' => 'list',
32 'help' => pht(
33 'List information about available credential revokers.'),
35 array(
36 'name' => 'everything',
37 'help' => pht('Revoke all credentials types.'),
39 array(
40 'name' => 'everywhere',
41 'help' => pht('Revoke from all credential owners.'),
43 array(
44 'name' => 'force',
45 'help' => pht('Revoke credentials without prompting.'),
47 ));
50 public function execute(PhutilArgumentParser $args) {
51 $viewer = $this->getViewer();
53 $all_types = PhabricatorAuthRevoker::getAllRevokers();
54 $is_force = $args->getArg('force');
56 // The "--list" flag is compatible with revoker selection flags like
57 // "--type" to filter the list, but not compatible with target selection
58 // flags like "--from".
59 $is_list = $args->getArg('list');
61 $type = $args->getArg('type');
62 $is_everything = $args->getArg('everything');
63 if ($type === null && !$is_everything) {
64 if ($is_list) {
65 // By default, "bin/revoke --list" implies "--everything".
66 $types = $all_types;
67 } else {
68 throw new PhutilArgumentUsageException(
69 pht(
70 'Specify the credential type to revoke with "--type" or specify '.
71 '"--everything". Use "--list" to list available credential '.
72 'types.'));
74 } else if (strlen($type) && $is_everything) {
75 throw new PhutilArgumentUsageException(
76 pht(
77 'Specify the credential type to revoke with "--type" or '.
78 '"--everything", but not both.'));
79 } else if ($is_everything) {
80 $types = $all_types;
81 } else {
82 if (empty($all_types[$type])) {
83 throw new PhutilArgumentUsageException(
84 pht(
85 'Credential type "%s" is not valid. Valid credential types '.
86 'are: %s.',
87 $type,
88 implode(', ', array_keys($all_types))));
90 $types = array($all_types[$type]);
93 $is_everywhere = $args->getArg('everywhere');
94 $from = $args->getArg('from');
96 if ($is_list) {
97 if ($from !== null || $is_everywhere) {
98 throw new PhutilArgumentUsageException(
99 pht(
100 'You can not "--list" and revoke credentials (with "--from" or '.
101 '"--everywhere") in the same operation.'));
105 if ($is_list) {
106 $last_key = last_key($types);
107 foreach ($types as $key => $type) {
108 echo tsprintf(
109 "**%s** (%s)\n\n",
110 $type->getRevokerKey(),
111 $type->getRevokerName());
113 id(new PhutilConsoleBlock())
114 ->addParagraph(tsprintf('%B', $type->getRevokerDescription()))
115 ->draw();
118 return 0;
121 $target = null;
122 if (!strlen($from) && !$is_everywhere) {
123 throw new PhutilArgumentUsageException(
124 pht(
125 'Specify the target to revoke credentials from with "--from" or '.
126 'specify "--everywhere".'));
127 } else if (strlen($from) && $is_everywhere) {
128 throw new PhutilArgumentUsageException(
129 pht(
130 'Specify the target to revoke credentials from with "--from" or '.
131 'specify "--everywhere", but not both.'));
132 } else if ($is_everywhere) {
133 // Just carry the flag through.
134 } else {
135 $target = id(new PhabricatorObjectQuery())
136 ->setViewer($viewer)
137 ->withNames(array($from))
138 ->executeOne();
139 if (!$target) {
140 throw new PhutilArgumentUsageException(
141 pht(
142 'Target "%s" is not a valid target to revoke credentials from. '.
143 'Usually, revoke from "@username".',
144 $from));
148 if ($is_everywhere && !$is_force) {
149 echo id(new PhutilConsoleBlock())
150 ->addParagraph(
151 pht(
152 'You are destroying an entire class of credentials. This may be '.
153 'very disruptive to users. You should normally do this only if '.
154 'you suspect there has been a widespread compromise which may '.
155 'have impacted everyone.'))
156 ->drawConsoleString();
158 $prompt = pht('Really destroy credentials everywhere?');
159 if (!phutil_console_confirm($prompt)) {
160 throw new PhutilArgumentUsageException(
161 pht('Aborted workflow.'));
165 foreach ($types as $type) {
166 $type->setViewer($viewer);
167 if ($is_everywhere) {
168 $count = $type->revokeAllCredentials();
169 } else {
170 $count = $type->revokeCredentialsFrom($target);
173 echo tsprintf(
174 "%s\n",
175 pht(
176 'Destroyed %s credential(s) of type "%s".',
177 new PhutilNumber($count),
178 $type->getRevokerKey()));
180 $guidance = $type->getRevokerNextSteps();
181 if ($guidance !== null) {
182 echo tsprintf(
183 "%s\n",
184 $guidance);
188 echo tsprintf(
189 "%s\n",
190 pht('Done.'));
192 return 0;