ControllerTest.php 36 KB

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