ControllerTest.php 37 KB

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