privatebin.php 36 KB

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