1
0

ControllerTest.php 37 KB

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