JsonApiTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. <?php
  2. use PrivateBin\Controller;
  3. use PrivateBin\Data\Filesystem;
  4. use PrivateBin\Persistence\ServerSalt;
  5. use PrivateBin\Request;
  6. class JsonApiTest extends PHPUnit_Framework_TestCase
  7. {
  8. protected $_model;
  9. protected $_path;
  10. public function setUp()
  11. {
  12. /* Setup Routine */
  13. $this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
  14. if (!is_dir($this->_path)) {
  15. mkdir($this->_path);
  16. }
  17. $this->_model = Filesystem::getInstance(array('dir' => $this->_path));
  18. ServerSalt::setStore($this->_model);
  19. $_POST = array();
  20. $_GET = array();
  21. $_SERVER = array();
  22. if ($this->_model->exists(Helper::getPasteId())) {
  23. $this->_model->delete(Helper::getPasteId());
  24. }
  25. $options = parse_ini_file(CONF_SAMPLE, true);
  26. $options['model_options']['dir'] = $this->_path;
  27. Helper::confBackup();
  28. Helper::createIniFile(CONF, $options);
  29. }
  30. public function tearDown()
  31. {
  32. /* Tear Down Routine */
  33. unlink(CONF);
  34. Helper::confRestore();
  35. Helper::rmDir($this->_path);
  36. }
  37. /**
  38. * @runInSeparateProcess
  39. */
  40. public function testCreate()
  41. {
  42. $options = parse_ini_file(CONF, true);
  43. $options['traffic']['limit'] = 0;
  44. Helper::createIniFile(CONF, $options);
  45. $paste = Helper::getPasteJson();
  46. $file = tempnam(sys_get_temp_dir(), 'FOO');
  47. file_put_contents($file, $paste);
  48. Request::setInputStream($file);
  49. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  50. $_SERVER['REQUEST_METHOD'] = 'POST';
  51. $_SERVER['REMOTE_ADDR'] = '::1';
  52. $_SERVER['REQUEST_URI'] = '/';
  53. ob_start();
  54. new Controller;
  55. $content = ob_get_contents();
  56. ob_end_clean();
  57. $response = json_decode($content, true);
  58. $this->assertEquals(0, $response['status'], 'outputs status');
  59. $this->assertStringEndsWith('?' . $response['id'], $response['url'], 'returned URL points to new paste');
  60. $this->assertTrue($this->_model->exists($response['id']), 'paste exists after posting data');
  61. $paste = $this->_model->read($response['id']);
  62. $this->assertEquals(
  63. hash_hmac('sha256', $response['id'], $paste['meta']['salt']),
  64. $response['deletetoken'],
  65. 'outputs valid delete token'
  66. );
  67. }
  68. /**
  69. * @runInSeparateProcess
  70. */
  71. public function testPut()
  72. {
  73. $options = parse_ini_file(CONF, true);
  74. $options['traffic']['limit'] = 0;
  75. Helper::createIniFile(CONF, $options);
  76. $paste = Helper::getPasteJson();
  77. $file = tempnam(sys_get_temp_dir(), 'FOO');
  78. file_put_contents($file, $paste);
  79. Request::setInputStream($file);
  80. $_SERVER['QUERY_STRING'] = Helper::getPasteId();
  81. $_GET[Helper::getPasteId()] = '';
  82. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  83. $_SERVER['REQUEST_METHOD'] = 'PUT';
  84. $_SERVER['REMOTE_ADDR'] = '::1';
  85. ob_start();
  86. new Controller;
  87. $content = ob_get_contents();
  88. ob_end_clean();
  89. unlink($file);
  90. $response = json_decode($content, true);
  91. $this->assertEquals(0, $response['status'], 'outputs status');
  92. $this->assertEquals(Helper::getPasteId(), $response['id'], 'outputted paste ID matches input');
  93. $this->assertStringEndsWith('?' . $response['id'], $response['url'], 'returned URL points to new paste');
  94. $this->assertTrue($this->_model->exists($response['id']), 'paste exists after posting data');
  95. $paste = $this->_model->read($response['id']);
  96. $this->assertEquals(
  97. hash_hmac('sha256', $response['id'], $paste['meta']['salt']),
  98. $response['deletetoken'],
  99. 'outputs valid delete token'
  100. );
  101. }
  102. /**
  103. * @runInSeparateProcess
  104. */
  105. public function testDelete()
  106. {
  107. $this->_model->create(Helper::getPasteId(), Helper::getPaste());
  108. $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data');
  109. $paste = $this->_model->read(Helper::getPasteId());
  110. $file = tempnam(sys_get_temp_dir(), 'FOO');
  111. file_put_contents($file, json_encode(array(
  112. 'deletetoken' => hash_hmac('sha256', Helper::getPasteId(), $paste['meta']['salt']),
  113. )));
  114. Request::setInputStream($file);
  115. $_SERVER['QUERY_STRING'] = Helper::getPasteId();
  116. $_GET[Helper::getPasteId()] = '';
  117. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  118. $_SERVER['REQUEST_METHOD'] = 'DELETE';
  119. ob_start();
  120. new Controller;
  121. $content = ob_get_contents();
  122. ob_end_clean();
  123. unlink($file);
  124. $response = json_decode($content, true);
  125. $this->assertEquals(0, $response['status'], 'outputs status');
  126. $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste successfully deleted');
  127. }
  128. /**
  129. * @runInSeparateProcess
  130. */
  131. public function testDeleteWithPost()
  132. {
  133. $this->_model->create(Helper::getPasteId(), Helper::getPaste());
  134. $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data');
  135. $paste = $this->_model->read(Helper::getPasteId());
  136. $file = tempnam(sys_get_temp_dir(), 'FOO');
  137. file_put_contents($file, json_encode(array(
  138. 'pasteid' => Helper::getPasteId(),
  139. 'deletetoken' => hash_hmac('sha256', Helper::getPasteId(), $paste['meta']['salt']),
  140. )));
  141. Request::setInputStream($file);
  142. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  143. $_SERVER['REQUEST_METHOD'] = 'POST';
  144. ob_start();
  145. new Controller;
  146. $content = ob_get_contents();
  147. ob_end_clean();
  148. $response = json_decode($content, true);
  149. $this->assertEquals(0, $response['status'], 'outputs status');
  150. $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste successfully deleted');
  151. }
  152. /**
  153. * @runInSeparateProcess
  154. */
  155. public function testRead()
  156. {
  157. $paste = Helper::getPaste();
  158. $this->_model->create(Helper::getPasteId(), $paste);
  159. $_SERVER['QUERY_STRING'] = Helper::getPasteId();
  160. $_GET[Helper::getPasteId()] = '';
  161. $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
  162. ob_start();
  163. new Controller;
  164. $content = ob_get_contents();
  165. ob_end_clean();
  166. $response = json_decode($content, true);
  167. $this->assertEquals(0, $response['status'], 'outputs success status');
  168. $this->assertEquals(Helper::getPasteId(), $response['id'], 'outputs data correctly');
  169. $this->assertStringEndsWith('?' . $response['id'], $response['url'], 'returned URL points to new paste');
  170. $this->assertEquals($paste['ct'], $response['ct'], 'outputs data correctly');
  171. $this->assertEquals($paste['meta']['created'], $response['meta']['created'], 'outputs postdate correctly');
  172. $this->assertEquals(0, $response['comment_count'], 'outputs comment_count correctly');
  173. $this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly');
  174. }
  175. /**
  176. * @runInSeparateProcess
  177. */
  178. public function testJsonLdPaste()
  179. {
  180. $_GET['jsonld'] = 'paste';
  181. ob_start();
  182. new Controller;
  183. $content = ob_get_contents();
  184. ob_end_clean();
  185. $this->assertEquals(str_replace(
  186. '?jsonld=',
  187. '/?jsonld=',
  188. file_get_contents(PUBLIC_PATH . '/js/paste.jsonld')
  189. ), $content, 'outputs data correctly');
  190. }
  191. /**
  192. * @runInSeparateProcess
  193. */
  194. public function testJsonLdComment()
  195. {
  196. $_GET['jsonld'] = 'comment';
  197. ob_start();
  198. new Controller;
  199. $content = ob_get_contents();
  200. ob_end_clean();
  201. $this->assertEquals(str_replace(
  202. '?jsonld=',
  203. '/?jsonld=',
  204. file_get_contents(PUBLIC_PATH . '/js/comment.jsonld')
  205. ), $content, 'outputs data correctly');
  206. }
  207. /**
  208. * @runInSeparateProcess
  209. */
  210. public function testJsonLdPasteMeta()
  211. {
  212. $_GET['jsonld'] = 'pastemeta';
  213. ob_start();
  214. new Controller;
  215. $content = ob_get_contents();
  216. ob_end_clean();
  217. $this->assertEquals(str_replace(
  218. '?jsonld=',
  219. '/?jsonld=',
  220. file_get_contents(PUBLIC_PATH . '/js/pastemeta.jsonld')
  221. ), $content, 'outputs data correctly');
  222. }
  223. /**
  224. * @runInSeparateProcess
  225. */
  226. public function testJsonLdCommentMeta()
  227. {
  228. $_GET['jsonld'] = 'commentmeta';
  229. ob_start();
  230. new Controller;
  231. $content = ob_get_contents();
  232. ob_end_clean();
  233. $this->assertEquals(str_replace(
  234. '?jsonld=',
  235. '/?jsonld=',
  236. file_get_contents(PUBLIC_PATH . '/js/commentmeta.jsonld')
  237. ), $content, 'outputs data correctly');
  238. }
  239. /**
  240. * @runInSeparateProcess
  241. */
  242. public function testJsonLdInvalid()
  243. {
  244. $_GET['jsonld'] = CONF;
  245. ob_start();
  246. new Controller;
  247. $content = ob_get_contents();
  248. ob_end_clean();
  249. $this->assertEquals('{}', $content, 'does not output nasty data');
  250. }
  251. /**
  252. * @runInSeparateProcess
  253. */
  254. public function testShortenViaYourls()
  255. {
  256. $mock_yourls_service = $this->_path . DIRECTORY_SEPARATOR . 'yourls.json';
  257. $options = parse_ini_file(CONF, true);
  258. $options['main']['basepath'] = 'https://example.com/path/';
  259. $options['main']['urlshortener'] = 'https://example.com/path/shortenviayourls?link=';
  260. $options['yourls']['apiurl'] = $mock_yourls_service;
  261. Helper::createIniFile(CONF, $options);
  262. // the real service answer is more complex, but we only look for the shorturl & statusCode
  263. file_put_contents($mock_yourls_service, '{"shorturl":"https:\/\/example.com\/1","statusCode":200}');
  264. $_SERVER['REQUEST_URI'] = '/path/shortenviayourls?link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar';
  265. $_GET['link'] = 'https://example.com/path/?foo#bar';
  266. ob_start();
  267. new Controller;
  268. $content = ob_get_contents();
  269. ob_end_clean();
  270. $this->assertContains('id="pasteurl" href="https://example.com/1"', $content, 'outputs shortened URL correctly');
  271. }
  272. /**
  273. * @runInSeparateProcess
  274. */
  275. public function testShortenViaYourlsFailure()
  276. {
  277. $_SERVER['REQUEST_URI'] = '/path/shortenviayourls?link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar';
  278. $_GET['link'] = 'https://example.com/path/?foo#bar';
  279. ob_start();
  280. new Controller;
  281. $content = ob_get_contents();
  282. ob_end_clean();
  283. $this->assertContains('Error calling YOURLS.', $content, 'outputs error correctly');
  284. }
  285. }