ControllerTest.php 37 KB

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