privatebin.php 35 KB

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