Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Encryption often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Encryption, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 44 | class Encryption implements IEncryptionModule { |
||
| 45 | |||
| 46 | const ID = 'OC_DEFAULT_MODULE'; |
||
| 47 | const DISPLAY_NAME = 'Default encryption module'; |
||
| 48 | |||
| 49 | /** |
||
| 50 | * @var Crypt |
||
| 51 | */ |
||
| 52 | private $crypt; |
||
| 53 | |||
| 54 | /** @var string */ |
||
| 55 | private $cipher; |
||
| 56 | |||
| 57 | /** @var string */ |
||
| 58 | private $path; |
||
| 59 | |||
| 60 | /** @var string */ |
||
| 61 | private $user; |
||
| 62 | |||
| 63 | /** @var string */ |
||
| 64 | private $fileKey; |
||
| 65 | |||
| 66 | /** @var string */ |
||
| 67 | private $writeCache; |
||
| 68 | |||
| 69 | /** @var KeyManager */ |
||
| 70 | private $keyManager; |
||
| 71 | |||
| 72 | /** @var array */ |
||
| 73 | private $accessList; |
||
| 74 | |||
| 75 | /** @var boolean */ |
||
| 76 | private $isWriteOperation; |
||
| 77 | |||
| 78 | /** @var Util */ |
||
| 79 | private $util; |
||
| 80 | |||
| 81 | /** @var Session */ |
||
| 82 | private $session; |
||
| 83 | |||
| 84 | /** @var ILogger */ |
||
| 85 | private $logger; |
||
| 86 | |||
| 87 | /** @var IL10N */ |
||
| 88 | private $l; |
||
| 89 | |||
| 90 | /** @var EncryptAll */ |
||
| 91 | private $encryptAll; |
||
| 92 | |||
| 93 | /** @var bool */ |
||
| 94 | private $useMasterPassword; |
||
| 95 | |||
| 96 | /** @var DecryptAll */ |
||
| 97 | private $decryptAll; |
||
| 98 | |||
| 99 | /** @var int unencrypted block size if block contains signature */ |
||
| 100 | private $unencryptedBlockSizeSigned = 6072; |
||
| 101 | |||
| 102 | /** @var int unencrypted block size */ |
||
| 103 | private $unencryptedBlockSize = 6126; |
||
| 104 | |||
| 105 | /** @var int Current version of the file */ |
||
| 106 | private $version = 0; |
||
| 107 | |||
| 108 | /** @var array remember encryption signature version */ |
||
| 109 | private static $rememberVersion = []; |
||
| 110 | |||
| 111 | |||
| 112 | /** |
||
| 113 | * |
||
| 114 | * @param Crypt $crypt |
||
| 115 | * @param KeyManager $keyManager |
||
| 116 | * @param Util $util |
||
| 117 | * @param Session $session |
||
| 118 | * @param EncryptAll $encryptAll |
||
| 119 | * @param DecryptAll $decryptAll |
||
| 120 | * @param ILogger $logger |
||
| 121 | * @param IL10N $il10n |
||
| 122 | */ |
||
| 123 | View Code Duplication | public function __construct(Crypt $crypt, |
|
| 141 | |||
| 142 | /** |
||
| 143 | * @return string defining the technical unique id |
||
| 144 | */ |
||
| 145 | public function getId() { |
||
| 148 | |||
| 149 | /** |
||
| 150 | * In comparison to getKey() this function returns a human readable (maybe translated) name |
||
| 151 | * |
||
| 152 | * @return string |
||
| 153 | */ |
||
| 154 | public function getDisplayName() { |
||
| 157 | |||
| 158 | /** |
||
| 159 | * start receiving chunks from a file. This is the place where you can |
||
| 160 | * perform some initial step before starting encrypting/decrypting the |
||
| 161 | * chunks |
||
| 162 | * |
||
| 163 | * @param string $path to the file |
||
| 164 | * @param string $user who read/write the file |
||
| 165 | * @param string $mode php stream open mode |
||
| 166 | * @param array $header contains the header data read from the file |
||
| 167 | * @param array $accessList who has access to the file contains the key 'users' and 'public' |
||
| 168 | * |
||
| 169 | * @return array $header contain data as key-value pairs which should be |
||
| 170 | * written to the header, in case of a write operation |
||
| 171 | * or if no additional data is needed return a empty array |
||
| 172 | */ |
||
| 173 | public function begin($path, $user, $mode, array $header, array $accessList) { |
||
| 234 | |||
| 235 | /** |
||
| 236 | * last chunk received. This is the place where you can perform some final |
||
| 237 | * operation and return some remaining data if something is left in your |
||
| 238 | * buffer. |
||
| 239 | * |
||
| 240 | * @param string $path to the file |
||
| 241 | * @param int $position |
||
| 242 | * @return string remained data which should be written to the file in case |
||
| 243 | * of a write operation |
||
| 244 | * @throws PublicKeyMissingException |
||
| 245 | * @throws \Exception |
||
| 246 | * @throws \OCA\Encryption\Exceptions\MultiKeyEncryptException |
||
| 247 | */ |
||
| 248 | public function end($path, $position = 0) { |
||
| 289 | |||
| 290 | /** |
||
| 291 | * encrypt data |
||
| 292 | * |
||
| 293 | * @param string $data you want to encrypt |
||
| 294 | * @param int $position |
||
| 295 | * @return string encrypted data |
||
| 296 | */ |
||
| 297 | public function encrypt($data, $position = 0) { |
||
| 354 | |||
| 355 | /** |
||
| 356 | * decrypt data |
||
| 357 | * |
||
| 358 | * @param string $data you want to decrypt |
||
| 359 | * @param int $position |
||
| 360 | * @return string decrypted data |
||
| 361 | * @throws DecryptionFailedException |
||
| 362 | */ |
||
| 363 | public function decrypt($data, $position = 0) { |
||
| 374 | |||
| 375 | /** |
||
| 376 | * update encrypted file, e.g. give additional users access to the file |
||
| 377 | * |
||
| 378 | * @param string $path path to the file which should be updated |
||
| 379 | * @param string $uid of the user who performs the operation |
||
| 380 | * @param array $accessList who has access to the file contains the key 'users' and 'public' |
||
| 381 | * @return boolean |
||
| 382 | */ |
||
| 383 | public function update($path, $uid, array $accessList) { |
||
| 427 | |||
| 428 | /** |
||
| 429 | * should the file be encrypted or not |
||
| 430 | * |
||
| 431 | * @param string $path |
||
| 432 | * @return boolean |
||
| 433 | */ |
||
| 434 | public function shouldEncrypt($path) { |
||
| 458 | |||
| 459 | /** |
||
| 460 | * get size of the unencrypted payload per block. |
||
| 461 | * ownCloud read/write files with a block size of 8192 byte |
||
| 462 | * |
||
| 463 | * @param bool $signed |
||
| 464 | * @return int |
||
| 465 | */ |
||
| 466 | public function getUnencryptedBlockSize($signed = false) { |
||
| 473 | |||
| 474 | /** |
||
| 475 | * check if the encryption module is able to read the file, |
||
| 476 | * e.g. if all encryption keys exists |
||
| 477 | * |
||
| 478 | * @param string $path |
||
| 479 | * @param string $uid user for whom we want to check if he can read the file |
||
| 480 | * @return bool |
||
| 481 | * @throws DecryptionFailedException |
||
| 482 | */ |
||
| 483 | public function isReadable($path, $uid) { |
||
| 503 | |||
| 504 | /** |
||
| 505 | * Initial encryption of all files |
||
| 506 | * |
||
| 507 | * @param InputInterface $input |
||
| 508 | * @param OutputInterface $output write some status information to the terminal during encryption |
||
| 509 | */ |
||
| 510 | public function encryptAll(InputInterface $input, OutputInterface $output) { |
||
| 513 | |||
| 514 | /** |
||
| 515 | * prepare module to perform decrypt all operation |
||
| 516 | * |
||
| 517 | * @param InputInterface $input |
||
| 518 | * @param OutputInterface $output |
||
| 519 | * @param string $user |
||
| 520 | * @return bool |
||
| 521 | */ |
||
| 522 | public function prepareDecryptAll(InputInterface $input, OutputInterface $output, $user = '') { |
||
| 525 | |||
| 526 | |||
| 527 | /** |
||
| 528 | * @param string $path |
||
| 529 | * @return string |
||
| 530 | */ |
||
| 531 | protected function getPathToRealFile($path) { |
||
| 542 | |||
| 543 | /** |
||
| 544 | * remove .part file extension and the ocTransferId from the file to get the |
||
| 545 | * original file name |
||
| 546 | * |
||
| 547 | * @param string $path |
||
| 548 | * @return string |
||
| 549 | */ |
||
| 550 | protected function stripPartFileExtension($path) { |
||
| 558 | |||
| 559 | /** |
||
| 560 | * Check if the module is ready to be used by that specific user. |
||
| 561 | * In case a module is not ready - because e.g. key pairs have not been generated |
||
| 562 | * upon login this method can return false before any operation starts and might |
||
| 563 | * cause issues during operations. |
||
| 564 | * |
||
| 565 | * @param string $user |
||
| 566 | * @return boolean |
||
| 567 | * @since 9.1.0 |
||
| 568 | */ |
||
| 569 | public function isReadyForUser($user) { |
||
| 572 | } |
||
| 573 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.