You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UtilTest.php 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. <?php
  2. /**
  3. * Copyright (c) 2012 Lukas Reschke <lukas@statuscode.ch>
  4. * This file is licensed under the Affero General Public License version 3 or
  5. * later.
  6. * See the COPYING-README file.
  7. */
  8. namespace Test;
  9. use OC_Util;
  10. use OCP\App\IAppManager;
  11. use OCP\IConfig;
  12. use OCP\IUser;
  13. /**
  14. * Class UtilTest
  15. *
  16. * @package Test
  17. * @group DB
  18. */
  19. class UtilTest extends \Test\TestCase {
  20. public function testGetVersion() {
  21. $version = \OCP\Util::getVersion();
  22. $this->assertTrue(is_array($version));
  23. foreach ($version as $num) {
  24. $this->assertTrue(is_int($num));
  25. }
  26. }
  27. public function testGetVersionString() {
  28. $version = \OC_Util::getVersionString();
  29. $this->assertTrue(is_string($version));
  30. }
  31. public function testGetEditionString() {
  32. $edition = \OC_Util::getEditionString();
  33. $this->assertTrue(is_string($edition));
  34. }
  35. public function testSanitizeHTML() {
  36. $badArray = [
  37. 'While it is unusual to pass an array',
  38. 'this function actually <blink>supports</blink> it.',
  39. 'And therefore there needs to be a <script>alert("Unit"+\'test\')</script> for it!',
  40. [
  41. 'And It Even May <strong>Nest</strong>',
  42. ],
  43. ];
  44. $goodArray = [
  45. 'While it is unusual to pass an array',
  46. 'this function actually &lt;blink&gt;supports&lt;/blink&gt; it.',
  47. 'And therefore there needs to be a &lt;script&gt;alert(&quot;Unit&quot;+&#039;test&#039;)&lt;/script&gt; for it!',
  48. [
  49. 'And It Even May &lt;strong&gt;Nest&lt;/strong&gt;'
  50. ],
  51. ];
  52. $result = OC_Util::sanitizeHTML($badArray);
  53. $this->assertEquals($goodArray, $result);
  54. $badString = '<img onload="alert(1)" />';
  55. $result = OC_Util::sanitizeHTML($badString);
  56. $this->assertEquals('&lt;img onload=&quot;alert(1)&quot; /&gt;', $result);
  57. $badString = "<script>alert('Hacked!');</script>";
  58. $result = OC_Util::sanitizeHTML($badString);
  59. $this->assertEquals('&lt;script&gt;alert(&#039;Hacked!&#039;);&lt;/script&gt;', $result);
  60. $goodString = 'This is a good string without HTML.';
  61. $result = OC_Util::sanitizeHTML($goodString);
  62. $this->assertEquals('This is a good string without HTML.', $result);
  63. }
  64. public function testEncodePath() {
  65. $component = '/§#@test%&^ä/-child';
  66. $result = OC_Util::encodePath($component);
  67. $this->assertEquals("/%C2%A7%23%40test%25%26%5E%C3%A4/-child", $result);
  68. }
  69. public function testFileInfoLoaded() {
  70. $expected = function_exists('finfo_open');
  71. $this->assertEquals($expected, \OC_Util::fileInfoLoaded());
  72. }
  73. public function testGetDefaultEmailAddress() {
  74. $email = \OCP\Util::getDefaultEmailAddress("no-reply");
  75. $this->assertEquals('no-reply@localhost', $email);
  76. }
  77. public function testGetDefaultEmailAddressFromConfig() {
  78. $config = \OC::$server->getConfig();
  79. $config->setSystemValue('mail_domain', 'example.com');
  80. $email = \OCP\Util::getDefaultEmailAddress("no-reply");
  81. $this->assertEquals('no-reply@example.com', $email);
  82. $config->deleteSystemValue('mail_domain');
  83. }
  84. public function testGetConfiguredEmailAddressFromConfig() {
  85. $config = \OC::$server->getConfig();
  86. $config->setSystemValue('mail_domain', 'example.com');
  87. $config->setSystemValue('mail_from_address', 'owncloud');
  88. $email = \OCP\Util::getDefaultEmailAddress("no-reply");
  89. $this->assertEquals('owncloud@example.com', $email);
  90. $config->deleteSystemValue('mail_domain');
  91. $config->deleteSystemValue('mail_from_address');
  92. }
  93. public function testGetInstanceIdGeneratesValidId() {
  94. \OC::$server->getConfig()->deleteSystemValue('instanceid');
  95. $instanceId = OC_Util::getInstanceId();
  96. $this->assertStringStartsWith('oc', $instanceId);
  97. $matchesRegex = preg_match('/^[a-z0-9]+$/', $instanceId);
  98. $this->assertSame(1, $matchesRegex);
  99. }
  100. /**
  101. * @dataProvider filenameValidationProvider
  102. */
  103. public function testFilenameValidation($file, $valid) {
  104. // private API
  105. $this->assertEquals($valid, \OC_Util::isValidFileName($file));
  106. // public API
  107. $this->assertEquals($valid, \OCP\Util::isValidFileName($file));
  108. }
  109. public function filenameValidationProvider() {
  110. return [
  111. // valid names
  112. ['boringname', true],
  113. ['something.with.extension', true],
  114. ['now with spaces', true],
  115. ['.a', true],
  116. ['..a', true],
  117. ['.dotfile', true],
  118. ['single\'quote', true],
  119. [' spaces before', true],
  120. ['spaces after ', true],
  121. ['allowed chars including the crazy ones $%&_-^@!,()[]{}=;#', true],
  122. ['汉字也能用', true],
  123. ['und Ümläüte sind auch willkommen', true],
  124. // disallowed names
  125. ['', false],
  126. [' ', false],
  127. ['.', false],
  128. ['..', false],
  129. ['back\\slash', false],
  130. ['sl/ash', false],
  131. ['lt<lt', true],
  132. ['gt>gt', true],
  133. ['col:on', true],
  134. ['double"quote', true],
  135. ['pi|pe', true],
  136. ['dont?ask?questions?', true],
  137. ['super*star', true],
  138. ['new\nline', false],
  139. // better disallow these to avoid unexpected trimming to have side effects
  140. [' ..', false],
  141. ['.. ', false],
  142. ['. ', false],
  143. [' .', false],
  144. // part files not allowed
  145. ['.part', false],
  146. ['notallowed.part', false],
  147. ['neither.filepart', false],
  148. // part in the middle is ok
  149. ['super movie part one.mkv', true],
  150. ['super.movie.part.mkv', true],
  151. ];
  152. }
  153. /**
  154. * @dataProvider dataProviderForTestIsSharingDisabledForUser
  155. * @param array $groups existing groups
  156. * @param array $membership groups the user belong to
  157. * @param array $excludedGroups groups which should be excluded from sharing
  158. * @param bool $expected expected result
  159. */
  160. public function testIsSharingDisabledForUser($groups, $membership, $excludedGroups, $expected) {
  161. $config = $this->getMockBuilder(IConfig::class)->disableOriginalConstructor()->getMock();
  162. $groupManager = $this->getMockBuilder('OCP\IGroupManager')->disableOriginalConstructor()->getMock();
  163. $user = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
  164. $config
  165. ->expects($this->at(0))
  166. ->method('getAppValue')
  167. ->with('core', 'shareapi_exclude_groups', 'no')
  168. ->willReturn('yes');
  169. $config
  170. ->expects($this->at(1))
  171. ->method('getAppValue')
  172. ->with('core', 'shareapi_exclude_groups_list')
  173. ->willReturn(json_encode($excludedGroups));
  174. $groupManager
  175. ->expects($this->at(0))
  176. ->method('getUserGroupIds')
  177. ->with($user)
  178. ->willReturn($membership);
  179. $result = \OC_Util::isSharingDisabledForUser($config, $groupManager, $user);
  180. $this->assertSame($expected, $result);
  181. }
  182. public function dataProviderForTestIsSharingDisabledForUser() {
  183. return [
  184. // existing groups, groups the user belong to, groups excluded from sharing, expected result
  185. [['g1', 'g2', 'g3'], [], ['g1'], false],
  186. [['g1', 'g2', 'g3'], [], [], false],
  187. [['g1', 'g2', 'g3'], ['g2'], ['g1'], false],
  188. [['g1', 'g2', 'g3'], ['g2'], [], false],
  189. [['g1', 'g2', 'g3'], ['g1', 'g2'], ['g1'], false],
  190. [['g1', 'g2', 'g3'], ['g1', 'g2'], ['g1', 'g2'], true],
  191. [['g1', 'g2', 'g3'], ['g1', 'g2'], ['g1', 'g2', 'g3'], true],
  192. ];
  193. }
  194. /**
  195. * Test default apps
  196. *
  197. * @dataProvider defaultAppsProvider
  198. * @group DB
  199. */
  200. public function testDefaultApps($defaultAppConfig, $expectedPath, $enabledApps) {
  201. $oldDefaultApps = \OC::$server->getConfig()->getSystemValue('defaultapp', '');
  202. // CLI is doing messy stuff with the webroot, so need to work it around
  203. $oldWebRoot = \OC::$WEBROOT;
  204. \OC::$WEBROOT = '';
  205. $appManager = $this->createMock(IAppManager::class);
  206. $appManager->expects($this->any())
  207. ->method('isEnabledForUser')
  208. ->willReturnCallback(function ($appId) use ($enabledApps) {
  209. return in_array($appId, $enabledApps);
  210. });
  211. Dummy_OC_Util::$appManager = $appManager;
  212. // need to set a user id to make sure enabled apps are read from cache
  213. \OC_User::setUserId($this->getUniqueID());
  214. \OC::$server->getConfig()->setSystemValue('defaultapp', $defaultAppConfig);
  215. $this->assertEquals('http://localhost/' . $expectedPath, Dummy_OC_Util::getDefaultPageUrl());
  216. // restore old state
  217. \OC::$WEBROOT = $oldWebRoot;
  218. \OC::$server->getConfig()->setSystemValue('defaultapp', $oldDefaultApps);
  219. \OC_User::setUserId(null);
  220. }
  221. public function defaultAppsProvider() {
  222. return [
  223. // none specified, default to files
  224. [
  225. '',
  226. 'index.php/apps/files/',
  227. ['files'],
  228. ],
  229. // unexisting or inaccessible app specified, default to files
  230. [
  231. 'unexist',
  232. 'index.php/apps/files/',
  233. ['files'],
  234. ],
  235. // non-standard app
  236. [
  237. 'calendar',
  238. 'index.php/apps/calendar/',
  239. ['files', 'calendar'],
  240. ],
  241. // non-standard app with fallback
  242. [
  243. 'contacts,calendar',
  244. 'index.php/apps/calendar/',
  245. ['files', 'calendar'],
  246. ],
  247. ];
  248. }
  249. public function testGetDefaultPageUrlWithRedirectUrlWithoutFrontController() {
  250. putenv('front_controller_active=false');
  251. \OC::$server->getConfig()->deleteSystemValue('htaccess.IgnoreFrontController');
  252. $_REQUEST['redirect_url'] = 'myRedirectUrl.com';
  253. $this->assertSame('http://localhost'.\OC::$WEBROOT.'/myRedirectUrl.com', OC_Util::getDefaultPageUrl());
  254. }
  255. public function testGetDefaultPageUrlWithRedirectUrlRedirectBypassWithoutFrontController() {
  256. putenv('front_controller_active=false');
  257. \OC::$server->getConfig()->deleteSystemValue('htaccess.IgnoreFrontController');
  258. $_REQUEST['redirect_url'] = 'myRedirectUrl.com@foo.com:a';
  259. $this->assertSame('http://localhost'.\OC::$WEBROOT.'/index.php/apps/files/', OC_Util::getDefaultPageUrl());
  260. }
  261. public function testGetDefaultPageUrlWithRedirectUrlRedirectBypassWithFrontController() {
  262. putenv('front_controller_active=true');
  263. $_REQUEST['redirect_url'] = 'myRedirectUrl.com@foo.com:a';
  264. $this->assertSame('http://localhost'.\OC::$WEBROOT.'/apps/files/', OC_Util::getDefaultPageUrl());
  265. }
  266. public function testGetDefaultPageUrlWithRedirectUrlWithIgnoreFrontController() {
  267. putenv('front_controller_active=false');
  268. \OC::$server->getConfig()->setSystemValue('htaccess.IgnoreFrontController', true);
  269. $_REQUEST['redirect_url'] = 'myRedirectUrl.com@foo.com:a';
  270. $this->assertSame('http://localhost'.\OC::$WEBROOT.'/apps/files/', OC_Util::getDefaultPageUrl());
  271. }
  272. /**
  273. * Test needUpgrade() when the core version is increased
  274. */
  275. public function testNeedUpgradeCore() {
  276. $config = \OC::$server->getConfig();
  277. $oldConfigVersion = $config->getSystemValue('version', '0.0.0');
  278. $oldSessionVersion = \OC::$server->getSession()->get('OC_Version');
  279. $this->assertFalse(\OCP\Util::needUpgrade());
  280. $config->setSystemValue('version', '7.0.0.0');
  281. \OC::$server->getSession()->set('OC_Version', [7, 0, 0, 1]);
  282. self::invokePrivate(new \OCP\Util, 'needUpgradeCache', [null]);
  283. $this->assertTrue(\OCP\Util::needUpgrade());
  284. $config->setSystemValue('version', $oldConfigVersion);
  285. \OC::$server->getSession()->set('OC_Version', $oldSessionVersion);
  286. self::invokePrivate(new \OCP\Util, 'needUpgradeCache', [null]);
  287. $this->assertFalse(\OCP\Util::needUpgrade());
  288. }
  289. public function testCheckDataDirectoryValidity() {
  290. $dataDir = \OC::$server->getTempManager()->getTemporaryFolder();
  291. touch($dataDir . '/.ocdata');
  292. $errors = \OC_Util::checkDataDirectoryValidity($dataDir);
  293. $this->assertEmpty($errors);
  294. \OCP\Files::rmdirr($dataDir);
  295. $dataDir = \OC::$server->getTempManager()->getTemporaryFolder();
  296. // no touch
  297. $errors = \OC_Util::checkDataDirectoryValidity($dataDir);
  298. $this->assertNotEmpty($errors);
  299. \OCP\Files::rmdirr($dataDir);
  300. $errors = \OC_Util::checkDataDirectoryValidity('relative/path');
  301. $this->assertNotEmpty($errors);
  302. }
  303. protected function setUp(): void {
  304. parent::setUp();
  305. \OC_Util::$scripts = [];
  306. \OC_Util::$styles = [];
  307. }
  308. protected function tearDown(): void {
  309. parent::tearDown();
  310. \OC_Util::$scripts = [];
  311. \OC_Util::$styles = [];
  312. }
  313. public function testAddScript() {
  314. \OC_Util::addScript('core', 'myFancyJSFile1');
  315. \OC_Util::addScript('myApp', 'myFancyJSFile2');
  316. \OC_Util::addScript('core', 'myFancyJSFile0', true);
  317. \OC_Util::addScript('core', 'myFancyJSFile10', true);
  318. // add duplicate
  319. \OC_Util::addScript('core', 'myFancyJSFile1');
  320. $this->assertEquals([
  321. 'core/js/myFancyJSFile10',
  322. 'core/js/myFancyJSFile0',
  323. 'core/js/myFancyJSFile1',
  324. 'myApp/l10n/en',
  325. 'myApp/js/myFancyJSFile2',
  326. ], \OC_Util::$scripts);
  327. $this->assertEquals([], \OC_Util::$styles);
  328. }
  329. public function testAddVendorScript() {
  330. \OC_Util::addVendorScript('core', 'myFancyJSFile1');
  331. \OC_Util::addVendorScript('myApp', 'myFancyJSFile2');
  332. \OC_Util::addVendorScript('core', 'myFancyJSFile0', true);
  333. \OC_Util::addVendorScript('core', 'myFancyJSFile10', true);
  334. // add duplicate
  335. \OC_Util::addVendorScript('core', 'myFancyJSFile1');
  336. $this->assertEquals([
  337. 'core/vendor/myFancyJSFile10',
  338. 'core/vendor/myFancyJSFile0',
  339. 'core/vendor/myFancyJSFile1',
  340. 'myApp/vendor/myFancyJSFile2',
  341. ], \OC_Util::$scripts);
  342. $this->assertEquals([], \OC_Util::$styles);
  343. }
  344. public function testAddTranslations() {
  345. \OC_Util::addTranslations('appId', 'de');
  346. $this->assertEquals([
  347. 'appId/l10n/de'
  348. ], \OC_Util::$scripts);
  349. $this->assertEquals([], \OC_Util::$styles);
  350. }
  351. public function testAddStyle() {
  352. \OC_Util::addStyle('core', 'myFancyCSSFile1');
  353. \OC_Util::addStyle('myApp', 'myFancyCSSFile2');
  354. \OC_Util::addStyle('core', 'myFancyCSSFile0', true);
  355. \OC_Util::addStyle('core', 'myFancyCSSFile10', true);
  356. // add duplicate
  357. \OC_Util::addStyle('core', 'myFancyCSSFile1');
  358. $this->assertEquals([], \OC_Util::$scripts);
  359. $this->assertEquals([
  360. 'core/css/myFancyCSSFile10',
  361. 'core/css/myFancyCSSFile0',
  362. 'core/css/myFancyCSSFile1',
  363. 'myApp/css/myFancyCSSFile2',
  364. ], \OC_Util::$styles);
  365. }
  366. public function testAddVendorStyle() {
  367. \OC_Util::addVendorStyle('core', 'myFancyCSSFile1');
  368. \OC_Util::addVendorStyle('myApp', 'myFancyCSSFile2');
  369. \OC_Util::addVendorStyle('core', 'myFancyCSSFile0', true);
  370. \OC_Util::addVendorStyle('core', 'myFancyCSSFile10', true);
  371. // add duplicate
  372. \OC_Util::addVendorStyle('core', 'myFancyCSSFile1');
  373. $this->assertEquals([], \OC_Util::$scripts);
  374. $this->assertEquals([
  375. 'core/vendor/myFancyCSSFile10',
  376. 'core/vendor/myFancyCSSFile0',
  377. 'core/vendor/myFancyCSSFile1',
  378. 'myApp/vendor/myFancyCSSFile2',
  379. ], \OC_Util::$styles);
  380. }
  381. }
  382. /**
  383. * Dummy OC Util class to make it possible to override the app manager
  384. */
  385. class Dummy_OC_Util extends OC_Util {
  386. /**
  387. * @var \OCP\App\IAppManager
  388. */
  389. public static $appManager;
  390. protected static function getAppManager() {
  391. return self::$appManager;
  392. }
  393. }