3 final class PhabricatorFilesManagementIntegrityWorkflow
4 extends PhabricatorFilesManagementWorkflow
{
6 protected function didConstruct() {
7 $arguments = $this->newIteratorArguments();
12 'DANGEROUS. Strip integrity hashes from files. This makes '.
13 'files vulnerable to corruption or tampering.'),
19 'Corrupt integrity hashes for given files. This is intended '.
26 'Compute and update integrity hashes for files which do not '.
31 'name' => 'overwrite',
33 'DANGEROUS. Recompute and update integrity hashes, overwriting '.
34 'invalid hashes. This may mark corrupt or dangerous files as '.
42 'Execute dangerous operations without prompting for '.
48 ->setName('integrity')
49 ->setSynopsis(pht('Verify or recalculate file integrity hashes.'))
50 ->setArguments($arguments);
53 public function execute(PhutilArgumentParser
$args) {
56 $is_strip = $args->getArg('strip');
61 $is_corrupt = $args->getArg('corrupt');
66 $is_compute = $args->getArg('compute');
71 $is_overwrite = $args->getArg('overwrite');
73 $modes[] = 'overwrite';
81 if (count($modes) > 1) {
82 throw new PhutilArgumentUsageException(
84 'You have selected multiple operation modes (%s). Choose a '.
85 'single mode to operate in.',
86 implode(', ', $modes)));
89 $is_force = $args->getArg('force');
94 'Stripping integrity hashes is dangerous and makes files '.
95 'vulnerable to corruption or tampering.');
100 'Corrupting integrity hashes will prevent files from being '.
101 'accessed. This mode is intended only for development and '.
107 'Overwriting integrity hashes is dangerous and may mark files '.
108 'which have been corrupted or tampered with as safe.');
112 $this->logWarn(pht('DANGEROUS'), $prompt);
114 if (!phutil_console_confirm(pht('Continue anyway?'))) {
115 throw new PhutilArgumentUsageException(pht('Aborted workflow.'));
120 $iterator = $this->buildIterator($args);
125 foreach ($iterator as $file) {
127 $display_name = $file->getMonogram();
129 $old_hash = $file->getIntegrityHash();
132 if ($old_hash === null) {
136 'File "%s" does not have an integrity hash to strip.',
140 ->setIntegrityHash(null)
146 'Stripped integrity hash for "%s".',
153 $need_hash = ($is_verify && $old_hash) ||
154 ($is_compute && ($old_hash === null)) ||
159 $new_hash = $file->newIntegrityHash();
160 } catch (Exception
$ex) {
166 'Unable to compute integrity hash for file "%s": %s',
176 // NOTE: When running in "corrupt" mode, we only corrupt the hash if
177 // we're able to compute a valid hash. Some files, like chunked files,
178 // do not support integrity hashing so corrupting them would create an
182 if ($new_hash === null) {
186 'Storage for file "%s" does not support integrity hashing.',
190 ->setIntegrityHash('<corrupted>')
196 'Corrupted integrity hash for file "%s".',
204 if ($old_hash === null) {
208 'File "%s" has no stored integrity hash.',
210 } else if ($new_hash === null) {
216 'Storage for file "%s" does not support integrity hashing, '.
217 'but the file has an integrity hash.',
219 } else if (phutil_hashes_are_identical($old_hash, $new_hash)) {
223 'File "%s" has a valid integrity hash.',
231 'File "%s" has an invalid integrity hash!',
239 if ($old_hash !== null) {
243 'File "%s" already has an integrity hash.',
245 } else if ($new_hash === null) {
249 'Storage for file "%s" does not support integrity hashing.',
253 ->setIntegrityHash($new_hash)
259 'Computed and stored integrity hash for file "%s".',
267 $same_hash = ($old_hash !== null) &&
268 ($new_hash !== null) &&
269 phutil_hashes_are_identical($old_hash, $new_hash);
271 if ($new_hash === null) {
275 'Storage for file "%s" does not support integrity hashing.',
277 } else if ($same_hash) {
281 'File "%s" already has the correct integrity hash.',
285 ->setIntegrityHash($new_hash)
291 'Overwrote integrity hash for file "%s".',
299 if ($failure_count) {
303 'Processed %s file(s), encountered %s error(s).',
304 new PhutilNumber($total_count),
305 new PhutilNumber($failure_count)));
310 'Processed %s file(s) with no errors.',
311 new PhutilNumber($total_count)));