@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at recaptime-dev/main 317 lines 8.3 kB view raw
1<?php 2 3final class PhabricatorFilesManagementIntegrityWorkflow 4 extends PhabricatorFilesManagementWorkflow { 5 6 protected function didConstruct() { 7 $arguments = $this->newIteratorArguments(); 8 9 $arguments[] = array( 10 'name' => 'strip', 11 'help' => pht( 12 'DANGEROUS. Strip integrity hashes from files. This makes '. 13 'files vulnerable to corruption or tampering.'), 14 ); 15 16 $arguments[] = array( 17 'name' => 'corrupt', 18 'help' => pht( 19 'Corrupt integrity hashes for given files. This is intended '. 20 'for debugging.'), 21 ); 22 23 $arguments[] = array( 24 'name' => 'compute', 25 'help' => pht( 26 'Compute and update integrity hashes for files which do not '. 27 'yet have them.'), 28 ); 29 30 $arguments[] = array( 31 'name' => 'overwrite', 32 'help' => pht( 33 'DANGEROUS. Recompute and update integrity hashes, overwriting '. 34 'invalid hashes. This may mark corrupt or dangerous files as '. 35 'valid.'), 36 ); 37 38 $arguments[] = array( 39 'name' => 'force', 40 'short' => 'f', 41 'help' => pht( 42 'Execute dangerous operations without prompting for '. 43 'confirmation.'), 44 ); 45 46 47 $this 48 ->setName('integrity') 49 ->setSynopsis(pht('Verify or recalculate file integrity hashes.')) 50 ->setArguments($arguments); 51 } 52 53 public function execute(PhutilArgumentParser $args) { 54 $modes = array(); 55 56 $is_strip = $args->getArg('strip'); 57 if ($is_strip) { 58 $modes[] = 'strip'; 59 } 60 61 $is_corrupt = $args->getArg('corrupt'); 62 if ($is_corrupt) { 63 $modes[] = 'corrupt'; 64 } 65 66 $is_compute = $args->getArg('compute'); 67 if ($is_compute) { 68 $modes[] = 'compute'; 69 } 70 71 $is_overwrite = $args->getArg('overwrite'); 72 if ($is_overwrite) { 73 $modes[] = 'overwrite'; 74 } 75 76 $is_verify = !$modes; 77 if ($is_verify) { 78 $modes[] = 'verify'; 79 } 80 81 if (count($modes) > 1) { 82 throw new PhutilArgumentUsageException( 83 pht( 84 'You have selected multiple operation modes (%s). Choose a '. 85 'single mode to operate in.', 86 implode(', ', $modes))); 87 } 88 89 $is_force = $args->getArg('force'); 90 if (!$is_force) { 91 $prompt = null; 92 if ($is_strip) { 93 $prompt = pht( 94 'Stripping integrity hashes is dangerous and makes files '. 95 'vulnerable to corruption or tampering.'); 96 } 97 98 if ($is_corrupt) { 99 $prompt = pht( 100 'Corrupting integrity hashes will prevent files from being '. 101 'accessed. This mode is intended only for development and '. 102 'debugging.'); 103 } 104 105 if ($is_overwrite) { 106 $prompt = pht( 107 'Overwriting integrity hashes is dangerous and may mark files '. 108 'which have been corrupted or tampered with as safe.'); 109 } 110 111 if ($prompt) { 112 $this->logWarn(pht('DANGEROUS'), $prompt); 113 114 if (!phutil_console_confirm(pht('Continue anyway?'))) { 115 throw new PhutilArgumentUsageException(pht('Aborted workflow.')); 116 } 117 } 118 } 119 120 $iterator = $this->buildIterator($args); 121 122 $failure_count = 0; 123 $total_count = 0; 124 125 foreach ($iterator as $file) { 126 $total_count++; 127 $display_name = $file->getMonogram(); 128 129 $old_hash = $file->getIntegrityHash(); 130 131 if ($is_strip) { 132 if ($old_hash === null) { 133 $this->logInfo( 134 pht('SKIPPED'), 135 pht( 136 'File "%s" does not have an integrity hash to strip.', 137 $display_name)); 138 } else { 139 $file 140 ->setIntegrityHash(null) 141 ->save(); 142 143 $this->logWarn( 144 pht('STRIPPED'), 145 pht( 146 'Stripped integrity hash for "%s".', 147 $display_name)); 148 } 149 150 continue; 151 } 152 153 $need_hash = ($is_verify && $old_hash) || 154 ($is_compute && ($old_hash === null)) || 155 ($is_corrupt) || 156 ($is_overwrite); 157 if ($need_hash) { 158 try { 159 $new_hash = $file->newIntegrityHash(); 160 } catch (Exception $ex) { 161 $failure_count++; 162 163 $this->logFail( 164 pht('ERROR'), 165 pht( 166 'Unable to compute integrity hash for file "%s": %s', 167 $display_name, 168 $ex->getMessage())); 169 170 continue; 171 } 172 } else { 173 $new_hash = null; 174 } 175 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 179 // unusual state. 180 181 if ($is_corrupt) { 182 if ($new_hash === null) { 183 $this->logInfo( 184 pht('IGNORED'), 185 pht( 186 'Storage for file "%s" does not support integrity hashing.', 187 $display_name)); 188 } else { 189 $file 190 ->setIntegrityHash('<corrupted>') 191 ->save(); 192 193 $this->logWarn( 194 pht('CORRUPTED'), 195 pht( 196 'Corrupted integrity hash for file "%s".', 197 $display_name)); 198 } 199 200 continue; 201 } 202 203 if ($is_verify) { 204 if ($old_hash === null) { 205 $this->logInfo( 206 pht('NONE'), 207 pht( 208 'File "%s" has no stored integrity hash.', 209 $display_name)); 210 } else if ($new_hash === null) { 211 $failure_count++; 212 213 $this->logWarn( 214 pht('UNEXPECTED'), 215 pht( 216 'Storage for file "%s" does not support integrity hashing, '. 217 'but the file has an integrity hash.', 218 $display_name)); 219 } else if (phutil_hashes_are_identical($old_hash, $new_hash)) { 220 $this->logOkay( 221 pht('VALID'), 222 pht( 223 'File "%s" has a valid integrity hash.', 224 $display_name)); 225 } else { 226 $failure_count++; 227 228 $this->logFail( 229 pht('MISMATCH'), 230 pht( 231 'File "%s" has an invalid integrity hash!', 232 $display_name)); 233 } 234 235 continue; 236 } 237 238 if ($is_compute) { 239 if ($old_hash !== null) { 240 $this->logInfo( 241 pht('SKIP'), 242 pht( 243 'File "%s" already has an integrity hash.', 244 $display_name)); 245 } else if ($new_hash === null) { 246 $this->logInfo( 247 pht('IGNORED'), 248 pht( 249 'Storage for file "%s" does not support integrity hashing.', 250 $display_name)); 251 } else { 252 $file 253 ->setIntegrityHash($new_hash) 254 ->save(); 255 256 $this->logOkay( 257 pht('COMPUTE'), 258 pht( 259 'Computed and stored integrity hash for file "%s".', 260 $display_name)); 261 } 262 263 continue; 264 } 265 266 if ($is_overwrite) { 267 $same_hash = ($old_hash !== null) && 268 ($new_hash !== null) && 269 phutil_hashes_are_identical($old_hash, $new_hash); 270 271 if ($new_hash === null) { 272 $this->logInfo( 273 pht('IGNORED'), 274 pht( 275 'Storage for file "%s" does not support integrity hashing.', 276 $display_name)); 277 } else if ($same_hash) { 278 $this->logInfo( 279 pht('UNCHANGED'), 280 pht( 281 'File "%s" already has the correct integrity hash.', 282 $display_name)); 283 } else { 284 $file 285 ->setIntegrityHash($new_hash) 286 ->save(); 287 288 $this->logOkay( 289 pht('OVERWRITE'), 290 pht( 291 'Overwrote integrity hash for file "%s".', 292 $display_name)); 293 } 294 295 continue; 296 } 297 } 298 299 if ($failure_count) { 300 $this->logFail( 301 pht('FAIL'), 302 pht( 303 'Processed %s file(s), encountered %s error(s).', 304 new PhutilNumber($total_count), 305 new PhutilNumber($failure_count))); 306 } else { 307 $this->logOkay( 308 pht('DONE'), 309 pht( 310 'Processed %s file(s) with no errors.', 311 new PhutilNumber($total_count))); 312 } 313 314 return 0; 315 } 316 317}