ControllerTest.php 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  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. * @expectedException Exception
  119. * @expectedExceptionCode 2
  120. */
  121. public function testConf()
  122. {
  123. file_put_contents(CONF, '');
  124. new Controller;
  125. }
  126. /**
  127. * @runInSeparateProcess
  128. */
  129. public function testCreate()
  130. {
  131. $options = parse_ini_file(CONF, true);
  132. $options['traffic']['limit'] = 0;
  133. Helper::createIniFile(CONF, $options);
  134. $paste = Helper::getPasteJson();
  135. $file = tempnam(sys_get_temp_dir(), 'FOO');
  136. file_put_contents($file, $paste);
  137. Request::setInputStream($file);
  138. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  139. $_SERVER['REQUEST_METHOD'] = 'POST';
  140. $_SERVER['REMOTE_ADDR'] = '::1';
  141. ob_start();
  142. new Controller;
  143. $content = ob_get_contents();
  144. ob_end_clean();
  145. $response = json_decode($content, true);
  146. $this->assertEquals(0, $response['status'], 'outputs status');
  147. $this->assertTrue($this->_data->exists($response['id']), 'paste exists after posting data');
  148. $paste = $this->_data->read($response['id']);
  149. $this->assertEquals(
  150. hash_hmac('sha256', $response['id'], $paste['meta']['salt']),
  151. $response['deletetoken'],
  152. 'outputs valid delete token'
  153. );
  154. }
  155. /**
  156. * @runInSeparateProcess
  157. */
  158. public function testCreateInvalidTimelimit()
  159. {
  160. $options = parse_ini_file(CONF, true);
  161. $options['traffic']['limit'] = 0;
  162. Helper::createIniFile(CONF, $options);
  163. $paste = Helper::getPasteJson(2, array('expire' => 25));
  164. $file = tempnam(sys_get_temp_dir(), 'FOO');
  165. file_put_contents($file, $paste);
  166. Request::setInputStream($file);
  167. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  168. $_SERVER['REQUEST_METHOD'] = 'POST';
  169. $_SERVER['REMOTE_ADDR'] = '::1';
  170. TrafficLimiter::canPass();
  171. ob_start();
  172. new Controller;
  173. $content = ob_get_contents();
  174. ob_end_clean();
  175. $response = json_decode($content, true);
  176. $this->assertEquals(0, $response['status'], 'outputs status');
  177. $this->assertTrue($this->_data->exists($response['id']), 'paste exists after posting data');
  178. $paste = $this->_data->read($response['id']);
  179. $this->assertEquals(
  180. hash_hmac('sha256', $response['id'], $paste['meta']['salt']),
  181. $response['deletetoken'],
  182. 'outputs valid delete token'
  183. );
  184. }
  185. /**
  186. * @runInSeparateProcess
  187. */
  188. public function testCreateInvalidSize()
  189. {
  190. $options = parse_ini_file(CONF, true);
  191. $options['main']['sizelimit'] = 10;
  192. $options['traffic']['limit'] = 0;
  193. Helper::createIniFile(CONF, $options);
  194. $paste = Helper::getPasteJson();
  195. $file = tempnam(sys_get_temp_dir(), 'FOO');
  196. file_put_contents($file, $paste);
  197. Request::setInputStream($file);
  198. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  199. $_SERVER['REQUEST_METHOD'] = 'POST';
  200. $_SERVER['REMOTE_ADDR'] = '::1';
  201. ob_start();
  202. new Controller;
  203. $content = ob_get_contents();
  204. ob_end_clean();
  205. $response = json_decode($content, true);
  206. $this->assertEquals(1, $response['status'], 'outputs error status');
  207. $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste exists after posting data');
  208. }
  209. /**
  210. * @runInSeparateProcess
  211. */
  212. public function testCreateProxyHeader()
  213. {
  214. $options = parse_ini_file(CONF, true);
  215. $options['traffic']['header'] = 'X_FORWARDED_FOR';
  216. Helper::createIniFile(CONF, $options);
  217. $paste = Helper::getPasteJson();
  218. $file = tempnam(sys_get_temp_dir(), 'FOO');
  219. file_put_contents($file, $paste);
  220. Request::setInputStream($file);
  221. $_SERVER['HTTP_X_FORWARDED_FOR'] = '::2';
  222. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  223. $_SERVER['REQUEST_METHOD'] = 'POST';
  224. $_SERVER['REMOTE_ADDR'] = '::1';
  225. ob_start();
  226. new Controller;
  227. $content = ob_get_contents();
  228. ob_end_clean();
  229. $response = json_decode($content, true);
  230. $this->assertEquals(0, $response['status'], 'outputs status');
  231. $this->assertTrue($this->_data->exists($response['id']), 'paste exists after posting data');
  232. $paste = $this->_data->read($response['id']);
  233. $this->assertEquals(
  234. hash_hmac('sha256', $response['id'], $paste['meta']['salt']),
  235. $response['deletetoken'],
  236. 'outputs valid delete token'
  237. );
  238. }
  239. /**
  240. * @runInSeparateProcess
  241. */
  242. public function testCreateDuplicateId()
  243. {
  244. $options = parse_ini_file(CONF, true);
  245. $options['traffic']['limit'] = 0;
  246. Helper::createIniFile(CONF, $options);
  247. $this->_data->create(Helper::getPasteId(), Helper::getPaste());
  248. $paste = Helper::getPasteJson();
  249. $file = tempnam(sys_get_temp_dir(), 'FOO');
  250. file_put_contents($file, $paste);
  251. Request::setInputStream($file);
  252. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  253. $_SERVER['REQUEST_METHOD'] = 'POST';
  254. $_SERVER['REMOTE_ADDR'] = '::1';
  255. ob_start();
  256. new Controller;
  257. $content = ob_get_contents();
  258. ob_end_clean();
  259. $response = json_decode($content, true);
  260. $this->assertEquals(1, $response['status'], 'outputs error status');
  261. $this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists after posting data');
  262. }
  263. /**
  264. * @runInSeparateProcess
  265. */
  266. public function testCreateValidExpire()
  267. {
  268. $options = parse_ini_file(CONF, true);
  269. $options['traffic']['limit'] = 0;
  270. Helper::createIniFile(CONF, $options);
  271. $paste = Helper::getPasteJson();
  272. $file = tempnam(sys_get_temp_dir(), 'FOO');
  273. file_put_contents($file, $paste);
  274. Request::setInputStream($file);
  275. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  276. $_SERVER['REQUEST_METHOD'] = 'POST';
  277. $_SERVER['REMOTE_ADDR'] = '::1';
  278. $time = time();
  279. ob_start();
  280. new Controller;
  281. $content = ob_get_contents();
  282. ob_end_clean();
  283. $response = json_decode($content, true);
  284. $this->assertEquals(0, $response['status'], 'outputs status');
  285. $this->assertTrue($this->_data->exists($response['id']), 'paste exists after posting data');
  286. $paste = $this->_data->read($response['id']);
  287. $this->assertEquals(
  288. hash_hmac('sha256', $response['id'], $paste['meta']['salt']),
  289. $response['deletetoken'],
  290. 'outputs valid delete token'
  291. );
  292. $this->assertGreaterThanOrEqual($time + 300, $paste['meta']['expire_date'], 'time is set correctly');
  293. }
  294. /**
  295. * @runInSeparateProcess
  296. */
  297. public function testCreateValidExpireWithDiscussion()
  298. {
  299. $options = parse_ini_file(CONF, true);
  300. $options['traffic']['limit'] = 0;
  301. Helper::createIniFile(CONF, $options);
  302. $paste = Helper::getPasteJson();
  303. $file = tempnam(sys_get_temp_dir(), 'FOO');
  304. file_put_contents($file, $paste);
  305. Request::setInputStream($file);
  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->_data->exists($response['id']), 'paste exists after posting data');
  317. $paste = $this->_data->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. $paste = Helper::getPasteJson(2, array('expire' => 'foo'));
  335. $file = tempnam(sys_get_temp_dir(), 'FOO');
  336. file_put_contents($file, $paste);
  337. Request::setInputStream($file);
  338. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  339. $_SERVER['REQUEST_METHOD'] = 'POST';
  340. $_SERVER['REMOTE_ADDR'] = '::1';
  341. ob_start();
  342. new Controller;
  343. $content = ob_get_contents();
  344. ob_end_clean();
  345. $response = json_decode($content, true);
  346. $this->assertEquals(0, $response['status'], 'outputs status');
  347. $this->assertTrue($this->_data->exists($response['id']), 'paste exists after posting data');
  348. $paste = $this->_data->read($response['id']);
  349. $this->assertEquals(
  350. hash_hmac('sha256', $response['id'], $paste['meta']['salt']),
  351. $response['deletetoken'],
  352. 'outputs valid delete token'
  353. );
  354. }
  355. /**
  356. * @runInSeparateProcess
  357. */
  358. public function testCreateInvalidBurn()
  359. {
  360. $options = parse_ini_file(CONF, true);
  361. $options['traffic']['limit'] = 0;
  362. Helper::createIniFile(CONF, $options);
  363. $paste = Helper::getPastePost();
  364. $paste['adata'][3] = 'neither 1 nor 0';
  365. $file = tempnam(sys_get_temp_dir(), 'FOO');
  366. file_put_contents($file, json_encode($paste));
  367. Request::setInputStream($file);
  368. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  369. $_SERVER['REQUEST_METHOD'] = 'POST';
  370. $_SERVER['REMOTE_ADDR'] = '::1';
  371. ob_start();
  372. new Controller;
  373. $content = ob_get_contents();
  374. ob_end_clean();
  375. $response = json_decode($content, true);
  376. $this->assertEquals(1, $response['status'], 'outputs error status');
  377. $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste exists after posting data');
  378. }
  379. /**
  380. * @runInSeparateProcess
  381. */
  382. public function testCreateInvalidOpenDiscussion()
  383. {
  384. $options = parse_ini_file(CONF, true);
  385. $options['traffic']['limit'] = 0;
  386. Helper::createIniFile(CONF, $options);
  387. $paste = Helper::getPastePost();
  388. $paste['adata'][2] = 'neither 1 nor 0';
  389. $file = tempnam(sys_get_temp_dir(), 'FOO');
  390. file_put_contents($file, json_encode($paste));
  391. Request::setInputStream($file);
  392. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  393. $_SERVER['REQUEST_METHOD'] = 'POST';
  394. $_SERVER['REMOTE_ADDR'] = '::1';
  395. ob_start();
  396. new Controller;
  397. $content = ob_get_contents();
  398. ob_end_clean();
  399. $response = json_decode($content, true);
  400. $this->assertEquals(1, $response['status'], 'outputs error status');
  401. $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste exists after posting data');
  402. }
  403. /**
  404. * In some webserver setups (found with Suhosin) overly long POST params are
  405. * silently removed, check that this case is handled
  406. *
  407. * @runInSeparateProcess
  408. * @expectedException Exception
  409. * @expectedExceptionCode 90
  410. */
  411. public function testCreateBrokenUpload()
  412. {
  413. $paste = substr(Helper::getPasteJson(), 0, -10);
  414. $file = tempnam(sys_get_temp_dir(), 'FOO');
  415. file_put_contents($file, $paste);
  416. Request::setInputStream($file);
  417. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  418. $_SERVER['REQUEST_METHOD'] = 'POST';
  419. $_SERVER['REMOTE_ADDR'] = '::1';
  420. $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste does not exists before posting data');
  421. new Controller;
  422. $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste exists after posting data');
  423. }
  424. /**
  425. * @runInSeparateProcess
  426. */
  427. public function testCreateTooSoon()
  428. {
  429. $paste = Helper::getPasteJson();
  430. $file = tempnam(sys_get_temp_dir(), 'FOO');
  431. file_put_contents($file, $paste);
  432. Request::setInputStream($file);
  433. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  434. $_SERVER['REQUEST_METHOD'] = 'POST';
  435. $_SERVER['REMOTE_ADDR'] = '::1';
  436. ob_start();
  437. new Controller;
  438. ob_end_clean();
  439. $this->_data->delete(Helper::getPasteId());
  440. ob_start();
  441. new Controller;
  442. $content = ob_get_contents();
  443. ob_end_clean();
  444. $response = json_decode($content, true);
  445. $this->assertEquals(1, $response['status'], 'outputs error status');
  446. $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste exists after posting data');
  447. }
  448. /**
  449. * @runInSeparateProcess
  450. */
  451. public function testCreateComment()
  452. {
  453. $options = parse_ini_file(CONF, true);
  454. $options['traffic']['limit'] = 0;
  455. Helper::createIniFile(CONF, $options);
  456. $comment = Helper::getCommentJson();
  457. $file = tempnam(sys_get_temp_dir(), 'FOO');
  458. file_put_contents($file, $comment);
  459. Request::setInputStream($file);
  460. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  461. $_SERVER['REQUEST_METHOD'] = 'POST';
  462. $_SERVER['REMOTE_ADDR'] = '::1';
  463. $this->_data->create(Helper::getPasteId(), Helper::getPaste());
  464. ob_start();
  465. new Controller;
  466. $content = ob_get_contents();
  467. ob_end_clean();
  468. $response = json_decode($content, true);
  469. $this->assertEquals(0, $response['status'], 'outputs status');
  470. $this->assertTrue($this->_data->existsComment(Helper::getPasteId(), Helper::getPasteId(), $response['id']), 'paste exists after posting data');
  471. }
  472. /**
  473. * @runInSeparateProcess
  474. */
  475. public function testCreateInvalidComment()
  476. {
  477. $options = parse_ini_file(CONF, true);
  478. $options['traffic']['limit'] = 0;
  479. Helper::createIniFile(CONF, $options);
  480. $comment = Helper::getCommentPost();
  481. $comment['parentid'] = 'foo';
  482. $file = tempnam(sys_get_temp_dir(), 'FOO');
  483. file_put_contents($file, json_encode($comment));
  484. Request::setInputStream($file);
  485. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  486. $_SERVER['REQUEST_METHOD'] = 'POST';
  487. $_SERVER['REMOTE_ADDR'] = '::1';
  488. $this->_data->create(Helper::getPasteId(), Helper::getPaste());
  489. ob_start();
  490. new Controller;
  491. $content = ob_get_contents();
  492. ob_end_clean();
  493. $response = json_decode($content, true);
  494. $this->assertEquals(1, $response['status'], 'outputs error status');
  495. $this->assertFalse($this->_data->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'paste exists after posting data');
  496. }
  497. /**
  498. * @runInSeparateProcess
  499. */
  500. public function testCreateCommentDiscussionDisabled()
  501. {
  502. $options = parse_ini_file(CONF, true);
  503. $options['traffic']['limit'] = 0;
  504. Helper::createIniFile(CONF, $options);
  505. $comment = Helper::getCommentJson();
  506. $file = tempnam(sys_get_temp_dir(), 'FOO');
  507. file_put_contents($file, $comment);
  508. Request::setInputStream($file);
  509. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  510. $_SERVER['REQUEST_METHOD'] = 'POST';
  511. $_SERVER['REMOTE_ADDR'] = '::1';
  512. $paste = Helper::getPaste();
  513. $paste['adata'][2] = 0;
  514. $this->_data->create(Helper::getPasteId(), $paste);
  515. ob_start();
  516. new Controller;
  517. $content = ob_get_contents();
  518. ob_end_clean();
  519. $response = json_decode($content, true);
  520. $this->assertEquals(1, $response['status'], 'outputs error status');
  521. $this->assertFalse($this->_data->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'paste exists after posting data');
  522. }
  523. /**
  524. * @runInSeparateProcess
  525. */
  526. public function testCreateCommentInvalidPaste()
  527. {
  528. $options = parse_ini_file(CONF, true);
  529. $options['traffic']['limit'] = 0;
  530. Helper::createIniFile(CONF, $options);
  531. $comment = Helper::getCommentJson();
  532. $file = tempnam(sys_get_temp_dir(), 'FOO');
  533. file_put_contents($file, $comment);
  534. Request::setInputStream($file);
  535. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  536. $_SERVER['REQUEST_METHOD'] = 'POST';
  537. $_SERVER['REMOTE_ADDR'] = '::1';
  538. ob_start();
  539. new Controller;
  540. $content = ob_get_contents();
  541. ob_end_clean();
  542. $response = json_decode($content, true);
  543. $this->assertEquals(1, $response['status'], 'outputs error status');
  544. $this->assertFalse($this->_data->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'paste exists after posting data');
  545. }
  546. /**
  547. * @runInSeparateProcess
  548. */
  549. public function testCreateDuplicateComment()
  550. {
  551. $options = parse_ini_file(CONF, true);
  552. $options['traffic']['limit'] = 0;
  553. Helper::createIniFile(CONF, $options);
  554. $this->_data->create(Helper::getPasteId(), Helper::getPaste());
  555. $this->_data->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId(), Helper::getComment());
  556. $this->assertTrue($this->_data->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId()), 'comment exists before posting data');
  557. $comment = Helper::getCommentJson();
  558. $file = tempnam(sys_get_temp_dir(), 'FOO');
  559. file_put_contents($file, $comment);
  560. Request::setInputStream($file);
  561. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  562. $_SERVER['REQUEST_METHOD'] = 'POST';
  563. $_SERVER['REMOTE_ADDR'] = '::1';
  564. ob_start();
  565. new Controller;
  566. $content = ob_get_contents();
  567. ob_end_clean();
  568. $response = json_decode($content, true);
  569. $this->assertEquals(1, $response['status'], 'outputs error status');
  570. $this->assertTrue($this->_data->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId()), 'paste exists after posting data');
  571. }
  572. /**
  573. * @runInSeparateProcess
  574. */
  575. public function testReadInvalidId()
  576. {
  577. $_SERVER['QUERY_STRING'] = 'foo';
  578. $_GET['foo'] = '';
  579. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  580. ob_start();
  581. new Controller;
  582. $content = ob_get_contents();
  583. ob_end_clean();
  584. $response = json_decode($content, true);
  585. $this->assertEquals(1, $response['status'], 'outputs error status');
  586. $this->assertEquals('Invalid paste ID.', $response['message'], 'outputs error message');
  587. }
  588. /**
  589. * @runInSeparateProcess
  590. */
  591. public function testReadNonexisting()
  592. {
  593. $_SERVER['QUERY_STRING'] = Helper::getPasteId();
  594. $_GET[Helper::getPasteId()] = '';
  595. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  596. ob_start();
  597. new Controller;
  598. $content = ob_get_contents();
  599. ob_end_clean();
  600. $response = json_decode($content, true);
  601. $this->assertEquals(1, $response['status'], 'outputs error status');
  602. $this->assertEquals('Paste does not exist, has expired or has been deleted.', $response['message'], 'outputs error message');
  603. }
  604. /**
  605. * @runInSeparateProcess
  606. */
  607. public function testReadExpired()
  608. {
  609. $expiredPaste = Helper::getPaste(2, array('expire_date' => 1344803344));
  610. $this->_data->create(Helper::getPasteId(), $expiredPaste);
  611. $_SERVER['QUERY_STRING'] = Helper::getPasteId();
  612. $_GET[Helper::getPasteId()] = '';
  613. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  614. ob_start();
  615. new Controller;
  616. $content = ob_get_contents();
  617. ob_end_clean();
  618. $response = json_decode($content, true);
  619. $this->assertEquals(1, $response['status'], 'outputs error status');
  620. $this->assertEquals('Paste does not exist, has expired or has been deleted.', $response['message'], 'outputs error message');
  621. }
  622. /**
  623. * @runInSeparateProcess
  624. */
  625. public function testReadBurn()
  626. {
  627. $paste = Helper::getPaste();
  628. $paste['adata'][3] = 1;
  629. $this->_data->create(Helper::getPasteId(), $paste);
  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(0, $response['status'], 'outputs success status');
  639. $this->assertEquals(Helper::getPasteId(), $response['id'], 'outputs data correctly');
  640. $this->assertStringEndsWith('?' . $response['id'], $response['url'], 'returned URL points to new paste');
  641. $this->assertEquals($paste['ct'], $response['ct'], 'outputs ct correctly');
  642. $this->assertEquals($paste['adata'][1], $response['adata'][1], 'outputs formatter correctly');
  643. $this->assertEquals($paste['adata'][2], $response['adata'][2], 'outputs opendiscussion correctly');
  644. $this->assertEquals($paste['adata'][3], $response['adata'][3], 'outputs burnafterreading correctly');
  645. $this->assertEquals($paste['meta']['created'], $response['meta']['created'], 'outputs created correctly');
  646. $this->assertEquals(0, $response['comment_count'], 'outputs comment_count correctly');
  647. $this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly');
  648. // by default it will be deleted instantly after it is read
  649. $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste exists after reading');
  650. }
  651. /**
  652. * @runInSeparateProcess
  653. */
  654. public function testReadJson()
  655. {
  656. $paste = Helper::getPaste();
  657. $this->_data->create(Helper::getPasteId(), $paste);
  658. $_SERVER['QUERY_STRING'] = Helper::getPasteId();
  659. $_GET[Helper::getPasteId()] = '';
  660. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  661. ob_start();
  662. new Controller;
  663. $content = ob_get_contents();
  664. ob_end_clean();
  665. $response = json_decode($content, true);
  666. $this->assertEquals(0, $response['status'], 'outputs success status');
  667. $this->assertEquals(Helper::getPasteId(), $response['id'], 'outputs data correctly');
  668. $this->assertStringEndsWith('?' . $response['id'], $response['url'], 'returned URL points to new paste');
  669. $this->assertEquals($paste['ct'], $response['ct'], 'outputs ct correctly');
  670. $this->assertEquals($paste['adata'][1], $response['adata'][1], 'outputs formatter correctly');
  671. $this->assertEquals($paste['adata'][2], $response['adata'][2], 'outputs opendiscussion correctly');
  672. $this->assertEquals($paste['adata'][3], $response['adata'][3], 'outputs burnafterreading correctly');
  673. $this->assertEquals($paste['meta']['created'], $response['meta']['created'], 'outputs created correctly');
  674. $this->assertEquals(0, $response['comment_count'], 'outputs comment_count correctly');
  675. $this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly');
  676. }
  677. /**
  678. * @runInSeparateProcess
  679. */
  680. public function testReadOldSyntax()
  681. {
  682. $paste = Helper::getPaste(1);
  683. $paste['meta'] = array(
  684. 'syntaxcoloring' => true,
  685. 'postdate' => $paste['meta']['postdate'],
  686. 'opendiscussion' => $paste['meta']['opendiscussion'],
  687. );
  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['data'], $response['data'], 'outputs data correctly');
  701. $this->assertEquals('syntaxhighlighting', $response['meta']['formatter'], 'outputs format correctly');
  702. $this->assertEquals($paste['meta']['postdate'], $response['meta']['postdate'], 'outputs postdate correctly');
  703. $this->assertEquals($paste['meta']['opendiscussion'], $response['meta']['opendiscussion'], 'outputs opendiscussion correctly');
  704. $this->assertEquals(0, $response['comment_count'], 'outputs comment_count correctly');
  705. $this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly');
  706. }
  707. /**
  708. * @runInSeparateProcess
  709. */
  710. public function testReadBurnAfterReading()
  711. {
  712. $burnPaste = Helper::getPaste();
  713. $burnPaste['adata'][3] = 1;
  714. $this->_data->create(Helper::getPasteId(), $burnPaste);
  715. $this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data');
  716. $_SERVER['QUERY_STRING'] = Helper::getPasteId();
  717. $_GET[Helper::getPasteId()] = '';
  718. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  719. ob_start();
  720. new Controller;
  721. $content = ob_get_contents();
  722. ob_end_clean();
  723. $response = json_decode($content, true);
  724. $this->assertEquals(0, $response['status'], 'outputs status');
  725. $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste successfully deleted');
  726. }
  727. /**
  728. * @runInSeparateProcess
  729. */
  730. public function testDelete()
  731. {
  732. $this->_data->create(Helper::getPasteId(), Helper::getPaste());
  733. $this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data');
  734. $paste = $this->_data->read(Helper::getPasteId());
  735. $_GET['pasteid'] = Helper::getPasteId();
  736. $_GET['deletetoken'] = hash_hmac('sha256', Helper::getPasteId(), $paste['meta']['salt']);
  737. ob_start();
  738. new Controller;
  739. $content = ob_get_contents();
  740. ob_end_clean();
  741. $this->assertRegExp(
  742. '#<div[^>]*id="status"[^>]*>.*Paste was properly deleted\.#s',
  743. $content,
  744. 'outputs deleted status correctly'
  745. );
  746. $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste successfully deleted');
  747. }
  748. /**
  749. * @runInSeparateProcess
  750. */
  751. public function testDeleteInvalidId()
  752. {
  753. $this->_data->create(Helper::getPasteId(), Helper::getPaste());
  754. $_GET['pasteid'] = 'foo';
  755. $_GET['deletetoken'] = 'bar';
  756. ob_start();
  757. new Controller;
  758. $content = ob_get_contents();
  759. ob_end_clean();
  760. $this->assertRegExp(
  761. '#<div[^>]*id="errormessage"[^>]*>.*Invalid paste ID\.#s',
  762. $content,
  763. 'outputs delete error correctly'
  764. );
  765. $this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists after failing to delete data');
  766. }
  767. /**
  768. * @runInSeparateProcess
  769. */
  770. public function testDeleteInexistantId()
  771. {
  772. $_GET['pasteid'] = Helper::getPasteId();
  773. $_GET['deletetoken'] = 'bar';
  774. ob_start();
  775. new Controller;
  776. $content = ob_get_contents();
  777. ob_end_clean();
  778. $this->assertRegExp(
  779. '#<div[^>]*id="errormessage"[^>]*>.*Paste does not exist, has expired or has been deleted\.#s',
  780. $content,
  781. 'outputs delete error correctly'
  782. );
  783. }
  784. /**
  785. * @runInSeparateProcess
  786. */
  787. public function testDeleteInvalidToken()
  788. {
  789. $this->_data->create(Helper::getPasteId(), Helper::getPaste());
  790. $_GET['pasteid'] = Helper::getPasteId();
  791. $_GET['deletetoken'] = 'bar';
  792. ob_start();
  793. new Controller;
  794. $content = ob_get_contents();
  795. ob_end_clean();
  796. $this->assertRegExp(
  797. '#<div[^>]*id="errormessage"[^>]*>.*Wrong deletion token\. Paste was not deleted\.#s',
  798. $content,
  799. 'outputs delete error correctly'
  800. );
  801. $this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists after failing to delete data');
  802. }
  803. /**
  804. * @runInSeparateProcess
  805. */
  806. public function testDeleteInvalidBurnAfterReading()
  807. {
  808. $this->_data->create(Helper::getPasteId(), Helper::getPaste());
  809. $this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data');
  810. $file = tempnam(sys_get_temp_dir(), 'FOO');
  811. file_put_contents($file, json_encode(array(
  812. 'deletetoken' => 'burnafterreading',
  813. )));
  814. Request::setInputStream($file);
  815. $_SERVER['QUERY_STRING'] = Helper::getPasteId();
  816. $_GET[Helper::getPasteId()] = '';
  817. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  818. $_SERVER['REQUEST_METHOD'] = 'POST';
  819. ob_start();
  820. new Controller;
  821. $content = ob_get_contents();
  822. ob_end_clean();
  823. $response = json_decode($content, true);
  824. $this->assertEquals(1, $response['status'], 'outputs status');
  825. $this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists after failing to delete data');
  826. }
  827. /**
  828. * @runInSeparateProcess
  829. */
  830. public function testDeleteExpired()
  831. {
  832. $expiredPaste = Helper::getPaste(2, array('expire_date' => 1000));
  833. $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste does not exist before being created');
  834. $this->_data->create(Helper::getPasteId(), $expiredPaste);
  835. $this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data');
  836. $_GET['pasteid'] = Helper::getPasteId();
  837. $_GET['deletetoken'] = 'does not matter in this context, but has to be set';
  838. ob_start();
  839. new Controller;
  840. $content = ob_get_contents();
  841. ob_end_clean();
  842. $this->assertRegExp(
  843. '#<div[^>]*id="errormessage"[^>]*>.*Paste does not exist, has expired or has been deleted\.#s',
  844. $content,
  845. 'outputs error correctly'
  846. );
  847. $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste successfully deleted');
  848. }
  849. /**
  850. * @runInSeparateProcess
  851. */
  852. public function testDeleteMissingPerPasteSalt()
  853. {
  854. $paste = Helper::getPaste();
  855. unset($paste['meta']['salt']);
  856. $this->_data->create(Helper::getPasteId(), $paste);
  857. $this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data');
  858. $_GET['pasteid'] = Helper::getPasteId();
  859. $_GET['deletetoken'] = hash_hmac('sha256', Helper::getPasteId(), ServerSalt::get());
  860. ob_start();
  861. new Controller;
  862. $content = ob_get_contents();
  863. ob_end_clean();
  864. $this->assertRegExp(
  865. '#<div[^>]*id="status"[^>]*>.*Paste was properly deleted\.#s',
  866. $content,
  867. 'outputs deleted status correctly'
  868. );
  869. $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste successfully deleted');
  870. }
  871. }