diff --git a/_test/tests/inc/common_ml.test.php b/_test/tests/inc/common_ml.test.php index 6f3b71db446f3f86b56c6bcb2b0d6fc5fcddcce0..415c0a88de4e8f178714af144bb37426ada82279 100644 --- a/_test/tests/inc/common_ml.test.php +++ b/_test/tests/inc/common_ml.test.php @@ -90,6 +90,25 @@ class common_ml_test extends DokuWikiTest { $this->assertEquals($expect, ml($id, $args)); } + function test_ml_img_external() { + global $conf; + $conf['useslash'] = 0; + $conf['userewrite'] = 0; + + $ids = array( + 'https://example.com/lib/tpl/dokuwiki/images/logo.png', + 'http://example.com/lib/tpl/dokuwiki/images/logo.png', + 'ftp://example.com/lib/tpl/dokuwiki/images/logo.png' + ); + + foreach($ids as $id) { + $tok = media_get_token($id, 0, 0); + + $expect = DOKU_BASE.$this->script.'?tok='.$tok.'&media='.rawurlencode($id); + $this->assertEquals($expect, ml($id)); + } + } + function test_ml_imgresize_array_external() { global $conf; $conf['useslash'] = 0; @@ -107,8 +126,24 @@ class common_ml_test extends DokuWikiTest { $tok = media_get_token($id, $w, 0); $hash = substr(PassHash::hmac('md5', $id, auth_cookiesalt()), 0, 6); - $expect = DOKU_BASE.$this->script.'?hash='.$hash.'&w='.$w.'&tok='.$tok.'&media='.rawurlencode($id); + $expect = DOKU_BASE.$this->script.'?w='.$w.'&tok='.$tok.'&media='.rawurlencode($id); $this->assertEquals($expect, ml($id, $args)); } + + $h = 50; + $args = array('h' => $h); + $tok = media_get_token($id, $h, 0); + + $expect = DOKU_BASE.$this->script.'?h='.$h.'&tok='.$tok.'&media='.rawurlencode($id); + $this->assertEquals($expect, ml($id, $args)); + + $w = 80; + $h = 50; + $args = array('w' => $w, 'h' => $h); + $tok = media_get_token($id, $w, $h); + + $expect = DOKU_BASE.$this->script.'?w='.$w.'&h='.$h.'&tok='.$tok.'&media='.rawurlencode($id); + $this->assertEquals($expect, ml($id, $args)); + } } diff --git a/_test/tests/lib/exe/fetch_imagetoken.test.php b/_test/tests/lib/exe/fetch_imagetoken.test.php index 9e5b6e4a26b21a0c8a7c6c9bf75e58efdd71268c..99e6425570e5ce08c3b48750afc7653c2c89190f 100644 --- a/_test/tests/lib/exe/fetch_imagetoken.test.php +++ b/_test/tests/lib/exe/fetch_imagetoken.test.php @@ -23,10 +23,10 @@ class fetch_imagetoken_test extends DokuWikiTest { parent::setUp(); global $conf; - $conf['sendfile'] = 0; + $conf['xsendfile'] = 0; global $MIME, $EXT, $CACHE, $INPUT; // variables fetch creates in global scope -- should this be in fetch? - } + } function getUri() { $w = $this->width ? 'w='.$this->width.'&' : ''; @@ -39,14 +39,14 @@ class fetch_imagetoken_test extends DokuWikiTest { $request = new TestRequest(); return $request->get(array(),str_replace('{%token%}',$token,$this->getUri())); } - - /** + + /** * modified image request with valid token * expect: header with mime-type * expect: content * expect: no error response - */ - function test_valid_token(){ + */ + function test_valid_token(){ $valid_token = 'tok='.media_get_token($this->media, $this->width, $this->height).'&'; $response = $this->fetchResponse($valid_token); $this->assertTrue((bool)$response->getHeader('Content-Type')); @@ -54,24 +54,24 @@ class fetch_imagetoken_test extends DokuWikiTest { $status_code = $response->getStatusCode(); $this->assertTrue(is_null($status_code) || (200 == $status_code)); - } - - /** + } + + /** * modified image request with invalid token - * expect: 412 status code - */ - function test_invalid_token(){ - $invalid_token = 'tok='.media_get_token('junk',200,100).'&'; - $this->assertEquals(412,$this->fetchResponse($invalid_token)->getStatusCode()); - } - - /** - * modified image request with no token * expect: 412 status code - */ - function test_missing_token(){ - $no_token = ''; - $this->assertEquals(412,$this->fetchResponse($notoken)->getStatusCode()); + */ + function test_invalid_token(){ + $invalid_token = 'tok='.media_get_token('junk',200,100).'&'; + $this->assertEquals(412,$this->fetchResponse($invalid_token)->getStatusCode()); + } + + /** + * modified image request with no token + * expect: 412 status code + */ + function test_missing_token(){ + $no_token = ''; + $this->assertEquals(412,$this->fetchResponse($no_token)->getStatusCode()); } /** diff --git a/_test/tests/lib/exe/fetch_statuscodes_external.test.php b/_test/tests/lib/exe/fetch_statuscodes_external.test.php new file mode 100644 index 0000000000000000000000000000000000000000..79a45ec93c6dbf28ebda345a1e377d839aa58822 --- /dev/null +++ b/_test/tests/lib/exe/fetch_statuscodes_external.test.php @@ -0,0 +1,107 @@ +<?php + +/** + * @group internet + */ +class fetch_statuscodes_external_test extends DokuWikiTest { + + private $media = 'http://www.google.com/images/srpr/logo3w.png'; //used in media_get_from_url test too + private $width = 200; + private $height = 0; + + function setUp() { + + header('X-Test: check headers working'); + $header_check = function_exists('xdebug_get_headers') ? xdebug_get_headers() : headers_list(); + if(empty($header_check)) { + $this->markTestSkipped('headers not returned, perhaps your sapi does not return headers, try xdebug'); + } else { + header_remove('X-Test'); + } + + parent::setUp(); + + global $conf; + $conf['fetchsize'] = 500 * 1024; //500kb + $conf['xsendfile'] = 0; + + global $MIME, $EXT, $CACHE, $INPUT; // variables fetch creates in global scope -- should this be in fetch? + } + + function getUri() { + $w = $this->width ? 'w='.$this->width.'&' : ''; + $h = $this->height ? 'h='.$this->height.'&' : ''; + return '/lib/exe/fetch.php?'.$w.$h.'{%token%}media='.rawurlencode($this->media); + } + + function fetchResponse($token) { + $request = new TestRequest(); + return $request->get(array(), str_replace('{%token%}', $token, $this->getUri())); + } + + /** + * modified image request with valid token + * and not-modified image request with valid token + * + * expect: header with mime-type + * expect: content + * expect: no error response + */ + function test_valid_token() { + $valid_token_resize = 'tok='.media_get_token($this->media, $this->width, $this->height).'&'; + + $this->handlevalidresponse($valid_token_resize); + + //original size + $this->width = $this->height = 0; + $valid_token_original = 'tok='.media_get_token($this->media, $this->width, $this->height).'&'; + + $this->handlevalidresponse($valid_token_original); + + } + + /** + * Performs asserts for valid request + * + * @param $valid_token + */ + private function handlevalidresponse($valid_token){ + $response = $this->fetchResponse($valid_token); + $this->assertTrue((bool) $response->getHeader('Content-Type')); + $this->assertTrue((bool) ($response->getContent())); + + $status_code = $response->getStatusCode(); + $this->assertTrue(is_null($status_code) || (200 == $status_code)); + } + + /** + * modified image request with invalid token + * expect: 412 status code + */ + function test_invalid_token() { + $invalid_tokens = array( + 'invalid_token_wrongid' => media_get_token('junk', 200, 100), + 'invalid_token_wrongh' => media_get_token($this->media, 200, 10), + 'invalid_token_wrongw' => media_get_token($this->media, 20, 100), + 'invalid_token_wrongwh' => media_get_token($this->media, 20, 10) + ); + foreach($invalid_tokens as $invalid_token) + $this->assertEquals(412, $this->fetchResponse('tok='.$invalid_token.'&')->getStatusCode()); + + } + + /** + * modified image request with no token + * and not modified image with no token + * expect: 412 status code + */ + function test_missing_token() { + $no_token = ''; + + $this->assertEquals(412, $this->fetchResponse($no_token)->getStatusCode()); + + $this->width = $this->height = 0; + $this->assertEquals(412, $this->fetchResponse($no_token)->getStatusCode()); + } +} +//Setup VIM: ex: et ts=4 : diff --git a/inc/common.php b/inc/common.php index bff6e80de214fdd4af9bdb95b41db9fd5db12d8d..3312141c8362d472e82d6e9743664b5fcfe9d589 100644 --- a/inc/common.php +++ b/inc/common.php @@ -148,7 +148,7 @@ function pageinfo() { $info['id'] = $ID; $info['rev'] = $REV; - if(isset($_SERVER['REMOTE_USER'])) { + if(isset($_SERVER['REMOTE_USER'])) { $sub = new Subscription(); $info['subscribed'] = $sub->user_subscription(); } else { @@ -474,7 +474,7 @@ function ml($id = '', $more = '', $direct = true, $sep = '&', $abs = false) if(is_array($more)) { // add token for resized images - if($more['w'] || $more['h']){ + if($more['w'] || $more['h'] || $isexternalimage){ $more['tok'] = media_get_token($id,$more['w'],$more['h']); } // strip defaults for shorter URLs @@ -485,12 +485,13 @@ function ml($id = '', $more = '', $direct = true, $sep = '&', $abs = false) $more = buildURLparams($more, $sep); } else { $matches = array(); - if (preg_match_all('/\b(w|h)=(\d*)\b/',$more,$matches,PREG_SET_ORDER)){ + if (preg_match_all('/\b(w|h)=(\d*)\b/',$more,$matches,PREG_SET_ORDER) || $isexternalimage){ $resize = array('w'=>0, 'h'=>0); foreach ($matches as $match){ $resize[$match[1]] = $match[2]; } - $more .= $sep.'tok='.media_get_token($id,$resize['w'],$resize['h']); + $more .= $more === '' ? '' : $sep; + $more .= 'tok='.media_get_token($id,$resize['w'],$resize['h']); } $more = str_replace('cache=cache', '', $more); //skip default $more = str_replace(',,', ',', $more); @@ -506,14 +507,8 @@ function ml($id = '', $more = '', $direct = true, $sep = '&', $abs = false) // external URLs are always direct without rewriting if($isexternalimage) { $xlink .= 'lib/exe/fetch.php'; - // add hash: - $xlink .= '?hash='.substr(PassHash::hmac('md5', $id, auth_cookiesalt()), 0, 6); - if($more) { - $xlink .= $sep.$more; - $xlink .= $sep.'media='.rawurlencode($id); - } else { - $xlink .= $sep.'media='.rawurlencode($id); - } + $xlink .= '?'.$more; + $xlink .= $sep.'media='.rawurlencode($id); return $xlink; } diff --git a/inc/fetch.functions.php b/inc/fetch.functions.php index 53ade3555f78d79042b620ce137d1f9af5cacb9f..207ad9e5face6ba2a18bd35bef5c530f930beed4 100644 --- a/inc/fetch.functions.php +++ b/inc/fetch.functions.php @@ -101,8 +101,8 @@ function checkFileStatus(&$media, &$file, $rev = '', $width=0, $height=0) { //media to local file if(media_isexternal($media)) { - //check hash - if(substr(PassHash::hmac('md5', $media, auth_cookiesalt()), 0, 6) !== $INPUT->str('hash')) { + //check token for external image and additional for resized and cached images + if(media_get_token($media, $width, $height) !== $INPUT->str('tok')) { return array(412, 'Precondition Failed'); } //handle external images diff --git a/inc/media.php b/inc/media.php index c76f2986cf2365780dacdf75b9f1d829a9f7c9a2..c4378fe9e5c51af9130ecdee5926b831971ca9b5 100644 --- a/inc/media.php +++ b/inc/media.php @@ -1900,7 +1900,7 @@ function media_crop_image($file, $ext, $w, $h=0){ */ function media_get_token($id,$w,$h){ // token is only required for modified images - if ($w || $h) { + if ($w || $h || media_isexternal($id)) { $token = $id; if ($w) $token .= '.'.$w; if ($h) $token .= '.'.$h; diff --git a/lib/exe/fetch.php b/lib/exe/fetch.php index 7a225037396cea8472e0a966aeb6bc7f47501185..5967494bfd24b0179f8a8a30d19a80846212dec5 100644 --- a/lib/exe/fetch.php +++ b/lib/exe/fetch.php @@ -60,6 +60,7 @@ if (defined('SIMPLE_TEST')) { if($evt->advise_before()) { // redirects if($data['status'] > 300 && $data['status'] <= 304) { + if (defined('SIMPLE_TEST')) return; //TestResponse doesn't recognize redirects send_redirect($data['statusmessage']); } // send any non 200 status