ControllerTest.php 36 KB

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