PrivateBinTest.php 39 KB

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