CookieComponentTest.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11. * @link https://cakephp.org CakePHP(tm) Project
  12. * @since 1.2.0
  13. * @license https://opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Test\TestCase\Controller\Component;
  16. use Cake\Controller\ComponentRegistry;
  17. use Cake\Controller\Component\CookieComponent;
  18. use Cake\Http\Response;
  19. use Cake\Http\ServerRequest;
  20. use Cake\I18n\Time;
  21. use Cake\TestSuite\TestCase;
  22. use Cake\Utility\Security;
  23. /**
  24. * CookieComponentTest class
  25. */
  26. class CookieComponentTest extends TestCase
  27. {
  28. /**
  29. * @var \Cake\Controller\Component\CookieComponent
  30. */
  31. protected $Cookie;
  32. /**
  33. * start
  34. *
  35. * @return void
  36. */
  37. public function setUp()
  38. {
  39. parent::setUp();
  40. $controller = $this->getMockBuilder('Cake\Controller\Controller')
  41. ->setMethods(['redirect'])
  42. ->setConstructorArgs([new ServerRequest(), new Response()])
  43. ->getMock();
  44. $controller->loadComponent('Cookie');
  45. $this->Controller = $controller;
  46. $this->Cookie = $controller->Cookie;
  47. $this->request = $controller->request;
  48. $this->Cookie->setConfig([
  49. 'expires' => '+10 seconds',
  50. 'path' => '/',
  51. 'domain' => '',
  52. 'secure' => false,
  53. 'key' => 'somerandomhaskeysomerandomhaskey',
  54. 'encryption' => false,
  55. ]);
  56. }
  57. /**
  58. * Test setting config per key.
  59. *
  60. * @return void
  61. */
  62. public function testConfigKey()
  63. {
  64. $this->Cookie->configKey('User', 'expires', '+3 days');
  65. $result = $this->Cookie->configKey('User');
  66. $expected = [
  67. 'expires' => '+3 days',
  68. 'path' => '/',
  69. 'domain' => '',
  70. 'key' => 'somerandomhaskeysomerandomhaskey',
  71. 'secure' => false,
  72. 'httpOnly' => false,
  73. 'encryption' => false,
  74. ];
  75. $this->assertEquals($expected, $result);
  76. }
  77. /**
  78. * Test setting config per key.
  79. *
  80. * @return void
  81. */
  82. public function testConfigKeyArray()
  83. {
  84. $this->Cookie->configKey('User', [
  85. 'expires' => '+3 days',
  86. 'path' => '/shop',
  87. ]);
  88. $result = $this->Cookie->configKey('User');
  89. $expected = [
  90. 'expires' => '+3 days',
  91. 'path' => '/shop',
  92. 'domain' => '',
  93. 'key' => 'somerandomhaskeysomerandomhaskey',
  94. 'secure' => false,
  95. 'httpOnly' => false,
  96. 'encryption' => false,
  97. ];
  98. $this->assertEquals($expected, $result);
  99. }
  100. /**
  101. * Test backwards compatibility with settings that use type juggling.
  102. *
  103. * @return void
  104. */
  105. public function testSettingsCompatibility()
  106. {
  107. $this->Cookie->setConfig([
  108. 'expires' => '+10 seconds',
  109. 'path' => '/',
  110. 'domain' => '',
  111. 'secure' => 0,
  112. 'key' => 'somerandomhaskeysomerandomhaskey',
  113. 'encryption' => 0,
  114. ]);
  115. $this->Cookie->write('key', 'value');
  116. $this->assertSame('value', $this->Cookie->read('key'));
  117. }
  118. /**
  119. * sets up some default cookie data.
  120. *
  121. * @return void
  122. */
  123. protected function _setCookieData()
  124. {
  125. $this->Cookie->write(['Encrypted_array' => ['name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!']]);
  126. $this->Cookie->write(['Encrypted_multi_cookies.name' => 'CakePHP']);
  127. $this->Cookie->write(['Encrypted_multi_cookies.version' => '1.2.0.x']);
  128. $this->Cookie->write(['Encrypted_multi_cookies.tag' => 'CakePHP Rocks!']);
  129. $this->Cookie->write(['Plain_array' => ['name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!']], null, false);
  130. $this->Cookie->write(['Plain_multi_cookies.name' => 'CakePHP'], null, false);
  131. $this->Cookie->write(['Plain_multi_cookies.version' => '1.2.0.x'], null, false);
  132. $this->Cookie->write(['Plain_multi_cookies.tag' => 'CakePHP Rocks!'], null, false);
  133. }
  134. /**
  135. * test that initialize sets settings from components array
  136. *
  137. * @return void
  138. */
  139. public function testSettings()
  140. {
  141. $settings = [
  142. 'time' => '5 days',
  143. 'path' => '/',
  144. ];
  145. $Cookie = new CookieComponent(new ComponentRegistry(), $settings);
  146. $this->assertEquals($Cookie->getConfig('time'), $settings['time']);
  147. $this->assertEquals($Cookie->getConfig('path'), $settings['path']);
  148. }
  149. /**
  150. * Test read when an invalid cipher is configured.
  151. *
  152. * @return void
  153. */
  154. public function testReadInvalidCipher()
  155. {
  156. $this->expectException(\RuntimeException::class);
  157. $this->expectExceptionMessage('Invalid encryption cipher. Must be one of aes, rijndael or false.');
  158. $this->Controller->request = $this->request->withCookieParams([
  159. 'Test' => $this->_encrypt('value'),
  160. ]);
  161. $this->Cookie->setConfig('encryption', 'derp');
  162. $this->Cookie->read('Test');
  163. }
  164. /**
  165. * testReadEncryptedCookieData
  166. *
  167. * @return void
  168. */
  169. public function testReadEncryptedCookieData()
  170. {
  171. $this->_setCookieData();
  172. $data = $this->Cookie->read('Encrypted_array');
  173. $expected = ['name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!'];
  174. $this->assertEquals($expected, $data);
  175. $data = $this->Cookie->read('Encrypted_multi_cookies');
  176. $expected = ['name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!'];
  177. $this->assertEquals($expected, $data);
  178. }
  179. /**
  180. * testReadPlainCookieData
  181. *
  182. * @return void
  183. */
  184. public function testReadPlainCookieData()
  185. {
  186. $this->_setCookieData();
  187. $data = $this->Cookie->read('Plain_array');
  188. $expected = ['name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!'];
  189. $this->assertEquals($expected, $data);
  190. $data = $this->Cookie->read('Plain_multi_cookies');
  191. $expected = ['name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!'];
  192. $this->assertEquals($expected, $data);
  193. }
  194. /**
  195. * test read() after switching the cookie name.
  196. *
  197. * @return void
  198. */
  199. public function testReadMultipleNames()
  200. {
  201. $this->Controller->request = $this->request->withCookieParams([
  202. 'CakeCookie' => [
  203. 'key' => 'value',
  204. ],
  205. 'OtherCookie' => [
  206. 'key' => 'other value',
  207. ],
  208. ]);
  209. $this->assertEquals('value', $this->Cookie->read('CakeCookie.key'));
  210. $this->assertEquals(['key' => 'value'], $this->Cookie->read('CakeCookie'));
  211. $this->assertEquals('other value', $this->Cookie->read('OtherCookie.key'));
  212. }
  213. /**
  214. * test a simple write()
  215. *
  216. * @return void
  217. */
  218. public function testWriteSimple()
  219. {
  220. $this->Cookie->write('Testing', 'value');
  221. $result = $this->Cookie->read('Testing');
  222. $this->assertEquals('value', $result);
  223. }
  224. /**
  225. * Test write when an invalid cipher is configured.
  226. *
  227. * @return void
  228. */
  229. public function testWriteInvalidCipher()
  230. {
  231. $this->expectException(\RuntimeException::class);
  232. $this->expectExceptionMessage('Invalid encryption cipher. Must be one of aes, rijndael or false.');
  233. $this->Cookie->setConfig('encryption', 'derp');
  234. $this->Cookie->write('Test', 'nope');
  235. }
  236. /**
  237. * Test writes don't omit request data from being read.
  238. *
  239. * @return void
  240. */
  241. public function testWriteThanRead()
  242. {
  243. $this->Controller->request = $this->request->withCookieParams([
  244. 'User' => ['name' => 'mark'],
  245. ]);
  246. $this->Cookie->write('Testing', 'value');
  247. $this->assertEquals('mark', $this->Cookie->read('User.name'));
  248. }
  249. /**
  250. * test write() encrypted data with falsey value
  251. *
  252. * @return void
  253. */
  254. public function testWriteWithFalseyValue()
  255. {
  256. $this->Cookie->setConfig([
  257. 'encryption' => 'aes',
  258. 'key' => 'qSI232qs*&sXOw!adre@34SAv!@*(XSL#$%)asGb$@11~_+!@#HKis~#^',
  259. ]);
  260. $this->Cookie->write('Testing');
  261. $result = $this->Cookie->read('Testing');
  262. $this->assertNull($result);
  263. $this->Cookie->write('Testing', '');
  264. $result = $this->Cookie->read('Testing');
  265. $this->assertEquals('', $result);
  266. $this->Cookie->write('Testing', false);
  267. $result = $this->Cookie->read('Testing');
  268. $this->assertFalse($result);
  269. $this->Cookie->write('Testing', 1);
  270. $result = $this->Cookie->read('Testing');
  271. $this->assertEquals(1, $result);
  272. $this->Cookie->write('Testing', '0');
  273. $result = $this->Cookie->read('Testing');
  274. $this->assertSame('0', $result);
  275. $this->Cookie->write('Testing', 0);
  276. $result = $this->Cookie->read('Testing');
  277. $this->assertSame(0, $result);
  278. }
  279. /**
  280. * test write with distant future cookies
  281. *
  282. * @return void
  283. */
  284. public function testWriteFarFuture()
  285. {
  286. $this->Cookie->configKey('Testing', 'expires', '+90 years');
  287. $this->Cookie->write('Testing', 'value');
  288. $future = new Time('now');
  289. $future = $future->modify('+90 years');
  290. $expected = [
  291. 'name' => 'Testing',
  292. 'value' => 'value',
  293. 'path' => '/',
  294. 'domain' => '',
  295. 'secure' => false,
  296. 'httpOnly' => false,
  297. 'samesite' => null,
  298. ];
  299. $result = $this->Controller->response->getCookie('Testing');
  300. $this->assertEquals($future->format('U'), $result['expire'], '', 3);
  301. unset($result['expire']);
  302. $this->assertEquals($expected, $result);
  303. }
  304. /**
  305. * test write with httpOnly cookies
  306. *
  307. * @return void
  308. */
  309. public function testWriteHttpOnly()
  310. {
  311. $this->Cookie->setConfig([
  312. 'httpOnly' => true,
  313. 'secure' => false,
  314. ]);
  315. $this->Cookie->write('Testing', 'value', false);
  316. $expected = [
  317. 'name' => 'Testing',
  318. 'value' => 'value',
  319. 'expire' => (new Time('+10 seconds'))->format('U'),
  320. 'path' => '/',
  321. 'domain' => '',
  322. 'secure' => false,
  323. 'httpOnly' => true,
  324. 'samesite' => null,
  325. ];
  326. $result = $this->Controller->response->getCookie('Testing');
  327. $this->assertEquals($expected, $result);
  328. }
  329. /**
  330. * Test writing multiple nested keys when some are encrypted.
  331. *
  332. * @return void
  333. */
  334. public function testWriteMulitMixedEncryption()
  335. {
  336. $this->Cookie->configKey('Open', 'encryption', false);
  337. $this->Cookie->configKey('Closed', 'encryption', 'aes');
  338. $this->Cookie->write([
  339. 'Closed.key' => 'secret',
  340. 'Open.key' => 'not secret',
  341. ]);
  342. $expected = [
  343. 'name' => 'Open',
  344. 'value' => '{"key":"not secret"}',
  345. 'path' => '/',
  346. 'domain' => '',
  347. 'secure' => false,
  348. 'httpOnly' => false,
  349. 'samesite' => null,
  350. ];
  351. $result = $this->Controller->response->getCookie('Open');
  352. unset($result['expire']);
  353. $this->assertEquals($expected, $result);
  354. $result = $this->Controller->response->getCookie('Closed');
  355. $this->assertContains('Q2FrZQ==.', $result['value']);
  356. }
  357. /**
  358. * Test writing with a custom encryption key using ConfigKey
  359. *
  360. * @return void
  361. */
  362. public function testWriteConfigKeyWithCustomEncryptionKey()
  363. {
  364. $name = 'sampleCookieTest';
  365. $value = 'some data';
  366. $encryption = 'aes';
  367. $prefix = 'Q2FrZQ==.';
  368. $key = 'justanotherencryptionkeyjustanotherencryptionkey';
  369. $this->Cookie->configKey($name, compact('key', 'encryption'));
  370. $this->Cookie->write($name, $value);
  371. $cookie = $this->Controller->response->getCookie($name);
  372. $this->assertEquals($value, Security::decrypt(base64_decode(substr($cookie['value'], strlen($prefix))), $key));
  373. }
  374. /**
  375. * Test reading with a custom encryption key using ConfigKey
  376. *
  377. * @return void
  378. */
  379. public function testReadConfigKeyWithCustomEncryptionKey()
  380. {
  381. $name = 'sampleCookieTest';
  382. $value = 'some data';
  383. $encryption = 'aes';
  384. $key = 'justanotherencryptionkeyjustanotherencryptionkey';
  385. $this->Cookie->configKey($name, compact('key', 'encryption'));
  386. $this->Cookie->write($name, $value);
  387. $this->assertEquals('some data', $this->Cookie->read($name));
  388. }
  389. /**
  390. * test delete with httpOnly
  391. *
  392. * @return void
  393. */
  394. public function testDeleteHttpOnly()
  395. {
  396. $this->Cookie->setConfig([
  397. 'httpOnly' => true,
  398. 'secure' => false,
  399. ]);
  400. $this->Cookie->delete('Testing');
  401. $expected = [
  402. 'name' => 'Testing',
  403. 'value' => '',
  404. 'expire' => '1',
  405. 'path' => '/',
  406. 'domain' => '',
  407. 'secure' => false,
  408. 'httpOnly' => true,
  409. 'samesite' => null,
  410. ];
  411. $result = $this->Controller->response->getCookie('Testing');
  412. $this->assertEquals($expected, $result);
  413. }
  414. /**
  415. * test writing values that are not scalars
  416. *
  417. * @return void
  418. */
  419. public function testWriteArrayValues()
  420. {
  421. $this->Cookie->write('Testing', [1, 2, 3]);
  422. $expected = [
  423. 'name' => 'Testing',
  424. 'value' => '[1,2,3]',
  425. 'path' => '/',
  426. 'domain' => '',
  427. 'secure' => false,
  428. 'httpOnly' => false,
  429. 'samesite' => null,
  430. ];
  431. $result = $this->Controller->response->getCookie('Testing');
  432. $time = new Time('now');
  433. $this->assertWithinRange($time->format('U') + 10, $result['expire'], 1);
  434. unset($result['expire']);
  435. $this->assertEquals($expected, $result);
  436. }
  437. /**
  438. * Test that writing mixed arrays results in the correct data.
  439. *
  440. * @return void
  441. */
  442. public function testWriteMixedArray()
  443. {
  444. $this->Cookie->write('User', ['name' => 'mark'], false);
  445. $this->Cookie->write('User.email', 'mark@example.com', false);
  446. $expected = [
  447. 'name' => 'User',
  448. 'value' => '{"name":"mark","email":"mark@example.com"}',
  449. 'path' => '/',
  450. 'domain' => '',
  451. 'secure' => false,
  452. 'httpOnly' => false,
  453. 'samesite' => null,
  454. ];
  455. $result = $this->Controller->response->getCookie('User');
  456. unset($result['expire']);
  457. $this->assertEquals($expected, $result);
  458. $this->Cookie->write('User.email', 'mark@example.com', false);
  459. $this->Cookie->write('User', ['name' => 'mark'], false);
  460. $expected = [
  461. 'name' => 'User',
  462. 'value' => '{"name":"mark"}',
  463. 'path' => '/',
  464. 'domain' => '',
  465. 'secure' => false,
  466. 'httpOnly' => false,
  467. 'samesite' => null,
  468. ];
  469. $result = $this->Controller->response->getCookie('User');
  470. unset($result['expire']);
  471. $this->assertEquals($expected, $result);
  472. }
  473. /**
  474. * testDeleteCookieValue
  475. *
  476. * @return void
  477. */
  478. public function testDeleteCookieValue()
  479. {
  480. $this->_setCookieData();
  481. $this->Cookie->delete('Encrypted_multi_cookies.name');
  482. $data = $this->Cookie->read('Encrypted_multi_cookies');
  483. $expected = ['version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!'];
  484. $this->assertEquals($expected, $data);
  485. $this->Cookie->delete('Encrypted_array');
  486. $data = $this->Cookie->read('Encrypted_array');
  487. $this->assertNull($data);
  488. $this->Cookie->delete('Plain_multi_cookies.name');
  489. $data = $this->Cookie->read('Plain_multi_cookies');
  490. $expected = ['version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!'];
  491. $this->assertEquals($expected, $data);
  492. $this->Cookie->delete('Plain_array');
  493. $data = $this->Cookie->read('Plain_array');
  494. $this->assertNull($data);
  495. }
  496. /**
  497. * testReadingCookieArray
  498. *
  499. * @return void
  500. */
  501. public function testReadingCookieArray()
  502. {
  503. $this->_setCookieData();
  504. $data = $this->Cookie->read('Encrypted_array.name');
  505. $expected = 'CakePHP';
  506. $this->assertEquals($expected, $data);
  507. $data = $this->Cookie->read('Encrypted_array.version');
  508. $expected = '1.2.0.x';
  509. $this->assertEquals($expected, $data);
  510. $data = $this->Cookie->read('Encrypted_array.tag');
  511. $expected = 'CakePHP Rocks!';
  512. $this->assertEquals($expected, $data);
  513. $data = $this->Cookie->read('Encrypted_multi_cookies.name');
  514. $expected = 'CakePHP';
  515. $this->assertEquals($expected, $data);
  516. $data = $this->Cookie->read('Encrypted_multi_cookies.version');
  517. $expected = '1.2.0.x';
  518. $this->assertEquals($expected, $data);
  519. $data = $this->Cookie->read('Encrypted_multi_cookies.tag');
  520. $expected = 'CakePHP Rocks!';
  521. $this->assertEquals($expected, $data);
  522. $data = $this->Cookie->read('Plain_array.name');
  523. $expected = 'CakePHP';
  524. $this->assertEquals($expected, $data);
  525. $data = $this->Cookie->read('Plain_array.version');
  526. $expected = '1.2.0.x';
  527. $this->assertEquals($expected, $data);
  528. $data = $this->Cookie->read('Plain_array.tag');
  529. $expected = 'CakePHP Rocks!';
  530. $this->assertEquals($expected, $data);
  531. $data = $this->Cookie->read('Plain_multi_cookies.name');
  532. $expected = 'CakePHP';
  533. $this->assertEquals($expected, $data);
  534. $data = $this->Cookie->read('Plain_multi_cookies.version');
  535. $expected = '1.2.0.x';
  536. $this->assertEquals($expected, $data);
  537. $data = $this->Cookie->read('Plain_multi_cookies.tag');
  538. $expected = 'CakePHP Rocks!';
  539. $this->assertEquals($expected, $data);
  540. }
  541. /**
  542. * testReadingCookieDataOnStartup
  543. *
  544. * @return void
  545. */
  546. public function testReadingDataFromRequest()
  547. {
  548. $this->Cookie->configKey('Encrypted_array', 'encryption', 'aes');
  549. $this->Cookie->configKey('Encrypted_multi_cookies', 'encryption', 'aes');
  550. $data = $this->Cookie->read('Encrypted_array');
  551. $this->assertNull($data);
  552. $data = $this->Cookie->read('Encrypted_multi_cookies');
  553. $this->assertNull($data);
  554. $data = $this->Cookie->read('Plain_array');
  555. $this->assertNull($data);
  556. $data = $this->Cookie->read('Plain_multi_cookies');
  557. $this->assertNull($data);
  558. $this->Controller->request = $this->request->withCookieParams([
  559. 'Encrypted_array' => $this->_encrypt(['name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!']),
  560. 'Encrypted_multi_cookies' => [
  561. 'name' => $this->_encrypt('CakePHP'),
  562. 'version' => $this->_encrypt('1.2.0.x'),
  563. 'tag' => $this->_encrypt('CakePHP Rocks!'),
  564. ],
  565. 'Plain_array' => '{"name":"CakePHP","version":"1.2.0.x","tag":"CakePHP Rocks!"}',
  566. 'Plain_multi_cookies' => [
  567. 'name' => 'CakePHP',
  568. 'version' => '1.2.0.x',
  569. 'tag' => 'CakePHP Rocks!',
  570. ],
  571. ]);
  572. $data = $this->Cookie->read('Encrypted_array');
  573. $expected = ['name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!'];
  574. $this->assertEquals($expected, $data);
  575. $data = $this->Cookie->read('Encrypted_multi_cookies');
  576. $expected = ['name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!'];
  577. $this->assertEquals($expected, $data);
  578. $data = $this->Cookie->read('Plain_array');
  579. $expected = ['name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!'];
  580. $this->assertEquals($expected, $data);
  581. $data = $this->Cookie->read('Plain_multi_cookies');
  582. $expected = ['name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!'];
  583. $this->assertEquals($expected, $data);
  584. }
  585. /**
  586. * testReadingMalformedEncryptedCookies
  587. *
  588. * @return void
  589. */
  590. public function testReadingMalformedEncryptedCookies()
  591. {
  592. $this->Cookie->configKey('Encrypted_empty', 'encryption', 'aes');
  593. $this->Cookie->configKey('Encrypted_wrong_prefix', 'encryption', 'aes');
  594. $this->Cookie->configKey('Encrypted_altered', 'encryption', 'aes');
  595. $this->Cookie->configKey('Encrypted_invalid_chars', 'encryption', 'aes');
  596. $encrypted = $this->_encrypt('secret data', 'aes');
  597. $this->Controller->request = $this->request->withCookieParams([
  598. 'Encrypted_empty' => '',
  599. 'Encrypted_wrong_prefix' => substr_replace($encrypted, 'foo', 0, 3),
  600. 'Encrypted_altered' => str_replace('M', 'A', $encrypted),
  601. 'Encrypted_invalid_chars' => str_replace('M', 'M#', $encrypted),
  602. ]);
  603. $data = $this->Cookie->read('Encrypted_empty');
  604. $this->assertSame('', $data);
  605. $data = $this->Cookie->read('Encrypted_wrong_prefix');
  606. $this->assertSame('', $data);
  607. $data = $this->Cookie->read('Encrypted_altered');
  608. $this->assertSame('', $data);
  609. $data = $this->Cookie->read('Encrypted_invalid_chars');
  610. $this->assertSame('', $data);
  611. }
  612. /**
  613. * Test Reading legacy cookie values.
  614. *
  615. * @return void
  616. */
  617. public function testReadLegacyCookieValue()
  618. {
  619. $this->Controller->request = $this->request->withCookieParams([
  620. 'Legacy' => ['value' => $this->_oldImplode([1, 2, 3])],
  621. ]);
  622. $result = $this->Cookie->read('Legacy.value');
  623. $expected = [1, 2, 3];
  624. $this->assertEquals($expected, $result);
  625. }
  626. /**
  627. * Test reading empty values.
  628. *
  629. * @return void
  630. */
  631. public function testReadEmpty()
  632. {
  633. $this->Controller->request = $this->request->withCookieParams([
  634. 'JSON' => '{"name":"value"}',
  635. 'Empty' => '',
  636. 'String' => '{"somewhat:"broken"}',
  637. 'Array' => '{}',
  638. ]);
  639. $this->assertEquals(['name' => 'value'], $this->Cookie->read('JSON'));
  640. $this->assertEquals('value', $this->Cookie->read('JSON.name'));
  641. $this->assertEquals('', $this->Cookie->read('Empty'));
  642. $this->assertEquals('{"somewhat:"broken"}', $this->Cookie->read('String'));
  643. $this->assertEquals([], $this->Cookie->read('Array'));
  644. }
  645. /**
  646. * testCheck method
  647. *
  648. * @return void
  649. */
  650. public function testCheck()
  651. {
  652. $this->Cookie->write('CookieComponentTestCase', 'value');
  653. $this->assertTrue($this->Cookie->check('CookieComponentTestCase'));
  654. $this->assertFalse($this->Cookie->check('NotExistingCookieComponentTestCase'));
  655. }
  656. /**
  657. * testCheckingSavedEmpty method
  658. *
  659. * @return void
  660. */
  661. public function testCheckingSavedEmpty()
  662. {
  663. $this->Cookie->write('CookieComponentTestCase', 0);
  664. $this->assertTrue($this->Cookie->check('CookieComponentTestCase'));
  665. $this->Cookie->write('CookieComponentTestCase', '0');
  666. $this->assertTrue($this->Cookie->check('CookieComponentTestCase'));
  667. }
  668. /**
  669. * testCheckKeyWithSpaces method
  670. *
  671. * @return void
  672. */
  673. public function testCheckKeyWithSpaces()
  674. {
  675. $this->Cookie->write('CookieComponent Test', 'test');
  676. $this->assertTrue($this->Cookie->check('CookieComponent Test'));
  677. $this->Cookie->delete('CookieComponent Test');
  678. $this->Cookie->write('CookieComponent Test.Test Case', 'test');
  679. $this->assertTrue($this->Cookie->check('CookieComponent Test.Test Case'));
  680. }
  681. /**
  682. * testCheckEmpty
  683. *
  684. * @return void
  685. */
  686. public function testCheckEmpty()
  687. {
  688. $this->assertFalse($this->Cookie->check());
  689. }
  690. /**
  691. * test that deleting a top level keys kills the child elements too.
  692. *
  693. * @return void
  694. */
  695. public function testDeleteRemovesChildren()
  696. {
  697. $this->Controller->request = $this->request->withCookieParams([
  698. 'User' => ['email' => 'example@example.com', 'name' => 'mark'],
  699. 'other' => 'value',
  700. ]);
  701. $this->assertEquals('mark', $this->Cookie->read('User.name'));
  702. $this->Cookie->delete('User');
  703. $this->assertNull($this->Cookie->read('User.email'));
  704. $this->assertNull($this->Cookie->read('User.name'));
  705. $result = $this->Controller->response->getCookie('User');
  706. $this->assertEquals('', $result['value']);
  707. $this->assertLessThan(time(), $result['expire']);
  708. }
  709. /**
  710. * Test deleting recursively with keys that don't exist.
  711. *
  712. * @return void
  713. */
  714. public function testDeleteChildrenNotExist()
  715. {
  716. $this->assertNull($this->Cookie->delete('NotFound'));
  717. $this->assertNull($this->Cookie->delete('Not.Found'));
  718. }
  719. /**
  720. * Helper method for generating old style encoded cookie values.
  721. *
  722. * @param array $array
  723. * @return string
  724. */
  725. protected function _oldImplode(array $array)
  726. {
  727. $string = '';
  728. foreach ($array as $key => $value) {
  729. $string .= ',' . $key . '|' . $value;
  730. }
  731. return substr($string, 1);
  732. }
  733. /**
  734. * Implode method to keep keys are multidimensional arrays
  735. *
  736. * @param array $array Map of key and values
  737. * @return string String in the form key1|value1,key2|value2
  738. */
  739. protected function _implode(array $array)
  740. {
  741. return json_encode($array);
  742. }
  743. /**
  744. * encrypt method
  745. *
  746. * @param array|string $value
  747. * @return string
  748. */
  749. protected function _encrypt($value)
  750. {
  751. if (is_array($value)) {
  752. $value = $this->_implode($value);
  753. }
  754. return 'Q2FrZQ==.' . base64_encode(Security::encrypt($value, $this->Cookie->getConfig('key')));
  755. }
  756. }