UtilTest.php 13 KB

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