diff --git a/lib/Controller.php b/lib/Controller.php index 8d7f0f13..1efd1145 100644 --- a/lib/Controller.php +++ b/lib/Controller.php @@ -383,12 +383,12 @@ class Controller $page = new View; $page->assign('CSPHEADER', $metacspheader); $page->assign('ERROR', I18n::_($this->_error)); + $page->assign('NAME', $this->_conf->getKey('name')); if ($this->_request->getOperation() === 'yourlsproxy') { $page->assign('SHORTURL', $this->_status); $page->draw('yourlsproxy'); return; } - $page->assign('NAME', $this->_conf->getKey('name')); $page->assign('BASEPATH', I18n::_($this->_conf->getKey('basepath'))); $page->assign('STATUS', I18n::_($this->_status)); $page->assign('VERSION', self::VERSION); diff --git a/lib/Request.php b/lib/Request.php index 9ed73074..ea566f5c 100644 --- a/lib/Request.php +++ b/lib/Request.php @@ -137,8 +137,7 @@ class Request } elseif (array_key_exists('jsonld', $this->_params) && !empty($this->_params['jsonld'])) { $this->_operation = 'jsonld'; } elseif (array_key_exists('link', $this->_params) && !empty($this->_params['link'])) { - $request_url = filter_var($_SERVER['REQUEST_URI'], FILTER_SANITIZE_URL); - if (strpos($request_url, '/shortenviayourls?link=') !== false) { + if (strpos($this->getRequestUri(), '/shortenviayourls') !== false) { $this->_operation = 'yourlsproxy'; } } diff --git a/lib/YourlsProxy.php b/lib/YourlsProxy.php index 8a1a4d9e..858317a2 100644 --- a/lib/YourlsProxy.php +++ b/lib/YourlsProxy.php @@ -53,8 +53,14 @@ class YourlsProxy return; } + $yourls_api_url = $conf->getKey('apiurl', 'yourls'); + if (empty($yourls_api_url)) { + $this->_error = 'Error calling YOURLS. Probably a configuration issue, like wrong or missing "apiurl" or "signature".'; + return; + } + $data = file_get_contents( - $conf->getKey('apiurl', 'yourls'), false, stream_context_create( + $yourls_api_url, false, stream_context_create( array( 'http' => array( 'method' => 'POST', @@ -71,23 +77,19 @@ class YourlsProxy ) ) ); - if ($data === false || !is_string($data)) { - $this->_error = 'Error calling YOURLS. Probably a configuration issue, like wrong or missing "apiurl" or "signature".'; - return; - } - try { $data = Json::decode($data); } catch (Exception $e) { - $this->_error = $e->getMessage(); + $this->_error = 'Error calling YOURLS. Probably a configuration issue, like wrong or missing "apiurl" or "signature".'; + error_log('Error calling YOURLS: ' . $e->getMessage()); return; } if ( !is_null($data) && array_key_exists('statusCode', $data) && - array_key_exists('shorturl', $data) && - $data['statusCode'] == 200 + $data['statusCode'] == 200 && + array_key_exists('shorturl', $data) ) { $this->_url = $data['shorturl']; } else { diff --git a/tst/ControllerTest.php b/tst/ControllerTest.php index 5c951273..e1637c11 100644 --- a/tst/ControllerTest.php +++ b/tst/ControllerTest.php @@ -48,6 +48,7 @@ class ControllerTest extends PHPUnit_Framework_TestCase */ public function testView() { + $_SERVER['HTTP_HOST'] = 'example.com'; $_SERVER['QUERY_STRING'] = Helper::getPasteId(); $_GET[Helper::getPasteId()] = ''; ob_start(); @@ -64,6 +65,11 @@ class ControllerTest extends PHPUnit_Framework_TestCase $content, 'doesn\'t output shortener button' ); + $this->assertRegExp( + '# href="https://' . preg_quote($_SERVER['HTTP_HOST']) . '/">switching to HTTPS#', + $content, + 'outputs configured https URL correctly' + ); } /** diff --git a/tst/JsonApiTest.php b/tst/JsonApiTest.php index 6d9732a5..058bd320 100644 --- a/tst/JsonApiTest.php +++ b/tst/JsonApiTest.php @@ -15,6 +15,9 @@ class JsonApiTest extends PHPUnit_Framework_TestCase { /* Setup Routine */ $this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data'; + if (!is_dir($this->_path)) { + mkdir($this->_path); + } $this->_model = Filesystem::getInstance(array('dir' => $this->_path)); ServerSalt::setStore($this->_model); @@ -186,8 +189,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase */ public function testJsonLdPaste() { - $paste = Helper::getPaste(); - $this->_model->create(Helper::getPasteId(), $paste); $_GET['jsonld'] = 'paste'; ob_start(); new Controller; @@ -205,8 +206,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase */ public function testJsonLdComment() { - $paste = Helper::getPaste(); - $this->_model->create(Helper::getPasteId(), $paste); $_GET['jsonld'] = 'comment'; ob_start(); new Controller; @@ -224,8 +223,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase */ public function testJsonLdPasteMeta() { - $paste = Helper::getPaste(); - $this->_model->create(Helper::getPasteId(), $paste); $_GET['jsonld'] = 'pastemeta'; ob_start(); new Controller; @@ -243,8 +240,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase */ public function testJsonLdCommentMeta() { - $paste = Helper::getPaste(); - $this->_model->create(Helper::getPasteId(), $paste); $_GET['jsonld'] = 'commentmeta'; ob_start(); new Controller; @@ -262,8 +257,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase */ public function testJsonLdInvalid() { - $paste = Helper::getPaste(); - $this->_model->create(Helper::getPasteId(), $paste); $_GET['jsonld'] = CONF; ob_start(); new Controller; @@ -271,4 +264,42 @@ class JsonApiTest extends PHPUnit_Framework_TestCase ob_end_clean(); $this->assertEquals('{}', $content, 'does not output nasty data'); } + + /** + * @runInSeparateProcess + */ + public function testShortenViaYourls() + { + $mock_yourls_service = $this->_path . DIRECTORY_SEPARATOR . 'yourls.json'; + $options = parse_ini_file(CONF, true); + $options['main']['basepath'] = 'https://example.com/path'; + $options['main']['urlshortener'] = 'https://example.com/path/shortenviayourls?link='; + $options['yourls']['apiurl'] = $mock_yourls_service; + Helper::createIniFile(CONF, $options); + + // the real service answer is more complex, but we only look for the shorturl & statusCode + file_put_contents($mock_yourls_service, '{"shorturl":"https:\/\/example.com\/1","statusCode":200}'); + + $_SERVER['REQUEST_URI'] = '/path/shortenviayourls?link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar'; + $_GET['link'] = 'https://example.com/path/?foo#bar'; + ob_start(); + new Controller; + $content = ob_get_contents(); + ob_end_clean(); + $this->assertContains('id="pasteurl" href="https://example.com/1"', $content, 'outputs shortened URL correctly'); + } + + /** + * @runInSeparateProcess + */ + public function testShortenViaYourlsFailure() + { + $_SERVER['REQUEST_URI'] = '/path/shortenviayourls?link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar'; + $_GET['link'] = 'https://example.com/path/?foo#bar'; + ob_start(); + new Controller; + $content = ob_get_contents(); + ob_end_clean(); + $this->assertContains('Error calling YOURLS.', $content, 'outputs error correctly'); + } } diff --git a/tst/YourlsProxyTest.php b/tst/YourlsProxyTest.php new file mode 100644 index 00000000..8c90112c --- /dev/null +++ b/tst/YourlsProxyTest.php @@ -0,0 +1,75 @@ +_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data'; + if (!is_dir($this->_path)) { + mkdir($this->_path); + } + $this->_mock_yourls_service = $this->_path . DIRECTORY_SEPARATOR . 'yourls.json'; + $options = parse_ini_file(CONF_SAMPLE, true); + $options['main']['basepath'] = 'https://example.com'; + $options['main']['urlshortener'] = 'https://example.com/shortenviayourls?link='; + $options['yourls']['apiurl'] = $this->_mock_yourls_service; + Helper::confBackup(); + Helper::createIniFile(CONF, $options); + $this->_conf = new Configuration; + } + + public function tearDown() + { + /* Tear Down Routine */ + unlink(CONF); + Helper::confRestore(); + Helper::rmDir($this->_path); + } + + public function testYourlsProxy() + { + // the real service answer is more complex, but we only look for the shorturl & statusCode + file_put_contents($this->_mock_yourls_service, '{"shorturl":"https:\/\/example.com\/1","statusCode":200}'); + + $yourls = new YourlsProxy($this->_conf, 'https://example.com/?foo#bar'); + $this->assertFalse($yourls->isError()); + $this->assertEquals($yourls->getUrl(), 'https://example.com/1'); + } + + public function testForeignUrl() + { + $yourls = new YourlsProxy($this->_conf, 'https://other.example.com/?foo#bar'); + $this->assertTrue($yourls->isError()); + $this->assertEquals($yourls->getError(), 'Trying to shorten a URL that isn\'t pointing at our instance.'); + } + + public function testYourlsError() + { + // when statusCode is not 200, shorturl may not have been set + file_put_contents($this->_mock_yourls_service, '{"statusCode":403}'); + + $yourls = new YourlsProxy($this->_conf, 'https://example.com/?foo#bar'); + $this->assertTrue($yourls->isError()); + $this->assertEquals($yourls->getError(), 'Error parsing YOURLS response.'); + } + + public function testServerError() + { + // simulate some other server error that results in a non-JSON reply + file_put_contents($this->_mock_yourls_service, ''); + + $yourls = new YourlsProxy($this->_conf, 'https://example.com/?foo#bar'); + $this->assertTrue($yourls->isError()); + $this->assertEquals($yourls->getError(), 'Error calling YOURLS. Probably a configuration issue, like wrong or missing "apiurl" or "signature".'); + } +} \ No newline at end of file