ControllerTest.php 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891
  1. <?php
  2. use PrivateBin\Controller;
  3. use PrivateBin\Data\Filesystem;
  4. use PrivateBin\Persistence\ServerSalt;
  5. use PrivateBin\Persistence\TrafficLimiter;
  6. class ControllerTest extends PHPUnit_Framework_TestCase
  7. {
  8. protected $_model;
  9. protected $_path;
  10. public function setUp()
  11. {
  12. /* Setup Routine */
  13. $this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
  14. $this->_model = Filesystem::getInstance(array('dir' => $this->_path));
  15. $this->reset();
  16. }
  17. public function tearDown()
  18. {
  19. /* Tear Down Routine */
  20. unlink(CONF);
  21. Helper::confRestore();
  22. Helper::rmDir($this->_path);
  23. }
  24. public function reset()
  25. {
  26. $_POST = array();
  27. $_GET = array();
  28. $_SERVER = array();
  29. if ($this->_model->exists(Helper::getPasteId())) {
  30. $this->_model->delete(Helper::getPasteId());
  31. }
  32. $options = parse_ini_file(CONF_SAMPLE, true);
  33. $options['purge']['dir'] = $this->_path;
  34. $options['traffic']['dir'] = $this->_path;
  35. $options['model_options']['dir'] = $this->_path;
  36. Helper::createIniFile(CONF, $options);
  37. ServerSalt::setPath($this->_path);
  38. }
  39. /**
  40. * @runInSeparateProcess
  41. */
  42. public function testView()
  43. {
  44. ob_start();
  45. new Controller;
  46. $content = ob_get_contents();
  47. ob_end_clean();
  48. $this->assertContains(
  49. '<title>PrivateBin</title>',
  50. $content,
  51. 'outputs title correctly'
  52. );
  53. $this->assertNotContains(
  54. 'id="shortenbutton"',
  55. $content,
  56. 'doesn\'t output shortener button'
  57. );
  58. }
  59. /**
  60. * @runInSeparateProcess
  61. */
  62. public function testViewLanguageSelection()
  63. {
  64. $options = parse_ini_file(CONF, true);
  65. $options['main']['languageselection'] = true;
  66. Helper::createIniFile(CONF, $options);
  67. $_COOKIE['lang'] = 'de';
  68. ob_start();
  69. new Controller;
  70. $content = ob_get_contents();
  71. ob_end_clean();
  72. $this->assertContains(
  73. '<title>PrivateBin</title>',
  74. $content,
  75. 'outputs title correctly'
  76. );
  77. }
  78. /**
  79. * @runInSeparateProcess
  80. */
  81. public function testViewForceLanguageDefault()
  82. {
  83. $options = parse_ini_file(CONF, true);
  84. $options['main']['languageselection'] = false;
  85. $options['main']['languagedefault'] = 'fr';
  86. Helper::createIniFile(CONF, $options);
  87. $_COOKIE['lang'] = 'de';
  88. ob_start();
  89. new Controller;
  90. $content = ob_get_contents();
  91. ob_end_clean();
  92. $this->assertContains(
  93. '<title>PrivateBin</title>',
  94. $content,
  95. 'outputs title correctly'
  96. );
  97. }
  98. /**
  99. * @runInSeparateProcess
  100. */
  101. public function testViewUrlShortener()
  102. {
  103. $shortener = 'https://shortener.example.com/api?link=';
  104. $options = parse_ini_file(CONF, true);
  105. $options['main']['urlshortener'] = $shortener;
  106. Helper::createIniFile(CONF, $options);
  107. $_COOKIE['lang'] = 'de';
  108. ob_start();
  109. new Controller;
  110. $content = ob_get_contents();
  111. ob_end_clean();
  112. $this->assertRegExp(
  113. '#id="shortenbutton"[^>]*data-shortener="' . preg_quote($shortener) . '"#',
  114. $content,
  115. 'outputs configured shortener URL correctly'
  116. );
  117. }
  118. /**
  119. * @runInSeparateProcess
  120. */
  121. public function testHtaccess()
  122. {
  123. $file = $this->_path . DIRECTORY_SEPARATOR . '.htaccess';
  124. @unlink($file);
  125. $_POST = Helper::getPastePostJson();
  126. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  127. $_SERVER['REQUEST_METHOD'] = 'POST';
  128. $_SERVER['REMOTE_ADDR'] = '::1';
  129. ob_start();
  130. new Controller;
  131. ob_end_clean();
  132. $this->assertFileExists($file, 'htaccess recreated');
  133. }
  134. /**
  135. * @expectedException Exception
  136. * @expectedExceptionCode 2
  137. */
  138. public function testConf()
  139. {
  140. file_put_contents(CONF, '');
  141. new Controller;
  142. }
  143. /**
  144. * @runInSeparateProcess
  145. */
  146. public function testCreate()
  147. {
  148. $options = parse_ini_file(CONF, true);
  149. $options['traffic']['limit'] = 0;
  150. Helper::createIniFile(CONF, $options);
  151. $_POST = Helper::getPastePostJson();
  152. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  153. $_SERVER['REQUEST_METHOD'] = 'POST';
  154. $_SERVER['REMOTE_ADDR'] = '::1';
  155. ob_start();
  156. new Controller;
  157. $content = ob_get_contents();
  158. ob_end_clean();
  159. $response = json_decode($content, true);
  160. $this->assertEquals(0, $response['status'], 'outputs status');
  161. $this->assertTrue($this->_model->exists($response['id']), 'paste exists after posting data');
  162. $paste = $this->_model->read($response['id']);
  163. $this->assertEquals(
  164. hash_hmac('sha256', $response['id'], $paste['meta']['salt']),
  165. $response['deletetoken'],
  166. 'outputs valid delete token'
  167. );
  168. }
  169. /**
  170. * @runInSeparateProcess
  171. */
  172. public function testCreateInvalidTimelimit()
  173. {
  174. $options = parse_ini_file(CONF, true);
  175. $options['traffic']['limit'] = 0;
  176. Helper::createIniFile(CONF, $options);
  177. $_POST = Helper::getPastePostJson(2, array('expire' => 25));
  178. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  179. $_SERVER['REQUEST_METHOD'] = 'POST';
  180. $_SERVER['REMOTE_ADDR'] = '::1';
  181. TrafficLimiter::canPass();
  182. ob_start();
  183. new Controller;
  184. $content = ob_get_contents();
  185. ob_end_clean();
  186. $response = json_decode($content, true);
  187. $this->assertEquals(0, $response['status'], 'outputs status');
  188. $this->assertTrue($this->_model->exists($response['id']), 'paste exists after posting data');
  189. $paste = $this->_model->read($response['id']);
  190. $this->assertEquals(
  191. hash_hmac('sha256', $response['id'], $paste['meta']['salt']),
  192. $response['deletetoken'],
  193. 'outputs valid delete token'
  194. );
  195. }
  196. /**
  197. * @runInSeparateProcess
  198. */
  199. public function testCreateInvalidSize()
  200. {
  201. $options = parse_ini_file(CONF, true);
  202. $options['main']['sizelimit'] = 10;
  203. $options['traffic']['limit'] = 0;
  204. Helper::createIniFile(CONF, $options);
  205. $_POST = Helper::getPastePostJson();
  206. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  207. $_SERVER['REQUEST_METHOD'] = 'POST';
  208. $_SERVER['REMOTE_ADDR'] = '::1';
  209. ob_start();
  210. new Controller;
  211. $content = ob_get_contents();
  212. ob_end_clean();
  213. $response = json_decode($content, true);
  214. $this->assertEquals(1, $response['status'], 'outputs error status');
  215. $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste exists after posting data');
  216. }
  217. /**
  218. * @runInSeparateProcess
  219. */
  220. public function testCreateProxyHeader()
  221. {
  222. $options = parse_ini_file(CONF, true);
  223. $options['traffic']['header'] = 'X_FORWARDED_FOR';
  224. Helper::createIniFile(CONF, $options);
  225. $_POST = Helper::getPastePostJson();
  226. $_SERVER['HTTP_X_FORWARDED_FOR'] = '::2';
  227. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  228. $_SERVER['REQUEST_METHOD'] = 'POST';
  229. $_SERVER['REMOTE_ADDR'] = '::1';
  230. ob_start();
  231. new Controller;
  232. $content = ob_get_contents();
  233. ob_end_clean();
  234. $response = json_decode($content, true);
  235. $this->assertEquals(0, $response['status'], 'outputs status');
  236. $this->assertTrue($this->_model->exists($response['id']), 'paste exists after posting data');
  237. $paste = $this->_model->read($response['id']);
  238. $this->assertEquals(
  239. hash_hmac('sha256', $response['id'], $paste['meta']['salt']),
  240. $response['deletetoken'],
  241. 'outputs valid delete token'
  242. );
  243. }
  244. /**
  245. * @runInSeparateProcess
  246. */
  247. public function testCreateDuplicateId()
  248. {
  249. $options = parse_ini_file(CONF, true);
  250. $options['traffic']['limit'] = 0;
  251. Helper::createIniFile(CONF, $options);
  252. $this->_model->create(Helper::getPasteId(), Helper::getPaste());
  253. $_POST = Helper::getPastePostJson();
  254. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  255. $_SERVER['REQUEST_METHOD'] = 'POST';
  256. $_SERVER['REMOTE_ADDR'] = '::1';
  257. ob_start();
  258. new Controller;
  259. $content = ob_get_contents();
  260. ob_end_clean();
  261. $response = json_decode($content, true);
  262. $this->assertEquals(1, $response['status'], 'outputs error status');
  263. $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after posting data');
  264. }
  265. /**
  266. * @runInSeparateProcess
  267. */
  268. public function testCreateValidExpire()
  269. {
  270. $options = parse_ini_file(CONF, true);
  271. $options['traffic']['limit'] = 0;
  272. Helper::createIniFile(CONF, $options);
  273. $_POST = Helper::getPastePostJson();
  274. $_POST['expire'] = '5min';
  275. $_POST['formatter'] = 'foo';
  276. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  277. $_SERVER['REQUEST_METHOD'] = 'POST';
  278. $_SERVER['REMOTE_ADDR'] = '::1';
  279. $time = time();
  280. ob_start();
  281. new Controller;
  282. $content = ob_get_contents();
  283. ob_end_clean();
  284. $response = json_decode($content, true);
  285. $this->assertEquals(0, $response['status'], 'outputs status');
  286. $this->assertTrue($this->_model->exists($response['id']), 'paste exists after posting data');
  287. $paste = $this->_model->read($response['id']);
  288. $this->assertEquals(
  289. hash_hmac('sha256', $response['id'], $paste['meta']['salt']),
  290. $response['deletetoken'],
  291. 'outputs valid delete token'
  292. );
  293. $this->assertGreaterThanOrEqual($time + 300, $paste['meta']['expire_date'], 'time is set correctly');
  294. }
  295. /**
  296. * @runInSeparateProcess
  297. */
  298. public function testCreateValidExpireWithDiscussion()
  299. {
  300. $options = parse_ini_file(CONF, true);
  301. $options['traffic']['limit'] = 0;
  302. Helper::createIniFile(CONF, $options);
  303. $_POST = Helper::getPastePostJson();
  304. $_POST['expire'] = '5min';
  305. $_POST['opendiscussion'] = '1';
  306. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  307. $_SERVER['REQUEST_METHOD'] = 'POST';
  308. $_SERVER['REMOTE_ADDR'] = '::1';
  309. $time = time();
  310. ob_start();
  311. new Controller;
  312. $content = ob_get_contents();
  313. ob_end_clean();
  314. $response = json_decode($content, true);
  315. $this->assertEquals(0, $response['status'], 'outputs status');
  316. $this->assertTrue($this->_model->exists($response['id']), 'paste exists after posting data');
  317. $paste = $this->_model->read($response['id']);
  318. $this->assertEquals(
  319. hash_hmac('sha256', $response['id'], $paste['meta']['salt']),
  320. $response['deletetoken'],
  321. 'outputs valid delete token'
  322. );
  323. $this->assertGreaterThanOrEqual($time + 300, $paste['meta']['expire_date'], 'time is set correctly');
  324. $this->assertEquals(1, $paste['adata'][2], 'discussion is enabled');
  325. }
  326. /**
  327. * @runInSeparateProcess
  328. */
  329. public function testCreateInvalidExpire()
  330. {
  331. $options = parse_ini_file(CONF, true);
  332. $options['traffic']['limit'] = 0;
  333. Helper::createIniFile(CONF, $options);
  334. $_POST = Helper::getPastePostJson();
  335. $_POST['expire'] = 'foo';
  336. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  337. $_SERVER['REQUEST_METHOD'] = 'POST';
  338. $_SERVER['REMOTE_ADDR'] = '::1';
  339. ob_start();
  340. new Controller;
  341. $content = ob_get_contents();
  342. ob_end_clean();
  343. $response = json_decode($content, true);
  344. $this->assertEquals(0, $response['status'], 'outputs status');
  345. $this->assertTrue($this->_model->exists($response['id']), 'paste exists after posting data');
  346. $paste = $this->_model->read($response['id']);
  347. $this->assertEquals(
  348. hash_hmac('sha256', $response['id'], $paste['meta']['salt']),
  349. $response['deletetoken'],
  350. 'outputs valid delete token'
  351. );
  352. }
  353. /**
  354. * @runInSeparateProcess
  355. */
  356. public function testCreateInvalidBurn()
  357. {
  358. $options = parse_ini_file(CONF, true);
  359. $options['traffic']['limit'] = 0;
  360. Helper::createIniFile(CONF, $options);
  361. $_POST = Helper::getPastePostJson();
  362. $adata = Helper::getPaste()['adata'];
  363. $adata[3] = 'neither 1 nor 0';
  364. $_POST['adata'] = json_encode($adata);
  365. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  366. $_SERVER['REQUEST_METHOD'] = 'POST';
  367. $_SERVER['REMOTE_ADDR'] = '::1';
  368. ob_start();
  369. new Controller;
  370. $content = ob_get_contents();
  371. ob_end_clean();
  372. $response = json_decode($content, true);
  373. $this->assertEquals(1, $response['status'], 'outputs error status');
  374. $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste exists after posting data');
  375. }
  376. /**
  377. * @runInSeparateProcess
  378. */
  379. public function testCreateInvalidOpenDiscussion()
  380. {
  381. $options = parse_ini_file(CONF, true);
  382. $options['traffic']['limit'] = 0;
  383. Helper::createIniFile(CONF, $options);
  384. $_POST = Helper::getPastePostJson();
  385. $adata = Helper::getPaste()['adata'];
  386. $adata[2] = 'neither 1 nor 0';
  387. $_POST['adata'] = json_encode($adata);
  388. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  389. $_SERVER['REQUEST_METHOD'] = 'POST';
  390. $_SERVER['REMOTE_ADDR'] = '::1';
  391. ob_start();
  392. new Controller;
  393. $content = ob_get_contents();
  394. ob_end_clean();
  395. $response = json_decode($content, true);
  396. $this->assertEquals(1, $response['status'], 'outputs error status');
  397. $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste exists after posting data');
  398. }
  399. /**
  400. * In some webserver setups (found with Suhosin) overly long POST params are
  401. * silently removed, check that this case is handled
  402. *
  403. * @runInSeparateProcess
  404. */
  405. public function testCreateBrokenUpload()
  406. {
  407. $_POST = Helper::getPastePostJson();
  408. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  409. $_SERVER['REQUEST_METHOD'] = 'POST';
  410. $_SERVER['REMOTE_ADDR'] = '::1';
  411. $_POST['ct'] = ' ';
  412. $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not exists before posting data');
  413. ob_start();
  414. new Controller;
  415. $content = ob_get_contents();
  416. ob_end_clean();
  417. $response = json_decode($content, true);
  418. $this->assertEquals(1, $response['status'], 'outputs error status');
  419. $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste exists after posting data');
  420. }
  421. /**
  422. * @runInSeparateProcess
  423. */
  424. public function testCreateTooSoon()
  425. {
  426. $_POST = Helper::getPastePostJson();
  427. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  428. $_SERVER['REQUEST_METHOD'] = 'POST';
  429. $_SERVER['REMOTE_ADDR'] = '::1';
  430. ob_start();
  431. new Controller;
  432. ob_end_clean();
  433. $this->_model->delete(Helper::getPasteId());
  434. ob_start();
  435. new Controller;
  436. $content = ob_get_contents();
  437. ob_end_clean();
  438. $response = json_decode($content, true);
  439. $this->assertEquals(1, $response['status'], 'outputs error status');
  440. $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste exists after posting data');
  441. }
  442. /**
  443. * @runInSeparateProcess
  444. */
  445. public function testCreateComment()
  446. {
  447. $options = parse_ini_file(CONF, true);
  448. $options['traffic']['limit'] = 0;
  449. Helper::createIniFile(CONF, $options);
  450. $_POST = Helper::getCommentPostJson();
  451. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  452. $_SERVER['REQUEST_METHOD'] = 'POST';
  453. $_SERVER['REMOTE_ADDR'] = '::1';
  454. $this->_model->create(Helper::getPasteId(), Helper::getPaste());
  455. ob_start();
  456. new Controller;
  457. $content = ob_get_contents();
  458. ob_end_clean();
  459. $response = json_decode($content, true);
  460. $this->assertEquals(0, $response['status'], 'outputs status');
  461. $this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), $response['id']), 'paste exists after posting data');
  462. }
  463. /**
  464. * @runInSeparateProcess
  465. */
  466. public function testCreateInvalidComment()
  467. {
  468. $options = parse_ini_file(CONF, true);
  469. $options['traffic']['limit'] = 0;
  470. Helper::createIniFile(CONF, $options);
  471. $_POST = Helper::getCommentPostJson();
  472. $_POST['parentid'] = 'foo';
  473. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  474. $_SERVER['REQUEST_METHOD'] = 'POST';
  475. $_SERVER['REMOTE_ADDR'] = '::1';
  476. $this->_model->create(Helper::getPasteId(), Helper::getPaste());
  477. ob_start();
  478. new Controller;
  479. $content = ob_get_contents();
  480. ob_end_clean();
  481. $response = json_decode($content, true);
  482. $this->assertEquals(1, $response['status'], 'outputs error status');
  483. $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'paste exists after posting data');
  484. }
  485. /**
  486. * @runInSeparateProcess
  487. */
  488. public function testCreateCommentDiscussionDisabled()
  489. {
  490. $options = parse_ini_file(CONF, true);
  491. $options['traffic']['limit'] = 0;
  492. Helper::createIniFile(CONF, $options);
  493. $_POST = Helper::getCommentPostJson();
  494. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  495. $_SERVER['REQUEST_METHOD'] = 'POST';
  496. $_SERVER['REMOTE_ADDR'] = '::1';
  497. $paste = Helper::getPaste();
  498. $paste['adata'][2] = 0;
  499. $this->_model->create(Helper::getPasteId(), $paste);
  500. ob_start();
  501. new Controller;
  502. $content = ob_get_contents();
  503. ob_end_clean();
  504. $response = json_decode($content, true);
  505. $this->assertEquals(1, $response['status'], 'outputs error status');
  506. $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'paste exists after posting data');
  507. }
  508. /**
  509. * @runInSeparateProcess
  510. */
  511. public function testCreateCommentInvalidPaste()
  512. {
  513. $options = parse_ini_file(CONF, true);
  514. $options['traffic']['limit'] = 0;
  515. Helper::createIniFile(CONF, $options);
  516. $_POST = Helper::getCommentPostJson();
  517. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  518. $_SERVER['REQUEST_METHOD'] = 'POST';
  519. $_SERVER['REMOTE_ADDR'] = '::1';
  520. ob_start();
  521. new Controller;
  522. $content = ob_get_contents();
  523. ob_end_clean();
  524. $response = json_decode($content, true);
  525. $this->assertEquals(1, $response['status'], 'outputs error status');
  526. $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'paste exists after posting data');
  527. }
  528. /**
  529. * @runInSeparateProcess
  530. */
  531. public function testCreateDuplicateComment()
  532. {
  533. $options = parse_ini_file(CONF, true);
  534. $options['traffic']['limit'] = 0;
  535. Helper::createIniFile(CONF, $options);
  536. $this->_model->create(Helper::getPasteId(), Helper::getPaste());
  537. $this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId(), Helper::getComment());
  538. $this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId()), 'comment exists before posting data');
  539. $_POST = Helper::getCommentPostJson();
  540. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  541. $_SERVER['REQUEST_METHOD'] = 'POST';
  542. $_SERVER['REMOTE_ADDR'] = '::1';
  543. ob_start();
  544. new Controller;
  545. $content = ob_get_contents();
  546. ob_end_clean();
  547. $response = json_decode($content, true);
  548. $this->assertEquals(1, $response['status'], 'outputs error status');
  549. $this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId()), 'paste exists after posting data');
  550. }
  551. /**
  552. * @runInSeparateProcess
  553. */
  554. public function testReadInvalidId()
  555. {
  556. $_SERVER['QUERY_STRING'] = 'foo';
  557. $_GET['foo'] = '';
  558. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  559. ob_start();
  560. new Controller;
  561. $content = ob_get_contents();
  562. ob_end_clean();
  563. $response = json_decode($content, true);
  564. $this->assertEquals(1, $response['status'], 'outputs error status');
  565. $this->assertEquals('Invalid paste ID.', $response['message'], 'outputs error message');
  566. }
  567. /**
  568. * @runInSeparateProcess
  569. */
  570. public function testReadNonexisting()
  571. {
  572. $_SERVER['QUERY_STRING'] = Helper::getPasteId();
  573. $_GET[Helper::getPasteId()] = '';
  574. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  575. ob_start();
  576. new Controller;
  577. $content = ob_get_contents();
  578. ob_end_clean();
  579. $response = json_decode($content, true);
  580. $this->assertEquals(1, $response['status'], 'outputs error status');
  581. $this->assertEquals('Paste does not exist, has expired or has been deleted.', $response['message'], 'outputs error message');
  582. }
  583. /**
  584. * @runInSeparateProcess
  585. */
  586. public function testReadExpired()
  587. {
  588. $expiredPaste = Helper::getPaste(2, array('expire_date' => 1344803344));
  589. $this->_model->create(Helper::getPasteId(), $expiredPaste);
  590. $_SERVER['QUERY_STRING'] = Helper::getPasteId();
  591. $_GET[Helper::getPasteId()] = '';
  592. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  593. ob_start();
  594. new Controller;
  595. $content = ob_get_contents();
  596. ob_end_clean();
  597. $response = json_decode($content, true);
  598. $this->assertEquals(1, $response['status'], 'outputs error status');
  599. $this->assertEquals('Paste does not exist, has expired or has been deleted.', $response['message'], 'outputs error message');
  600. }
  601. /**
  602. * @runInSeparateProcess
  603. */
  604. public function testReadBurn()
  605. {
  606. $paste = Helper::getPaste();
  607. $paste['adata'][3] = 1;
  608. $this->_model->create(Helper::getPasteId(), $paste);
  609. $_SERVER['QUERY_STRING'] = Helper::getPasteId();
  610. $_GET[Helper::getPasteId()] = '';
  611. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  612. ob_start();
  613. new Controller;
  614. $content = ob_get_contents();
  615. ob_end_clean();
  616. $response = json_decode($content, true);
  617. $this->assertEquals(0, $response['status'], 'outputs success status');
  618. $this->assertEquals(Helper::getPasteId(), $response['id'], 'outputs data correctly');
  619. $this->assertStringEndsWith('?' . $response['id'], $response['url'], 'returned URL points to new paste');
  620. $this->assertEquals($paste['ct'], $response['ct'], 'outputs ct correctly');
  621. $this->assertEquals($paste['adata'][1], $response['adata'][1], 'outputs formatter correctly');
  622. $this->assertEquals($paste['adata'][2], $response['adata'][2], 'outputs opendiscussion correctly');
  623. $this->assertEquals($paste['adata'][3], $response['adata'][3], 'outputs burnafterreading correctly');
  624. $this->assertEquals($paste['meta']['created'], $response['meta']['created'], 'outputs created correctly');
  625. $this->assertEquals(0, $response['comment_count'], 'outputs comment_count correctly');
  626. $this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly');
  627. // by default it will be deleted instantly after it is read
  628. $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste exists after reading');
  629. }
  630. /**
  631. * @runInSeparateProcess
  632. */
  633. public function testReadJson()
  634. {
  635. $paste = Helper::getPaste();
  636. $this->_model->create(Helper::getPasteId(), $paste);
  637. $_SERVER['QUERY_STRING'] = Helper::getPasteId();
  638. $_GET[Helper::getPasteId()] = '';
  639. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  640. ob_start();
  641. new Controller;
  642. $content = ob_get_contents();
  643. ob_end_clean();
  644. $response = json_decode($content, true);
  645. $this->assertEquals(0, $response['status'], 'outputs success status');
  646. $this->assertEquals(Helper::getPasteId(), $response['id'], 'outputs data correctly');
  647. $this->assertStringEndsWith('?' . $response['id'], $response['url'], 'returned URL points to new paste');
  648. $this->assertEquals($paste['ct'], $response['ct'], 'outputs ct correctly');
  649. $this->assertEquals($paste['adata'][1], $response['adata'][1], 'outputs formatter correctly');
  650. $this->assertEquals($paste['adata'][2], $response['adata'][2], 'outputs opendiscussion correctly');
  651. $this->assertEquals($paste['adata'][3], $response['adata'][3], 'outputs burnafterreading correctly');
  652. $this->assertEquals($paste['meta']['created'], $response['meta']['created'], 'outputs created correctly');
  653. $this->assertEquals(0, $response['comment_count'], 'outputs comment_count correctly');
  654. $this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly');
  655. }
  656. /**
  657. * @runInSeparateProcess
  658. */
  659. public function testReadOldSyntax()
  660. {
  661. $paste = Helper::getPaste(1);
  662. $paste['meta'] = array(
  663. 'syntaxcoloring' => true,
  664. 'postdate' => $paste['meta']['postdate'],
  665. 'opendiscussion' => $paste['meta']['opendiscussion'],
  666. );
  667. $this->_model->create(Helper::getPasteId(), $paste);
  668. $_SERVER['QUERY_STRING'] = Helper::getPasteId();
  669. $_GET[Helper::getPasteId()] = '';
  670. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  671. ob_start();
  672. new Controller;
  673. $content = ob_get_contents();
  674. ob_end_clean();
  675. $response = json_decode($content, true);
  676. $this->assertEquals(0, $response['status'], 'outputs success status');
  677. $this->assertEquals(Helper::getPasteId(), $response['id'], 'outputs data correctly');
  678. $this->assertStringEndsWith('?' . $response['id'], $response['url'], 'returned URL points to new paste');
  679. $this->assertEquals($paste['data'], $response['data'], 'outputs data correctly');
  680. $this->assertEquals('syntaxhighlighting', $response['meta']['formatter'], 'outputs format correctly');
  681. $this->assertEquals($paste['meta']['postdate'], $response['meta']['postdate'], 'outputs postdate correctly');
  682. $this->assertEquals($paste['meta']['opendiscussion'], $response['meta']['opendiscussion'], 'outputs opendiscussion correctly');
  683. $this->assertEquals(0, $response['comment_count'], 'outputs comment_count correctly');
  684. $this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly');
  685. }
  686. /**
  687. * @runInSeparateProcess
  688. */
  689. public function testReadBurnAfterReading()
  690. {
  691. $burnPaste = Helper::getPaste();
  692. $burnPaste['adata'][3] = 1;
  693. $this->_model->create(Helper::getPasteId(), $burnPaste);
  694. $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data');
  695. $_SERVER['QUERY_STRING'] = Helper::getPasteId();
  696. $_GET[Helper::getPasteId()] = '';
  697. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  698. ob_start();
  699. new Controller;
  700. $content = ob_get_contents();
  701. ob_end_clean();
  702. $response = json_decode($content, true);
  703. $this->assertEquals(0, $response['status'], 'outputs status');
  704. $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste successfully deleted');
  705. }
  706. /**
  707. * @runInSeparateProcess
  708. */
  709. public function testDelete()
  710. {
  711. $this->_model->create(Helper::getPasteId(), Helper::getPaste());
  712. $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data');
  713. $paste = $this->_model->read(Helper::getPasteId());
  714. $_GET['pasteid'] = Helper::getPasteId();
  715. $_GET['deletetoken'] = hash_hmac('sha256', Helper::getPasteId(), $paste['meta']['salt']);
  716. ob_start();
  717. new Controller;
  718. $content = ob_get_contents();
  719. ob_end_clean();
  720. $this->assertRegExp(
  721. '#<div[^>]*id="status"[^>]*>.*Paste was properly deleted\.#s',
  722. $content,
  723. 'outputs deleted status correctly'
  724. );
  725. $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste successfully deleted');
  726. }
  727. /**
  728. * @runInSeparateProcess
  729. */
  730. public function testDeleteInvalidId()
  731. {
  732. $this->_model->create(Helper::getPasteId(), Helper::getPaste());
  733. $_GET['pasteid'] = 'foo';
  734. $_GET['deletetoken'] = 'bar';
  735. ob_start();
  736. new Controller;
  737. $content = ob_get_contents();
  738. ob_end_clean();
  739. $this->assertRegExp(
  740. '#<div[^>]*id="errormessage"[^>]*>.*Invalid paste ID\.#s',
  741. $content,
  742. 'outputs delete error correctly'
  743. );
  744. $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after failing to delete data');
  745. }
  746. /**
  747. * @runInSeparateProcess
  748. */
  749. public function testDeleteInexistantId()
  750. {
  751. $_GET['pasteid'] = Helper::getPasteId();
  752. $_GET['deletetoken'] = 'bar';
  753. ob_start();
  754. new Controller;
  755. $content = ob_get_contents();
  756. ob_end_clean();
  757. $this->assertRegExp(
  758. '#<div[^>]*id="errormessage"[^>]*>.*Paste does not exist, has expired or has been deleted\.#s',
  759. $content,
  760. 'outputs delete error correctly'
  761. );
  762. }
  763. /**
  764. * @runInSeparateProcess
  765. */
  766. public function testDeleteInvalidToken()
  767. {
  768. $this->_model->create(Helper::getPasteId(), Helper::getPaste());
  769. $_GET['pasteid'] = Helper::getPasteId();
  770. $_GET['deletetoken'] = 'bar';
  771. ob_start();
  772. new Controller;
  773. $content = ob_get_contents();
  774. ob_end_clean();
  775. $this->assertRegExp(
  776. '#<div[^>]*id="errormessage"[^>]*>.*Wrong deletion token\. Paste was not deleted\.#s',
  777. $content,
  778. 'outputs delete error correctly'
  779. );
  780. $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after failing to delete data');
  781. }
  782. /**
  783. * @runInSeparateProcess
  784. */
  785. public function testDeleteInvalidBurnAfterReading()
  786. {
  787. $this->_model->create(Helper::getPasteId(), Helper::getPaste());
  788. $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data');
  789. $_POST['deletetoken'] = 'burnafterreading';
  790. $_SERVER['QUERY_STRING'] = Helper::getPasteId();
  791. $_GET[Helper::getPasteId()] = '';
  792. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  793. $_SERVER['REQUEST_METHOD'] = 'POST';
  794. ob_start();
  795. new Controller;
  796. $content = ob_get_contents();
  797. ob_end_clean();
  798. $response = json_decode($content, true);
  799. $this->assertEquals(1, $response['status'], 'outputs status');
  800. $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after failing to delete data');
  801. }
  802. /**
  803. * @runInSeparateProcess
  804. */
  805. public function testDeleteExpired()
  806. {
  807. $expiredPaste = Helper::getPaste(2, array('expire_date' => 1000));
  808. $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not exist before being created');
  809. $this->_model->create(Helper::getPasteId(), $expiredPaste);
  810. $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data');
  811. $_GET['pasteid'] = Helper::getPasteId();
  812. $_GET['deletetoken'] = 'does not matter in this context, but has to be set';
  813. ob_start();
  814. new Controller;
  815. $content = ob_get_contents();
  816. ob_end_clean();
  817. $this->assertRegExp(
  818. '#<div[^>]*id="errormessage"[^>]*>.*Paste does not exist, has expired or has been deleted\.#s',
  819. $content,
  820. 'outputs error correctly'
  821. );
  822. $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste successfully deleted');
  823. }
  824. /**
  825. * @runInSeparateProcess
  826. */
  827. public function testDeleteMissingPerPasteSalt()
  828. {
  829. $paste = Helper::getPaste();
  830. unset($paste['meta']['salt']);
  831. $this->_model->create(Helper::getPasteId(), $paste);
  832. $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data');
  833. $_GET['pasteid'] = Helper::getPasteId();
  834. $_GET['deletetoken'] = hash_hmac('sha256', Helper::getPasteId(), ServerSalt::get());
  835. ob_start();
  836. new Controller;
  837. $content = ob_get_contents();
  838. ob_end_clean();
  839. $this->assertRegExp(
  840. '#<div[^>]*id="status"[^>]*>.*Paste was properly deleted\.#s',
  841. $content,
  842. 'outputs deleted status correctly'
  843. );
  844. $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste successfully deleted');
  845. }
  846. }