3 final class PhabricatorAuthManagementRevokeWorkflow
4 extends PhabricatorAuthManagementWorkflow
{
6 protected function didConstruct() {
10 "**revoke** --list\n".
11 "**revoke** --type __type__ --from __@user__\n".
12 "**revoke** --everything --everywhere")
15 'Revoke credentials which may have been leaked or disclosed.'))
22 'Revoke credentials for the specified object. To revoke '.
23 'credentials for a user, use "@username".'),
28 'help' => pht('Revoke credentials of the given type.'),
33 'List information about available credential revokers.'),
36 'name' => 'everything',
37 'help' => pht('Revoke all credentials types.'),
40 'name' => 'everywhere',
41 'help' => pht('Revoke from all credential owners.'),
45 'help' => pht('Revoke credentials without prompting.'),
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) {
65 // By default, "bin/revoke --list" implies "--everything".
68 throw new PhutilArgumentUsageException(
70 'Specify the credential type to revoke with "--type" or specify '.
71 '"--everything". Use "--list" to list available credential '.
74 } else if (strlen($type) && $is_everything) {
75 throw new PhutilArgumentUsageException(
77 'Specify the credential type to revoke with "--type" or '.
78 '"--everything", but not both.'));
79 } else if ($is_everything) {
82 if (empty($all_types[$type])) {
83 throw new PhutilArgumentUsageException(
85 'Credential type "%s" is not valid. Valid credential types '.
88 implode(', ', array_keys($all_types))));
90 $types = array($all_types[$type]);
93 $is_everywhere = $args->getArg('everywhere');
94 $from = $args->getArg('from');
97 if ($from !== null ||
$is_everywhere) {
98 throw new PhutilArgumentUsageException(
100 'You can not "--list" and revoke credentials (with "--from" or '.
101 '"--everywhere") in the same operation.'));
106 $last_key = last_key($types);
107 foreach ($types as $key => $type) {
110 $type->getRevokerKey(),
111 $type->getRevokerName());
113 id(new PhutilConsoleBlock())
114 ->addParagraph(tsprintf('%B', $type->getRevokerDescription()))
122 if (!strlen($from) && !$is_everywhere) {
123 throw new PhutilArgumentUsageException(
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(
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.
135 $target = id(new PhabricatorObjectQuery())
137 ->withNames(array($from))
140 throw new PhutilArgumentUsageException(
142 'Target "%s" is not a valid target to revoke credentials from. '.
143 'Usually, revoke from "@username".',
148 if ($is_everywhere && !$is_force) {
149 echo id(new PhutilConsoleBlock())
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();
170 $count = $type->revokeCredentialsFrom($target);
176 'Destroyed %s credential(s) of type "%s".',
177 new PhutilNumber($count),
178 $type->getRevokerKey()));
180 $guidance = $type->getRevokerNextSteps();
181 if ($guidance !== null) {