CookieComponentTest.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  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.');
  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.');
  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. $result = $this->Controller->response->getCookie('Testing');
  298. $this->assertEquals($future->format('U'), $result['expire'], '', 3);
  299. unset($result['expire']);
  300. $this->assertEquals($expected, $result);
  301. }
  302. /**
  303. * test write with httpOnly cookies
  304. *
  305. * @return void
  306. */
  307. public function testWriteHttpOnly()
  308. {
  309. $this->Cookie->setConfig([
  310. 'httpOnly' => true,
  311. 'secure' => false
  312. ]);
  313. $this->Cookie->write('Testing', 'value', false);
  314. $expected = [
  315. 'name' => 'Testing',
  316. 'value' => 'value',
  317. 'expire' => (new Time('+10 seconds'))->format('U'),
  318. 'path' => '/',
  319. 'domain' => '',
  320. 'secure' => false,
  321. 'httpOnly' => true];
  322. $result = $this->Controller->response->getCookie('Testing');
  323. $this->assertEquals($expected, $result);
  324. }
  325. /**
  326. * Test writing multiple nested keys when some are encrypted.
  327. *
  328. * @return void
  329. */
  330. public function testWriteMulitMixedEncryption()
  331. {
  332. $this->Cookie->configKey('Open', 'encryption', false);
  333. $this->Cookie->configKey('Closed', 'encryption', 'aes');
  334. $this->Cookie->write([
  335. 'Closed.key' => 'secret',
  336. 'Open.key' => 'not secret',
  337. ]);
  338. $expected = [
  339. 'name' => 'Open',
  340. 'value' => '{"key":"not secret"}',
  341. 'path' => '/',
  342. 'domain' => '',
  343. 'secure' => false,
  344. 'httpOnly' => false
  345. ];
  346. $result = $this->Controller->response->getCookie('Open');
  347. unset($result['expire']);
  348. $this->assertEquals($expected, $result);
  349. $result = $this->Controller->response->getCookie('Closed');
  350. $this->assertContains('Q2FrZQ==.', $result['value']);
  351. }
  352. /**
  353. * Test writing with a custom encryption key using ConfigKey
  354. *
  355. * @return void
  356. */
  357. public function testWriteConfigKeyWithCustomEncryptionKey()
  358. {
  359. $name = 'sampleCookieTest';
  360. $value = 'some data';
  361. $encryption = 'aes';
  362. $prefix = 'Q2FrZQ==.';
  363. $key = 'justanotherencryptionkeyjustanotherencryptionkey';
  364. $this->Cookie->configKey($name, compact('key', 'encryption'));
  365. $this->Cookie->write($name, $value);
  366. $cookie = $this->Controller->response->getCookie($name);
  367. $this->assertEquals($value, Security::decrypt(base64_decode(substr($cookie['value'], strlen($prefix))), $key));
  368. }
  369. /**
  370. * Test reading with a custom encryption key using ConfigKey
  371. *
  372. * @return void
  373. */
  374. public function testReadConfigKeyWithCustomEncryptionKey()
  375. {
  376. $name = 'sampleCookieTest';
  377. $value = 'some data';
  378. $encryption = 'aes';
  379. $key = 'justanotherencryptionkeyjustanotherencryptionkey';
  380. $this->Cookie->configKey($name, compact('key', 'encryption'));
  381. $this->Cookie->write($name, $value);
  382. $this->assertEquals('some data', $this->Cookie->read($name));
  383. }
  384. /**
  385. * test delete with httpOnly
  386. *
  387. * @return void
  388. */
  389. public function testDeleteHttpOnly()
  390. {
  391. $this->Cookie->setConfig([
  392. 'httpOnly' => true,
  393. 'secure' => false
  394. ]);
  395. $this->Cookie->delete('Testing');
  396. $expected = [
  397. 'name' => 'Testing',
  398. 'value' => '',
  399. 'expire' => (new Time('now'))->format('U') - 42000,
  400. 'path' => '/',
  401. 'domain' => '',
  402. 'secure' => false,
  403. 'httpOnly' => true];
  404. $result = $this->Controller->response->getCookie('Testing');
  405. $this->assertEquals($expected, $result);
  406. }
  407. /**
  408. * test writing values that are not scalars
  409. *
  410. * @return void
  411. */
  412. public function testWriteArrayValues()
  413. {
  414. $this->Cookie->write('Testing', [1, 2, 3]);
  415. $expected = [
  416. 'name' => 'Testing',
  417. 'value' => '[1,2,3]',
  418. 'path' => '/',
  419. 'domain' => '',
  420. 'secure' => false,
  421. 'httpOnly' => false
  422. ];
  423. $result = $this->Controller->response->getCookie('Testing');
  424. $time = new Time('now');
  425. $this->assertWithinRange($time->format('U') + 10, $result['expire'], 1);
  426. unset($result['expire']);
  427. $this->assertEquals($expected, $result);
  428. }
  429. /**
  430. * Test that writing mixed arrays results in the correct data.
  431. *
  432. * @return void
  433. */
  434. public function testWriteMixedArray()
  435. {
  436. $this->Cookie->write('User', ['name' => 'mark'], false);
  437. $this->Cookie->write('User.email', 'mark@example.com', false);
  438. $expected = [
  439. 'name' => 'User',
  440. 'value' => '{"name":"mark","email":"mark@example.com"}',
  441. 'path' => '/',
  442. 'domain' => '',
  443. 'secure' => false,
  444. 'httpOnly' => false
  445. ];
  446. $result = $this->Controller->response->getCookie('User');
  447. unset($result['expire']);
  448. $this->assertEquals($expected, $result);
  449. $this->Cookie->write('User.email', 'mark@example.com', false);
  450. $this->Cookie->write('User', ['name' => 'mark'], false);
  451. $expected = [
  452. 'name' => 'User',
  453. 'value' => '{"name":"mark"}',
  454. 'path' => '/',
  455. 'domain' => '',
  456. 'secure' => false,
  457. 'httpOnly' => false
  458. ];
  459. $result = $this->Controller->response->getCookie('User');
  460. unset($result['expire']);
  461. $this->assertEquals($expected, $result);
  462. }
  463. /**
  464. * testDeleteCookieValue
  465. *
  466. * @return void
  467. */
  468. public function testDeleteCookieValue()
  469. {
  470. $this->_setCookieData();
  471. $this->Cookie->delete('Encrypted_multi_cookies.name');
  472. $data = $this->Cookie->read('Encrypted_multi_cookies');
  473. $expected = ['version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!'];
  474. $this->assertEquals($expected, $data);
  475. $this->Cookie->delete('Encrypted_array');
  476. $data = $this->Cookie->read('Encrypted_array');
  477. $this->assertNull($data);
  478. $this->Cookie->delete('Plain_multi_cookies.name');
  479. $data = $this->Cookie->read('Plain_multi_cookies');
  480. $expected = ['version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!'];
  481. $this->assertEquals($expected, $data);
  482. $this->Cookie->delete('Plain_array');
  483. $data = $this->Cookie->read('Plain_array');
  484. $this->assertNull($data);
  485. }
  486. /**
  487. * testReadingCookieArray
  488. *
  489. * @return void
  490. */
  491. public function testReadingCookieArray()
  492. {
  493. $this->_setCookieData();
  494. $data = $this->Cookie->read('Encrypted_array.name');
  495. $expected = 'CakePHP';
  496. $this->assertEquals($expected, $data);
  497. $data = $this->Cookie->read('Encrypted_array.version');
  498. $expected = '1.2.0.x';
  499. $this->assertEquals($expected, $data);
  500. $data = $this->Cookie->read('Encrypted_array.tag');
  501. $expected = 'CakePHP Rocks!';
  502. $this->assertEquals($expected, $data);
  503. $data = $this->Cookie->read('Encrypted_multi_cookies.name');
  504. $expected = 'CakePHP';
  505. $this->assertEquals($expected, $data);
  506. $data = $this->Cookie->read('Encrypted_multi_cookies.version');
  507. $expected = '1.2.0.x';
  508. $this->assertEquals($expected, $data);
  509. $data = $this->Cookie->read('Encrypted_multi_cookies.tag');
  510. $expected = 'CakePHP Rocks!';
  511. $this->assertEquals($expected, $data);
  512. $data = $this->Cookie->read('Plain_array.name');
  513. $expected = 'CakePHP';
  514. $this->assertEquals($expected, $data);
  515. $data = $this->Cookie->read('Plain_array.version');
  516. $expected = '1.2.0.x';
  517. $this->assertEquals($expected, $data);
  518. $data = $this->Cookie->read('Plain_array.tag');
  519. $expected = 'CakePHP Rocks!';
  520. $this->assertEquals($expected, $data);
  521. $data = $this->Cookie->read('Plain_multi_cookies.name');
  522. $expected = 'CakePHP';
  523. $this->assertEquals($expected, $data);
  524. $data = $this->Cookie->read('Plain_multi_cookies.version');
  525. $expected = '1.2.0.x';
  526. $this->assertEquals($expected, $data);
  527. $data = $this->Cookie->read('Plain_multi_cookies.tag');
  528. $expected = 'CakePHP Rocks!';
  529. $this->assertEquals($expected, $data);
  530. }
  531. /**
  532. * testReadingCookieDataOnStartup
  533. *
  534. * @return void
  535. */
  536. public function testReadingDataFromRequest()
  537. {
  538. $this->Cookie->configKey('Encrypted_array', 'encryption', 'aes');
  539. $this->Cookie->configKey('Encrypted_multi_cookies', 'encryption', 'aes');
  540. $data = $this->Cookie->read('Encrypted_array');
  541. $this->assertNull($data);
  542. $data = $this->Cookie->read('Encrypted_multi_cookies');
  543. $this->assertNull($data);
  544. $data = $this->Cookie->read('Plain_array');
  545. $this->assertNull($data);
  546. $data = $this->Cookie->read('Plain_multi_cookies');
  547. $this->assertNull($data);
  548. $this->Controller->request = $this->request->withCookieParams([
  549. 'Encrypted_array' => $this->_encrypt(['name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!']),
  550. 'Encrypted_multi_cookies' => [
  551. 'name' => $this->_encrypt('CakePHP'),
  552. 'version' => $this->_encrypt('1.2.0.x'),
  553. 'tag' => $this->_encrypt('CakePHP Rocks!')
  554. ],
  555. 'Plain_array' => '{"name":"CakePHP","version":"1.2.0.x","tag":"CakePHP Rocks!"}',
  556. 'Plain_multi_cookies' => [
  557. 'name' => 'CakePHP',
  558. 'version' => '1.2.0.x',
  559. 'tag' => 'CakePHP Rocks!'
  560. ]
  561. ]);
  562. $data = $this->Cookie->read('Encrypted_array');
  563. $expected = ['name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!'];
  564. $this->assertEquals($expected, $data);
  565. $data = $this->Cookie->read('Encrypted_multi_cookies');
  566. $expected = ['name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!'];
  567. $this->assertEquals($expected, $data);
  568. $data = $this->Cookie->read('Plain_array');
  569. $expected = ['name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!'];
  570. $this->assertEquals($expected, $data);
  571. $data = $this->Cookie->read('Plain_multi_cookies');
  572. $expected = ['name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!'];
  573. $this->assertEquals($expected, $data);
  574. }
  575. /**
  576. * testReadingMalformedEncryptedCookies
  577. *
  578. * @return void
  579. */
  580. public function testReadingMalformedEncryptedCookies()
  581. {
  582. $this->Cookie->configKey('Encrypted_empty', 'encryption', 'aes');
  583. $this->Cookie->configKey('Encrypted_wrong_prefix', 'encryption', 'aes');
  584. $this->Cookie->configKey('Encrypted_altered', 'encryption', 'aes');
  585. $this->Cookie->configKey('Encrypted_invalid_chars', 'encryption', 'aes');
  586. $encrypted = $this->_encrypt('secret data', 'aes');
  587. $this->Controller->request = $this->request->withCookieParams([
  588. 'Encrypted_empty' => '',
  589. 'Encrypted_wrong_prefix' => substr_replace($encrypted, 'foo', 0, 3),
  590. 'Encrypted_altered' => str_replace('M', 'A', $encrypted),
  591. 'Encrypted_invalid_chars' => str_replace('M', 'M#', $encrypted),
  592. ]);
  593. $data = $this->Cookie->read('Encrypted_empty');
  594. $this->assertSame('', $data);
  595. $data = $this->Cookie->read('Encrypted_wrong_prefix');
  596. $this->assertSame('', $data);
  597. $data = $this->Cookie->read('Encrypted_altered');
  598. $this->assertSame('', $data);
  599. $data = $this->Cookie->read('Encrypted_invalid_chars');
  600. $this->assertSame('', $data);
  601. }
  602. /**
  603. * Test Reading legacy cookie values.
  604. *
  605. * @return void
  606. */
  607. public function testReadLegacyCookieValue()
  608. {
  609. $this->Controller->request = $this->request->withCookieParams([
  610. 'Legacy' => ['value' => $this->_oldImplode([1, 2, 3])]
  611. ]);
  612. $result = $this->Cookie->read('Legacy.value');
  613. $expected = [1, 2, 3];
  614. $this->assertEquals($expected, $result);
  615. }
  616. /**
  617. * Test reading empty values.
  618. *
  619. * @return void
  620. */
  621. public function testReadEmpty()
  622. {
  623. $this->Controller->request = $this->request->withCookieParams([
  624. 'JSON' => '{"name":"value"}',
  625. 'Empty' => '',
  626. 'String' => '{"somewhat:"broken"}',
  627. 'Array' => '{}'
  628. ]);
  629. $this->assertEquals(['name' => 'value'], $this->Cookie->read('JSON'));
  630. $this->assertEquals('value', $this->Cookie->read('JSON.name'));
  631. $this->assertEquals('', $this->Cookie->read('Empty'));
  632. $this->assertEquals('{"somewhat:"broken"}', $this->Cookie->read('String'));
  633. $this->assertEquals([], $this->Cookie->read('Array'));
  634. }
  635. /**
  636. * testCheck method
  637. *
  638. * @return void
  639. */
  640. public function testCheck()
  641. {
  642. $this->Cookie->write('CookieComponentTestCase', 'value');
  643. $this->assertTrue($this->Cookie->check('CookieComponentTestCase'));
  644. $this->assertFalse($this->Cookie->check('NotExistingCookieComponentTestCase'));
  645. }
  646. /**
  647. * testCheckingSavedEmpty method
  648. *
  649. * @return void
  650. */
  651. public function testCheckingSavedEmpty()
  652. {
  653. $this->Cookie->write('CookieComponentTestCase', 0);
  654. $this->assertTrue($this->Cookie->check('CookieComponentTestCase'));
  655. $this->Cookie->write('CookieComponentTestCase', '0');
  656. $this->assertTrue($this->Cookie->check('CookieComponentTestCase'));
  657. }
  658. /**
  659. * testCheckKeyWithSpaces method
  660. *
  661. * @return void
  662. */
  663. public function testCheckKeyWithSpaces()
  664. {
  665. $this->Cookie->write('CookieComponent Test', 'test');
  666. $this->assertTrue($this->Cookie->check('CookieComponent Test'));
  667. $this->Cookie->delete('CookieComponent Test');
  668. $this->Cookie->write('CookieComponent Test.Test Case', 'test');
  669. $this->assertTrue($this->Cookie->check('CookieComponent Test.Test Case'));
  670. }
  671. /**
  672. * testCheckEmpty
  673. *
  674. * @return void
  675. */
  676. public function testCheckEmpty()
  677. {
  678. $this->assertFalse($this->Cookie->check());
  679. }
  680. /**
  681. * test that deleting a top level keys kills the child elements too.
  682. *
  683. * @return void
  684. */
  685. public function testDeleteRemovesChildren()
  686. {
  687. $this->Controller->request = $this->request->withCookieParams([
  688. 'User' => ['email' => 'example@example.com', 'name' => 'mark'],
  689. 'other' => 'value'
  690. ]);
  691. $this->assertEquals('mark', $this->Cookie->read('User.name'));
  692. $this->Cookie->delete('User');
  693. $this->assertNull($this->Cookie->read('User.email'));
  694. $this->assertNull($this->Cookie->read('User.name'));
  695. $result = $this->Controller->response->getCookie('User');
  696. $this->assertEquals('', $result['value']);
  697. $this->assertLessThan(time(), $result['expire']);
  698. }
  699. /**
  700. * Test deleting recursively with keys that don't exist.
  701. *
  702. * @return void
  703. */
  704. public function testDeleteChildrenNotExist()
  705. {
  706. $this->assertNull($this->Cookie->delete('NotFound'));
  707. $this->assertNull($this->Cookie->delete('Not.Found'));
  708. }
  709. /**
  710. * Helper method for generating old style encoded cookie values.
  711. *
  712. * @param array $array
  713. * @return string
  714. */
  715. protected function _oldImplode(array $array)
  716. {
  717. $string = '';
  718. foreach ($array as $key => $value) {
  719. $string .= ',' . $key . '|' . $value;
  720. }
  721. return substr($string, 1);
  722. }
  723. /**
  724. * Implode method to keep keys are multidimensional arrays
  725. *
  726. * @param array $array Map of key and values
  727. * @return string String in the form key1|value1,key2|value2
  728. */
  729. protected function _implode(array $array)
  730. {
  731. return json_encode($array);
  732. }
  733. /**
  734. * encrypt method
  735. *
  736. * @param array|string $value
  737. * @return string
  738. */
  739. protected function _encrypt($value)
  740. {
  741. if (is_array($value)) {
  742. $value = $this->_implode($value);
  743. }
  744. return 'Q2FrZQ==.' . base64_encode(Security::encrypt($value, $this->Cookie->getConfig('key')));
  745. }
  746. }