EncryptionTest.php 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  1. <?php
  2. namespace Test\Files\Storage\Wrapper;
  3. use OC\Encryption\Exceptions\ModuleDoesNotExistsException;
  4. use OC\Encryption\Update;
  5. use OC\Encryption\Util;
  6. use OC\Files\Storage\Temporary;
  7. use OC\Files\Storage\Wrapper\Encryption;
  8. use OC\Files\View;
  9. use OC\Log;
  10. use OC\Memcache\ArrayCache;
  11. use OC\User\Manager;
  12. use OCP\Encryption\IEncryptionModule;
  13. use OCP\Encryption\IFile;
  14. use OCP\Encryption\Keys\IStorage;
  15. use OCP\Files\Cache\ICache;
  16. use OCP\Files\Mount\IMountPoint;
  17. use OCP\IConfig;
  18. use OCP\ILogger;
  19. use Test\Files\Storage\Storage;
  20. class EncryptionTest extends Storage {
  21. /**
  22. * block size will always be 8192 for a PHP stream
  23. * @see https://bugs.php.net/bug.php?id=21641
  24. * @var integer
  25. */
  26. protected $headerSize = 8192;
  27. /**
  28. * @var Temporary
  29. */
  30. private $sourceStorage;
  31. /**
  32. * @var \OC\Files\Storage\Wrapper\Encryption | \PHPUnit_Framework_MockObject_MockObject
  33. */
  34. protected $instance;
  35. /**
  36. * @var \OC\Encryption\Keys\Storage | \PHPUnit_Framework_MockObject_MockObject
  37. */
  38. private $keyStore;
  39. /**
  40. * @var \OC\Encryption\Util | \PHPUnit_Framework_MockObject_MockObject
  41. */
  42. private $util;
  43. /**
  44. * @var \OC\Encryption\Manager | \PHPUnit_Framework_MockObject_MockObject
  45. */
  46. private $encryptionManager;
  47. /**
  48. * @var \OCP\Encryption\IEncryptionModule | \PHPUnit_Framework_MockObject_MockObject
  49. */
  50. private $encryptionModule;
  51. /**
  52. * @var \OC\Encryption\Update | \PHPUnit_Framework_MockObject_MockObject
  53. */
  54. private $update;
  55. /**
  56. * @var \OC\Files\Cache\Cache | \PHPUnit_Framework_MockObject_MockObject
  57. */
  58. private $cache;
  59. /**
  60. * @var \OC\Log | \PHPUnit_Framework_MockObject_MockObject
  61. */
  62. private $logger;
  63. /**
  64. * @var \OC\Encryption\File | \PHPUnit_Framework_MockObject_MockObject
  65. */
  66. private $file;
  67. /**
  68. * @var \OC\Files\Mount\MountPoint | \PHPUnit_Framework_MockObject_MockObject
  69. */
  70. private $mount;
  71. /**
  72. * @var \OC\Files\Mount\Manager | \PHPUnit_Framework_MockObject_MockObject
  73. */
  74. private $mountManager;
  75. /**
  76. * @var \OC\Group\Manager | \PHPUnit_Framework_MockObject_MockObject
  77. */
  78. private $groupManager;
  79. /**
  80. * @var \OCP\IConfig | \PHPUnit_Framework_MockObject_MockObject
  81. */
  82. private $config;
  83. /** @var \OC\Memcache\ArrayCache | \PHPUnit_Framework_MockObject_MockObject */
  84. private $arrayCache;
  85. /** @var integer dummy unencrypted size */
  86. private $dummySize = -1;
  87. protected function setUp() {
  88. parent::setUp();
  89. $mockModule = $this->buildMockModule();
  90. $this->encryptionManager = $this->getMockBuilder('\OC\Encryption\Manager')
  91. ->disableOriginalConstructor()
  92. ->setMethods(['getEncryptionModule', 'isEnabled'])
  93. ->getMock();
  94. $this->encryptionManager->expects($this->any())
  95. ->method('getEncryptionModule')
  96. ->willReturn($mockModule);
  97. $this->arrayCache = $this->createMock(ArrayCache::class);
  98. $this->config = $this->getMockBuilder(IConfig::class)
  99. ->disableOriginalConstructor()
  100. ->getMock();
  101. $this->groupManager = $this->getMockBuilder('\OC\Group\Manager')
  102. ->disableOriginalConstructor()
  103. ->getMock();
  104. $this->util = $this->getMockBuilder('\OC\Encryption\Util')
  105. ->setMethods(['getUidAndFilename', 'isFile', 'isExcluded'])
  106. ->setConstructorArgs([new View(), new Manager($this->config), $this->groupManager, $this->config, $this->arrayCache])
  107. ->getMock();
  108. $this->util->expects($this->any())
  109. ->method('getUidAndFilename')
  110. ->willReturnCallback(function ($path) {
  111. return ['user1', $path];
  112. });
  113. $this->file = $this->getMockBuilder('\OC\Encryption\File')
  114. ->disableOriginalConstructor()
  115. ->setMethods(['getAccessList'])
  116. ->getMock();
  117. $this->file->expects($this->any())->method('getAccessList')->willReturn([]);
  118. $this->logger = $this->createMock(Log::class);
  119. $this->sourceStorage = new Temporary(array());
  120. $this->keyStore = $this->getMockBuilder('\OC\Encryption\Keys\Storage')
  121. ->disableOriginalConstructor()->getMock();
  122. $this->update = $this->getMockBuilder('\OC\Encryption\Update')
  123. ->disableOriginalConstructor()->getMock();
  124. $this->mount = $this->getMockBuilder('\OC\Files\Mount\MountPoint')
  125. ->disableOriginalConstructor()
  126. ->setMethods(['getOption'])
  127. ->getMock();
  128. $this->mount->expects($this->any())->method('getOption')->willReturnCallback(function ($option, $default) {
  129. if ($option === 'encrypt' && $default === true) {
  130. global $mockedMountPointEncryptionEnabled;
  131. if ($mockedMountPointEncryptionEnabled !== null) {
  132. return $mockedMountPointEncryptionEnabled;
  133. }
  134. }
  135. return true;
  136. });
  137. $this->cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
  138. ->disableOriginalConstructor()->getMock();
  139. $this->cache->expects($this->any())
  140. ->method('get')
  141. ->willReturnCallback(function($path) {return ['encrypted' => false, 'path' => $path];});
  142. $this->mountManager = $this->createMock(\OC\Files\Mount\Manager::class);
  143. $this->mountManager->method('findByStorageId')
  144. ->willReturn([]);
  145. $this->instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption')
  146. ->setConstructorArgs(
  147. [
  148. [
  149. 'storage' => $this->sourceStorage,
  150. 'root' => 'foo',
  151. 'mountPoint' => '/',
  152. 'mount' => $this->mount
  153. ],
  154. $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache
  155. ]
  156. )
  157. ->setMethods(['getMetaData', 'getCache', 'getEncryptionModule'])
  158. ->getMock();
  159. $this->instance->expects($this->any())
  160. ->method('getMetaData')
  161. ->willReturnCallback(function ($path) {
  162. return ['encrypted' => true, 'size' => $this->dummySize, 'path' => $path];
  163. });
  164. $this->instance->expects($this->any())
  165. ->method('getCache')
  166. ->willReturn($this->cache);
  167. $this->instance->expects($this->any())
  168. ->method('getEncryptionModule')
  169. ->willReturn($mockModule);
  170. }
  171. /**
  172. * @return \PHPUnit_Framework_MockObject_MockObject
  173. */
  174. protected function buildMockModule() {
  175. $this->encryptionModule = $this->getMockBuilder('\OCP\Encryption\IEncryptionModule')
  176. ->disableOriginalConstructor()
  177. ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll', 'isReadyForUser', 'needDetailedAccessList'])
  178. ->getMock();
  179. $this->encryptionModule->expects($this->any())->method('getId')->willReturn('UNIT_TEST_MODULE');
  180. $this->encryptionModule->expects($this->any())->method('getDisplayName')->willReturn('Unit test module');
  181. $this->encryptionModule->expects($this->any())->method('begin')->willReturn([]);
  182. $this->encryptionModule->expects($this->any())->method('end')->willReturn('');
  183. $this->encryptionModule->expects($this->any())->method('encrypt')->willReturnArgument(0);
  184. $this->encryptionModule->expects($this->any())->method('decrypt')->willReturnArgument(0);
  185. $this->encryptionModule->expects($this->any())->method('update')->willReturn(true);
  186. $this->encryptionModule->expects($this->any())->method('shouldEncrypt')->willReturn(true);
  187. $this->encryptionModule->expects($this->any())->method('getUnencryptedBlockSize')->willReturn(8192);
  188. $this->encryptionModule->expects($this->any())->method('isReadable')->willReturn(true);
  189. $this->encryptionModule->expects($this->any())->method('needDetailedAccessList')->willReturn(false);
  190. return $this->encryptionModule;
  191. }
  192. /**
  193. * @dataProvider dataTestGetMetaData
  194. *
  195. * @param string $path
  196. * @param array $metaData
  197. * @param bool $encrypted
  198. * @param bool $unencryptedSizeSet
  199. * @param int $storedUnencryptedSize
  200. * @param array $expected
  201. */
  202. public function testGetMetaData($path, $metaData, $encrypted, $unencryptedSizeSet, $storedUnencryptedSize, $expected) {
  203. $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage')
  204. ->disableOriginalConstructor()->getMock();
  205. $cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
  206. ->disableOriginalConstructor()->getMock();
  207. $cache->expects($this->any())
  208. ->method('get')
  209. ->willReturnCallback(
  210. function($path) use ($encrypted) {
  211. return ['encrypted' => $encrypted, 'path' => $path, 'size' => 0, 'fileid' => 1];
  212. }
  213. );
  214. $this->instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption')
  215. ->setConstructorArgs(
  216. [
  217. [
  218. 'storage' => $sourceStorage,
  219. 'root' => 'foo',
  220. 'mountPoint' => '/',
  221. 'mount' => $this->mount
  222. ],
  223. $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache
  224. ]
  225. )
  226. ->setMethods(['getCache', 'verifyUnencryptedSize'])
  227. ->getMock();
  228. if($unencryptedSizeSet) {
  229. $this->invokePrivate($this->instance, 'unencryptedSize', [[$path => $storedUnencryptedSize]]);
  230. }
  231. $fileEntry = $this->getMockBuilder('\OC\Files\Cache\Cache')
  232. ->disableOriginalConstructor()->getMock();
  233. $sourceStorage->expects($this->once())->method('getMetaData')->with($path)
  234. ->willReturn($metaData);
  235. $sourceStorage->expects($this->any())
  236. ->method('getCache')
  237. ->with($path)
  238. ->willReturn($fileEntry);
  239. $fileEntry->expects($this->any())
  240. ->method('get')
  241. ->with($metaData['fileid']);
  242. $this->instance->expects($this->any())->method('getCache')->willReturn($cache);
  243. $this->instance->expects($this->any())->method('verifyUnencryptedSize')
  244. ->with($path, 0)->willReturn($expected['size']);
  245. $result = $this->instance->getMetaData($path);
  246. if(isset($expected['encrypted'])) {
  247. $this->assertSame($expected['encrypted'], (bool)$result['encrypted']);
  248. if(isset($expected['encryptedVersion'])) {
  249. $this->assertSame($expected['encryptedVersion'], $result['encryptedVersion']);
  250. }
  251. }
  252. $this->assertSame($expected['size'], $result['size']);
  253. }
  254. public function dataTestGetMetaData() {
  255. return [
  256. ['/test.txt', ['size' => 42, 'encrypted' => 2, 'encryptedVersion' => 2, 'fileid' => 1], true, true, 12, ['size' => 12, 'encrypted' => true, 'encryptedVersion' => 2]],
  257. ['/test.txt', null, true, true, 12, null],
  258. ['/test.txt', ['size' => 42, 'encrypted' => 0, 'fileid' => 1], false, false, 12, ['size' => 42, 'encrypted' => false]],
  259. ['/test.txt', ['size' => 42, 'encrypted' => false, 'fileid' => 1], true, false, 12, ['size' => 12, 'encrypted' => true]]
  260. ];
  261. }
  262. public function testFilesize() {
  263. $cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
  264. ->disableOriginalConstructor()->getMock();
  265. $cache->expects($this->any())
  266. ->method('get')
  267. ->willReturn(['encrypted' => true, 'path' => '/test.txt', 'size' => 0, 'fileid' => 1]);
  268. $this->instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption')
  269. ->setConstructorArgs(
  270. [
  271. [
  272. 'storage' => $this->sourceStorage,
  273. 'root' => 'foo',
  274. 'mountPoint' => '/',
  275. 'mount' => $this->mount
  276. ],
  277. $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache
  278. ]
  279. )
  280. ->setMethods(['getCache', 'verifyUnencryptedSize'])
  281. ->getMock();
  282. $this->instance->expects($this->any())->method('getCache')->willReturn($cache);
  283. $this->instance->expects($this->any())->method('verifyUnencryptedSize')
  284. ->willReturn(42);
  285. $this->assertSame(42,
  286. $this->instance->filesize('/test.txt')
  287. );
  288. }
  289. /**
  290. * @dataProvider dataTestVerifyUnencryptedSize
  291. *
  292. * @param int $encryptedSize
  293. * @param int $unencryptedSize
  294. * @param bool $failure
  295. * @param int $expected
  296. */
  297. public function testVerifyUnencryptedSize($encryptedSize, $unencryptedSize, $failure, $expected) {
  298. $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage')
  299. ->disableOriginalConstructor()->getMock();
  300. $this->instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption')
  301. ->setConstructorArgs(
  302. [
  303. [
  304. 'storage' => $sourceStorage,
  305. 'root' => 'foo',
  306. 'mountPoint' => '/',
  307. 'mount' => $this->mount
  308. ],
  309. $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache
  310. ]
  311. )
  312. ->setMethods(['fixUnencryptedSize'])
  313. ->getMock();
  314. $sourceStorage->expects($this->once())->method('filesize')->willReturn($encryptedSize);
  315. $this->instance->expects($this->any())->method('fixUnencryptedSize')
  316. ->with('/test.txt', $encryptedSize, $unencryptedSize)
  317. ->willReturnCallback(
  318. function() use ($failure, $expected) {
  319. if ($failure) {
  320. throw new \Exception();
  321. } else {
  322. return $expected;
  323. }
  324. }
  325. );
  326. $this->assertSame(
  327. $expected,
  328. $this->invokePrivate($this->instance, 'verifyUnencryptedSize', ['/test.txt', $unencryptedSize])
  329. );
  330. }
  331. public function dataTestVerifyUnencryptedSize() {
  332. return [
  333. [120, 80, false, 80],
  334. [120, 120, false, 80],
  335. [120, -1, false, 80],
  336. [120, -1, true, -1]
  337. ];
  338. }
  339. /**
  340. * @dataProvider dataTestCopyAndRename
  341. *
  342. * @param string $source
  343. * @param string $target
  344. * @param $encryptionEnabled
  345. * @param boolean $renameKeysReturn
  346. */
  347. public function testRename($source,
  348. $target,
  349. $encryptionEnabled,
  350. $renameKeysReturn) {
  351. if ($encryptionEnabled) {
  352. $this->keyStore
  353. ->expects($this->once())
  354. ->method('renameKeys')
  355. ->willReturn($renameKeysReturn);
  356. } else {
  357. $this->keyStore
  358. ->expects($this->never())->method('renameKeys');
  359. }
  360. $this->util->expects($this->any())
  361. ->method('isFile')->willReturn(true);
  362. $this->encryptionManager->expects($this->once())
  363. ->method('isEnabled')->willReturn($encryptionEnabled);
  364. $this->instance->mkdir($source);
  365. $this->instance->mkdir(dirname($target));
  366. $this->instance->rename($source, $target);
  367. }
  368. public function testCopyEncryption() {
  369. $this->instance->file_put_contents('source.txt', 'bar');
  370. $this->instance->copy('source.txt', 'target.txt');
  371. $this->assertSame('bar', $this->instance->file_get_contents('target.txt'));
  372. $targetMeta = $this->instance->getMetaData('target.txt');
  373. $sourceMeta = $this->instance->getMetaData('source.txt');
  374. $this->assertSame($sourceMeta['encrypted'], $targetMeta['encrypted']);
  375. $this->assertSame($sourceMeta['size'], $targetMeta['size']);
  376. }
  377. /**
  378. * data provider for testCopyTesting() and dataTestCopyAndRename()
  379. *
  380. * @return array
  381. */
  382. public function dataTestCopyAndRename() {
  383. return array(
  384. array('source', 'target', true, false, false),
  385. array('source', 'target', true, true, false),
  386. array('source', '/subFolder/target', true, false, false),
  387. array('source', '/subFolder/target', true, true, true),
  388. array('source', '/subFolder/target', false, true, false),
  389. );
  390. }
  391. public function testIsLocal() {
  392. $this->encryptionManager->expects($this->once())
  393. ->method('isEnabled')->willReturn(true);
  394. $this->assertFalse($this->instance->isLocal());
  395. }
  396. /**
  397. * @dataProvider dataTestRmdir
  398. *
  399. * @param string $path
  400. * @param boolean $rmdirResult
  401. * @param boolean $isExcluded
  402. * @param boolean $encryptionEnabled
  403. */
  404. public function testRmdir($path, $rmdirResult, $isExcluded, $encryptionEnabled) {
  405. $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage')
  406. ->disableOriginalConstructor()->getMock();
  407. $util = $this->getMockBuilder('\OC\Encryption\Util')->disableOriginalConstructor()->getMock();
  408. $sourceStorage->expects($this->once())->method('rmdir')->willReturn($rmdirResult);
  409. $util->expects($this->any())->method('isExcluded')-> willReturn($isExcluded);
  410. $this->encryptionManager->expects($this->any())->method('isEnabled')->willReturn($encryptionEnabled);
  411. $encryptionStorage = new \OC\Files\Storage\Wrapper\Encryption(
  412. [
  413. 'storage' => $sourceStorage,
  414. 'root' => 'foo',
  415. 'mountPoint' => '/mountPoint',
  416. 'mount' => $this->mount
  417. ],
  418. $this->encryptionManager, $util, $this->logger, $this->file, null, $this->keyStore, $this->update
  419. );
  420. if ($rmdirResult === true && $isExcluded === false && $encryptionEnabled === true) {
  421. $this->keyStore->expects($this->once())->method('deleteAllFileKeys')->with('/mountPoint' . $path);
  422. } else {
  423. $this->keyStore->expects($this->never())->method('deleteAllFileKeys');
  424. }
  425. $encryptionStorage->rmdir($path);
  426. }
  427. public function dataTestRmdir() {
  428. return array(
  429. array('/file.txt', true, true, true),
  430. array('/file.txt', false, true, true),
  431. array('/file.txt', true, false, true),
  432. array('/file.txt', false, false, true),
  433. array('/file.txt', true, true, false),
  434. array('/file.txt', false, true, false),
  435. array('/file.txt', true, false, false),
  436. array('/file.txt', false, false, false),
  437. );
  438. }
  439. /**
  440. * @dataProvider dataTestCopyKeys
  441. *
  442. * @param boolean $excluded
  443. * @param boolean $expected
  444. */
  445. public function testCopyKeys($excluded, $expected) {
  446. $this->util->expects($this->once())
  447. ->method('isExcluded')
  448. ->willReturn($excluded);
  449. if ($excluded) {
  450. $this->keyStore->expects($this->never())->method('copyKeys');
  451. } else {
  452. $this->keyStore->expects($this->once())->method('copyKeys')->willReturn(true);
  453. }
  454. $this->assertSame($expected,
  455. self::invokePrivate($this->instance, 'copyKeys', ['/source', '/target'])
  456. );
  457. }
  458. public function dataTestCopyKeys() {
  459. return array(
  460. array(true, false),
  461. array(false, true),
  462. );
  463. }
  464. /**
  465. * @dataProvider dataTestGetHeader
  466. *
  467. * @param string $path
  468. * @param bool $strippedPathExists
  469. * @param string $strippedPath
  470. */
  471. public function testGetHeader($path, $strippedPathExists, $strippedPath) {
  472. $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage')
  473. ->disableOriginalConstructor()->getMock();
  474. $util = $this->getMockBuilder('\OC\Encryption\Util')
  475. ->setConstructorArgs(
  476. [
  477. new View(),
  478. new Manager($this->config),
  479. $this->groupManager,
  480. $this->config,
  481. $this->arrayCache
  482. ]
  483. )->getMock();
  484. $instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption')
  485. ->setConstructorArgs(
  486. [
  487. [
  488. 'storage' => $sourceStorage,
  489. 'root' => 'foo',
  490. 'mountPoint' => '/',
  491. 'mount' => $this->mount
  492. ],
  493. $this->encryptionManager, $util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache
  494. ]
  495. )
  496. ->setMethods(['readFirstBlock', 'parseRawHeader'])
  497. ->getMock();
  498. $instance->expects($this->once())->method(('parseRawHeader'))
  499. ->willReturn([Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']);
  500. if ($strippedPathExists) {
  501. $instance->expects($this->once())->method('readFirstBlock')
  502. ->with($strippedPath)->willReturn('');
  503. } else {
  504. $instance->expects($this->once())->method('readFirstBlock')
  505. ->with($path)->willReturn('');
  506. }
  507. $util->expects($this->once())->method('stripPartialFileExtension')
  508. ->with($path)->willReturn($strippedPath);
  509. $sourceStorage->expects($this->once())
  510. ->method('file_exists')
  511. ->with($strippedPath)
  512. ->willReturn($strippedPathExists);
  513. $this->invokePrivate($instance, 'getHeader', [$path]);
  514. }
  515. public function dataTestGetHeader() {
  516. return array(
  517. array('/foo/bar.txt', false, '/foo/bar.txt'),
  518. array('/foo/bar.txt.part', false, '/foo/bar.txt'),
  519. array('/foo/bar.txt.ocTransferId7437493.part', false, '/foo/bar.txt'),
  520. array('/foo/bar.txt.part', true, '/foo/bar.txt'),
  521. array('/foo/bar.txt.ocTransferId7437493.part', true, '/foo/bar.txt'),
  522. );
  523. }
  524. /**
  525. * test if getHeader adds the default module correctly to the header for
  526. * legacy files
  527. *
  528. * @dataProvider dataTestGetHeaderAddLegacyModule
  529. */
  530. public function testGetHeaderAddLegacyModule($header, $isEncrypted, $exists, $expected) {
  531. $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage')
  532. ->disableOriginalConstructor()->getMock();
  533. $sourceStorage->expects($this->once())
  534. ->method('file_exists')
  535. ->willReturn($exists);
  536. $util = $this->getMockBuilder('\OC\Encryption\Util')
  537. ->setConstructorArgs([new View(), new Manager($this->config), $this->groupManager, $this->config, $this->arrayCache])
  538. ->getMock();
  539. $cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
  540. ->disableOriginalConstructor()->getMock();
  541. $cache->expects($this->any())
  542. ->method('get')
  543. ->willReturnCallback(function($path) use ($isEncrypted) {return ['encrypted' => $isEncrypted, 'path' => $path];});
  544. $instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption')
  545. ->setConstructorArgs(
  546. [
  547. [
  548. 'storage' => $sourceStorage,
  549. 'root' => 'foo',
  550. 'mountPoint' => '/',
  551. 'mount' => $this->mount
  552. ],
  553. $this->encryptionManager, $util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache
  554. ]
  555. )
  556. ->setMethods(['readFirstBlock', 'parseRawHeader', 'getCache'])
  557. ->getMock();
  558. $instance->expects($this->once())->method(('parseRawHeader'))->willReturn($header);
  559. $instance->expects($this->any())->method('getCache')->willReturn($cache);
  560. $result = $this->invokePrivate($instance, 'getHeader', ['test.txt']);
  561. $this->assertSameSize($expected, $result);
  562. foreach ($result as $key => $value) {
  563. $this->assertArrayHasKey($key, $expected);
  564. $this->assertSame($expected[$key], $value);
  565. }
  566. }
  567. public function dataTestGetHeaderAddLegacyModule() {
  568. return [
  569. [['cipher' => 'AES-128'], true, true, ['cipher' => 'AES-128', Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']],
  570. [[], true, false, []],
  571. [[], true, true, [Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']],
  572. [[], false, true, []],
  573. ];
  574. }
  575. /**
  576. * @dataProvider dataTestParseRawHeader
  577. */
  578. public function testParseRawHeader($rawHeader, $expected) {
  579. $instance = new \OC\Files\Storage\Wrapper\Encryption(
  580. [
  581. 'storage' => $this->sourceStorage,
  582. 'root' => 'foo',
  583. 'mountPoint' => '/',
  584. 'mount' => $this->mount
  585. ],
  586. $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache
  587. );
  588. $result = $this->invokePrivate($instance, 'parseRawHeader', [$rawHeader]);
  589. $this->assertSameSize($expected, $result);
  590. foreach ($result as $key => $value) {
  591. $this->assertArrayHasKey($key, $expected);
  592. $this->assertSame($expected[$key], $value);
  593. }
  594. }
  595. public function dataTestParseRawHeader() {
  596. return [
  597. [str_pad('HBEGIN:oc_encryption_module:0:HEND', $this->headerSize, '-', STR_PAD_RIGHT)
  598. , [Util::HEADER_ENCRYPTION_MODULE_KEY => '0']],
  599. [str_pad('HBEGIN:oc_encryption_module:0:custom_header:foo:HEND', $this->headerSize, '-', STR_PAD_RIGHT)
  600. , ['custom_header' => 'foo', Util::HEADER_ENCRYPTION_MODULE_KEY => '0']],
  601. [str_pad('HelloWorld', $this->headerSize, '-', STR_PAD_RIGHT), []],
  602. ['', []],
  603. [str_pad('HBEGIN:oc_encryption_module:0', $this->headerSize, '-', STR_PAD_RIGHT)
  604. , []],
  605. [str_pad('oc_encryption_module:0:HEND', $this->headerSize, '-', STR_PAD_RIGHT)
  606. , []],
  607. ];
  608. }
  609. public function dataCopyBetweenStorage() {
  610. return [
  611. [true, true, true],
  612. [true, false, false],
  613. [false, true, false],
  614. [false, false, false],
  615. ];
  616. }
  617. public function testCopyBetweenStorageMinimumEncryptedVersion() {
  618. $storage2 = $this->createMock(\OC\Files\Storage\Storage::class);
  619. $sourceInternalPath = $targetInternalPath = 'file.txt';
  620. $preserveMtime = $isRename = false;
  621. $storage2->expects($this->any())
  622. ->method('fopen')
  623. ->willReturnCallback(function($path, $mode) {
  624. $temp = \OC::$server->getTempManager();
  625. return fopen($temp->getTemporaryFile(), $mode);
  626. });
  627. $storage2->method('getId')
  628. ->willReturn('stroage2');
  629. $cache = $this->createMock(ICache::class);
  630. $cache->expects($this->once())
  631. ->method('get')
  632. ->with($sourceInternalPath)
  633. ->willReturn(['encryptedVersion' => 0]);
  634. $storage2->expects($this->once())
  635. ->method('getCache')
  636. ->willReturn($cache);
  637. $this->encryptionManager->expects($this->any())
  638. ->method('isEnabled')
  639. ->willReturn(true);
  640. global $mockedMountPointEncryptionEnabled;
  641. $mockedMountPointEncryptionEnabled = true;
  642. $expectedCachePut = [
  643. 'encrypted' => true,
  644. ];
  645. $expectedCachePut['encryptedVersion'] = 1;
  646. $this->cache->expects($this->once())
  647. ->method('put')
  648. ->with($sourceInternalPath, $expectedCachePut);
  649. $this->invokePrivate($this->instance, 'copyBetweenStorage', [$storage2, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename]);
  650. $this->assertFalse(false);
  651. }
  652. /**
  653. * @dataProvider dataCopyBetweenStorage
  654. *
  655. * @param bool $encryptionEnabled
  656. * @param bool $mountPointEncryptionEnabled
  657. * @param bool $expectedEncrypted
  658. */
  659. public function testCopyBetweenStorage($encryptionEnabled, $mountPointEncryptionEnabled, $expectedEncrypted) {
  660. $storage2 = $this->createMock(\OC\Files\Storage\Storage::class);
  661. $sourceInternalPath = $targetInternalPath = 'file.txt';
  662. $preserveMtime = $isRename = false;
  663. $storage2->expects($this->any())
  664. ->method('fopen')
  665. ->willReturnCallback(function($path, $mode) {
  666. $temp = \OC::$server->getTempManager();
  667. return fopen($temp->getTemporaryFile(), $mode);
  668. });
  669. $storage2->method('getId')
  670. ->willReturn('stroage2');
  671. if($expectedEncrypted) {
  672. $cache = $this->createMock(ICache::class);
  673. $cache->expects($this->once())
  674. ->method('get')
  675. ->with($sourceInternalPath)
  676. ->willReturn(['encryptedVersion' => 12345]);
  677. $storage2->expects($this->once())
  678. ->method('getCache')
  679. ->willReturn($cache);
  680. }
  681. $this->encryptionManager->expects($this->any())
  682. ->method('isEnabled')
  683. ->willReturn($encryptionEnabled);
  684. // FIXME can not overwrite the return after definition
  685. // $this->mount->expects($this->at(0))
  686. // ->method('getOption')
  687. // ->with('encrypt', true)
  688. // ->willReturn($mountPointEncryptionEnabled);
  689. global $mockedMountPointEncryptionEnabled;
  690. $mockedMountPointEncryptionEnabled = $mountPointEncryptionEnabled;
  691. $expectedCachePut = [
  692. 'encrypted' => $expectedEncrypted,
  693. ];
  694. if($expectedEncrypted === true) {
  695. $expectedCachePut['encryptedVersion'] = 1;
  696. }
  697. $this->arrayCache->expects($this->never())->method('set');
  698. $this->cache->expects($this->once())
  699. ->method('put')
  700. ->with($sourceInternalPath, $expectedCachePut);
  701. $this->invokePrivate($this->instance, 'copyBetweenStorage', [$storage2, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename]);
  702. $this->assertFalse(false);
  703. }
  704. /**
  705. * @dataProvider dataTestCopyBetweenStorageVersions
  706. *
  707. * @param string $sourceInternalPath
  708. * @param string $targetInternalPath
  709. * @param bool $copyResult
  710. * @param bool $encrypted
  711. */
  712. public function testCopyBetweenStorageVersions($sourceInternalPath, $targetInternalPath, $copyResult, $encrypted) {
  713. $sourceStorage = $this->createMock(\OC\Files\Storage\Storage::class);
  714. $targetStorage = $this->createMock(\OC\Files\Storage\Storage::class);
  715. $cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
  716. ->disableOriginalConstructor()->getMock();
  717. $mountPoint = '/mountPoint';
  718. /** @var \OC\Files\Storage\Wrapper\Encryption |\PHPUnit_Framework_MockObject_MockObject $instance */
  719. $instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption')
  720. ->setConstructorArgs(
  721. [
  722. [
  723. 'storage' => $targetStorage,
  724. 'root' => 'foo',
  725. 'mountPoint' => $mountPoint,
  726. 'mount' => $this->mount
  727. ],
  728. $this->encryptionManager,
  729. $this->util,
  730. $this->logger,
  731. $this->file,
  732. null,
  733. $this->keyStore,
  734. $this->update,
  735. $this->mountManager,
  736. $this->arrayCache
  737. ]
  738. )
  739. ->setMethods(['updateUnencryptedSize', 'getCache'])
  740. ->getMock();
  741. $targetStorage->expects($this->once())->method('copyFromStorage')
  742. ->with($sourceStorage, $sourceInternalPath, $targetInternalPath)
  743. ->willReturn($copyResult);
  744. $instance->expects($this->any())->method('getCache')
  745. ->willReturn($cache);
  746. $this->arrayCache->expects($this->once())->method('set')
  747. ->with('encryption_copy_version_' . $sourceInternalPath, true);
  748. if ($copyResult) {
  749. $cache->expects($this->once())->method('get')
  750. ->with($sourceInternalPath)
  751. ->willReturn(['encrypted' => $encrypted, 'size' => 42]);
  752. if ($encrypted) {
  753. $instance->expects($this->once())->method('updateUnencryptedSize')
  754. ->with($mountPoint . $targetInternalPath, 42);
  755. } else {
  756. $instance->expects($this->never())->method('updateUnencryptedSize');
  757. }
  758. } else {
  759. $instance->expects($this->never())->method('updateUnencryptedSize');
  760. }
  761. $result = $this->invokePrivate(
  762. $instance,
  763. 'copyBetweenStorage',
  764. [
  765. $sourceStorage,
  766. $sourceInternalPath,
  767. $targetInternalPath,
  768. false,
  769. false
  770. ]
  771. );
  772. $this->assertSame($copyResult, $result);
  773. }
  774. public function dataTestCopyBetweenStorageVersions() {
  775. return [
  776. ['/files/foo.txt', '/files_versions/foo.txt.768743', true, true],
  777. ['/files/foo.txt', '/files_versions/foo.txt.768743', true, false],
  778. ['/files/foo.txt', '/files_versions/foo.txt.768743', false, true],
  779. ['/files/foo.txt', '/files_versions/foo.txt.768743', false, false],
  780. ['/files_versions/foo.txt.6487634', '/files/foo.txt', true, true],
  781. ['/files_versions/foo.txt.6487634', '/files/foo.txt', true, false],
  782. ['/files_versions/foo.txt.6487634', '/files/foo.txt', false, true],
  783. ['/files_versions/foo.txt.6487634', '/files/foo.txt', false, false],
  784. ];
  785. }
  786. /**
  787. * @dataProvider dataTestIsVersion
  788. * @param string $path
  789. * @param bool $expected
  790. */
  791. public function testIsVersion($path, $expected) {
  792. $this->assertSame($expected,
  793. $this->invokePrivate($this->instance, 'isVersion', [$path])
  794. );
  795. }
  796. public function dataTestIsVersion() {
  797. return [
  798. ['files_versions/foo', true],
  799. ['/files_versions/foo', true],
  800. ['//files_versions/foo', true],
  801. ['files/versions/foo', false],
  802. ['files/files_versions/foo', false],
  803. ['files_versions_test/foo', false],
  804. ];
  805. }
  806. /**
  807. * @dataProvider dataTestShouldEncrypt
  808. *
  809. * @param bool $encryptMountPoint
  810. * @param mixed $encryptionModule
  811. * @param bool $encryptionModuleShouldEncrypt
  812. * @param bool $expected
  813. */
  814. public function testShouldEncrypt(
  815. $encryptMountPoint,
  816. $encryptionModule,
  817. $encryptionModuleShouldEncrypt,
  818. $expected
  819. ) {
  820. $encryptionManager = $this->createMock(\OC\Encryption\Manager::class);
  821. $util = $this->createMock(Util::class);
  822. $logger = $this->createMock(ILogger::class);
  823. $fileHelper = $this->createMock(IFile::class);
  824. $uid = null;
  825. $keyStorage = $this->createMock(IStorage::class);
  826. $update = $this->createMock(Update::class);
  827. $mountManager = $this->createMock(\OC\Files\Mount\Manager::class);
  828. $mount = $this->createMock(IMountPoint::class);
  829. $arrayCache = $this->createMock(ArrayCache::class);
  830. $path = '/welcome.txt';
  831. $fullPath = 'admin/files/welcome.txt';
  832. $defaultEncryptionModule = $this->createMock(IEncryptionModule::class);
  833. $wrapper = $this->getMockBuilder(Encryption::class)
  834. ->setConstructorArgs(
  835. [
  836. ['mountPoint' => '', 'mount' => $mount, 'storage' => ''],
  837. $encryptionManager,
  838. $util,
  839. $logger,
  840. $fileHelper,
  841. $uid,
  842. $keyStorage,
  843. $update,
  844. $mountManager,
  845. $arrayCache
  846. ]
  847. )
  848. ->setMethods(['getFullPath', 'getEncryptionModule'])
  849. ->getMock();
  850. if ($encryptionModule === true) {
  851. /** @var IEncryptionModule|\PHPUnit_Framework_MockObject_MockObject $encryptionModule */
  852. $encryptionModule = $this->createMock(IEncryptionModule::class);
  853. }
  854. $wrapper->method('getFullPath')->with($path)->willReturn($fullPath);
  855. $wrapper->expects($encryptMountPoint ? $this->once() : $this->never())
  856. ->method('getEncryptionModule')
  857. ->with($fullPath)
  858. ->willReturnCallback(
  859. function() use ($encryptionModule) {
  860. if ($encryptionModule === false) {
  861. throw new ModuleDoesNotExistsException();
  862. }
  863. return $encryptionModule;
  864. }
  865. );
  866. $mount->expects($this->once())->method('getOption')->with('encrypt', true)
  867. ->willReturn($encryptMountPoint);
  868. if ($encryptionModule !== null && $encryptionModule !== false) {
  869. $encryptionModule
  870. ->method('shouldEncrypt')
  871. ->with($fullPath)
  872. ->willReturn($encryptionModuleShouldEncrypt);
  873. }
  874. if ($encryptionModule === null) {
  875. $encryptionManager->expects($this->once())
  876. ->method('getEncryptionModule')
  877. ->willReturn($defaultEncryptionModule);
  878. }
  879. $defaultEncryptionModule->method('shouldEncrypt')->willReturn(true);
  880. $result = $this->invokePrivate($wrapper, 'shouldEncrypt', [$path]);
  881. $this->assertSame($expected, $result);
  882. }
  883. public function dataTestShouldEncrypt() {
  884. return [
  885. [false, false, false, false],
  886. [true, false, false, false],
  887. [true, true, false, false],
  888. [true, true, true, true],
  889. [true, null, false, true],
  890. ];
  891. }
  892. }