diff --git a/_test/tests/inc/remoteapicore.test.php b/_test/tests/inc/remoteapicore.test.php new file mode 100644 index 0000000000000000000000000000000000000000..a83a4eb26cc835f7204bf55e21b2b40aa80a7e24 --- /dev/null +++ b/_test/tests/inc/remoteapicore.test.php @@ -0,0 +1,424 @@ +<?php + +/** + * Class remoteapicore_test + */ +class remoteapicore_test extends DokuWikiTest { + + protected $userinfo; + protected $oldAuthAcl; + /** @var RemoteAPI */ + protected $remote; + + public function setUp() { + parent::setUp(); + global $conf; + global $USERINFO; + global $AUTH_ACL; + global $auth; + $this->oldAuthAcl = $AUTH_ACL; + $this->userinfo = $USERINFO; + $auth = new DokuWiki_Auth_Plugin(); + + $conf['remote'] = 1; + $conf['remoteuser'] = '@user'; + $conf['useacl'] = 0; + + $this->remote = new RemoteAPI(); + } + + public function tearDown() { + global $USERINFO; + global $AUTH_ACL; + + $USERINFO = $this->userinfo; + $AUTH_ACL = $this->oldAuthAcl; + + } + + public function test_core() { + $this->assertEquals(getVersion(), $this->remote->call('dokuwiki.getVersion')); +// $params = array('user', 'passwrd'); +// $this->assertEquals(, $remoteApi->call('dokuwiki.login')); //TODO + +// $this->assertEquals(, $remoteApi->call('dokuwiki.logoff')); //TODO + + $file1 = wikiFN('wiki:dokuwiki'); + $file2 = wikiFN('wiki:syntax'); + $expected = array( + array( + 'id' => 'wiki:dokuwiki', + 'rev' => filemtime($file1), + 'mtime' => filemtime($file1), + 'size' => filesize($file1), + 'hash' => md5(trim(rawWiki('wiki:dokuwiki'))) + ), + array( + 'id' => 'wiki:syntax', + 'rev' => filemtime($file2), + 'mtime' => filemtime($file2), + 'size' => filesize($file2), + 'hash' => md5(trim(rawWiki('wiki:syntax'))) + ) + ); + $params = array( + 'wiki:', + array( + 'depth' => 0, // 0 for all + 'hash' => 1, + 'skipacl' => 1 // is ignored + ) + ); + $this->assertEquals($expected, $this->remote->call('dokuwiki.getPagelist', $params)); + + idx_addPage('wiki:syntax'); //full text search depends on index + $expected = array( + array( + 'id' => 'wiki:syntax', + 'score' => 1, + 'rev' => filemtime($file2), + 'mtime' => filemtime($file2), + 'size' => filesize($file2), + 'snippet' => ' a footnote)) by using double parentheses. + +===== <strong class="search_hit">Sectioning</strong> ===== + +You can use up to five different levels of', + 'title' => 'wiki:syntax' + ) + ); + $params = array('Sectioning'); + $this->assertEquals($expected, $this->remote->call('dokuwiki.search', $params)); + + $timeexpect = time(); + $timeactual = $this->remote->call('dokuwiki.getTime'); + $this->assertTrue(($timeexpect <= $timeactual) && ($timeactual <= $timeexpect + 1)); + + $expected = array( + 'locked' => array('wiki:dokuwiki', 'wiki:syntax', 'nonexisting'), + 'lockfail' => array(), + 'unlocked' => array(), + 'unlockfail' => array(), + ); + $params = array( + array( + 'lock' => array('wiki:dokuwiki', 'wiki:syntax', 'nonexisting'), + 'unlock' => array() + ) + ); + $this->assertEquals($expected, $this->remote->call('dokuwiki.setLocks', $params)); + + $expected = array( + 'locked' => array(), + 'lockfail' => array(), + 'unlocked' => array('wiki:dokuwiki', 'wiki:syntax', 'nonexisting'), + 'unlockfail' => array('nonexisting2'), + ); + $params = array( + array( + 'lock' => array(), + 'unlock' => array('wiki:dokuwiki', 'wiki:syntax', 'nonexisting', 'nonexisting2') + ) + ); + $this->assertEquals($expected, $this->remote->call('dokuwiki.setLocks', $params)); + + global $conf; + $this->assertEquals($conf['title'], $this->remote->call('dokuwiki.getTitle')); + + $file3 = wikiFN('nice_page'); + $content = "====Title====\nText"; + $params = array( + 'nice_page', + $content, + array( + 'minor' => false, + 'sum' => 'Summary of nice text' + ) + ); + $this->assertEquals(true, $this->remote->call('wiki.putPage', $params)); //TODO check exceptions + $this->assertEquals($content, rawWiki('nice_page')); + + $rev[1] = filemtime(wikiFN('nice_page')); //stored for later + sleep(1); // wait for new revision ID + + $params = array('nice_page'); + $this->assertEquals($content, $this->remote->call('wiki.getPage', $params)); + + $morecontent = "\nOther text."; + $secondcontent = $content . $morecontent; + $params_append = array( + 'nice_page', + $morecontent, + array() + ); + $this->assertEquals(true, $this->remote->call('dokuwiki.appendPage', $params_append)); + $this->assertEquals($secondcontent, rawWiki('nice_page')); + + $params = array('nice_page', ''); + $this->assertEquals($secondcontent, $this->remote->call('wiki.getPageVersion', $params)); + $params = array('nice_page', $rev[1]); + $this->assertEquals($content, $this->remote->call('wiki.getPageVersion', $params)); + $params = array('nice_page', 1234); + $this->assertEquals('', $this->remote->call('wiki.getPageVersion', $params), 'Not existing revision'); + $params = array('notexisting', 1234); + $this->assertEquals('', $this->remote->call('wiki.getPageVersion', $params), 'Not existing page'); + + $html1 = "\n<h3 class=\"sectionedit1\" id=\"title\">Title</h3>\n<div class=\"level3\">\n\n<p>\nText\n"; + $html2 = "Other text.\n"; + $html3 = "</p>\n\n</div>\n"; + $params = array('nice_page'); + $this->assertEquals($html1 . $html2 . $html3, $this->remote->call('wiki.getPageHTML', $params)); + + $params = array('nice_page', ''); + $this->assertEquals($html1 . $html2 . $html3, $this->remote->call('wiki.getPageHTMLVersion', $params)); + $params = array('nice_page', $rev[1]); + $this->assertEquals($html1 . $html3, $this->remote->call('wiki.getPageHTMLVersion', $params)); + $params = array('nice_page', 1234); + $this->assertEquals('', $this->remote->call('wiki.getPageHTMLVersion', $params)); + + $expected = array( + array( + 'id' => 'wiki:syntax', + 'perms' => 8, + 'size' => filesize($file2), + 'lastModified' => filemtime($file2) + ), + array( + 'id' => 'nice_page', + 'perms' => 8, + 'size' => filesize($file3), + 'lastModified' => filemtime($file3) + ) + ); + $this->assertEquals($expected, $this->remote->call('wiki.getAllPages')); //only indexed pages + + $params = array('wiki:syntax'); + $this->assertEquals(ft_backlinks('wiki:syntax'), $this->remote->call('wiki.getBackLinks', $params)); + + $expected = array( + 'name' => 'nice_page', + 'lastModified' => filemtime($file3), + 'author' => clientIP(), + 'version' => filemtime($file3) + ); + $params = array('nice_page'); + $this->assertEquals($expected, $this->remote->call('wiki.getPageInfo', $params)); + + $expected = array( + 'name' => 'nice_page', + 'lastModified' => $rev[1], + 'author' => clientIP(), + 'version' => $rev[1] + ); + $params = array('nice_page', $rev[1]); + $this->assertEquals($expected, $this->remote->call('wiki.getPageInfoVersion', $params)); + + $rev[2] = filemtime(wikiFN('nice_page')); + sleep(1); // wait for new revision ID + $this->remote->call('dokuwiki.appendPage', $params_append); + $rev[3] = filemtime(wikiFN('nice_page')); + sleep(1); + $this->remote->call('dokuwiki.appendPage', $params_append); + $rev[4] = filemtime(wikiFN('nice_page')); + sleep(1); + $this->remote->call('dokuwiki.appendPage', $params_append); + $rev[5] = filemtime(wikiFN('nice_page')); + sleep(1); + $this->remote->call('dokuwiki.appendPage', $params_append); + $rev[6] = filemtime(wikiFN('nice_page')); + + $expected = array( + array( + 'name' => 'nice_page', + 'lastModified' => $rev[6], + 'author' => '', + 'version' => $rev[6], + 'perms' => 8, + 'size' => 78 + ) + ); + $params = array(strtotime("-1 year")); + $this->assertEquals($expected, $this->remote->call('wiki.getRecentChanges', $params)); + + $params = array('nice_page', 0); + $versions = $this->remote->call('wiki.getPageVersions', $params); + $this->assertEquals($rev[6], $versions[0]['version']); + $this->assertEquals($rev[5], $versions[1]['version']); + $this->assertEquals($rev[1], $versions[5]['version']); + $this->assertEquals(6, count($this->remote->call('wiki.getPageVersions', $params))); + + $params = array('nice_page', 1); + $versions = $this->remote->call('wiki.getPageVersions', $params); + $this->assertEquals($rev[5], $versions[0]['version']); + $this->assertEquals($rev[4], $versions[1]['version']); + $this->assertEquals(5, count($this->remote->call('wiki.getPageVersions', $params))); + + $conf['recent'] = 3; //set number of page returned + $params = array('nice_page', 1); + $this->assertEquals(3, count($this->remote->call('wiki.getPageVersions', $params))); + + $params = array('nice_page', $conf['recent']); + $versions = $this->remote->call('wiki.getPageVersions', $params); + $this->assertEquals($rev[3], $versions[0]['version']); //skips current,1st old,2nd old + $this->assertEquals(3, count($this->remote->call('wiki.getPageVersions', $params))); + + $params = array('nice_page', 2 * $conf['recent']); + $this->assertEquals(0, count($this->remote->call('wiki.getPageVersions', $params))); + + //remove page + $file3 = wikiFN('nice_page'); + $content = ""; + $params = array( + 'nice_page', + $content, + array( + 'minor' => false, + ) + ); + $this->assertEquals(true, $this->remote->call('wiki.putPage', $params)); + $this->assertFalse(file_exists($file3)); + + $params = array('nice_page', 0); + $this->assertEquals(2, count($this->remote->call('wiki.getPageVersions', $params))); + + $params = array('nice_page', 1); + $this->assertEquals(3, count($this->remote->call('wiki.getPageVersions', $params))); + + $params = array('nice_page'); + $this->assertEquals(AUTH_UPLOAD, $this->remote->call('wiki.aclCheck', $params)); + + global $conf; + global $AUTH_ACL, $USERINFO; + $conf['useacl'] = 1; + $_SERVER['REMOTE_USER'] = 'john'; + $USERINFO['grps'] = array('user'); + $AUTH_ACL = array( + '* @ALL 0', + '* @user 2', //edit + ); + + $params = array('nice_page'); + $this->assertEquals(AUTH_EDIT, $this->remote->call('wiki.aclCheck', $params)); + + $this->assertEquals(DOKU_API_VERSION, $this->remote->call('dokuwiki.getXMLRPCAPIVersion')); + + $this->assertEquals(2, $this->remote->call('wiki.getRPCVersionSupported')); + } + + public function test_core2() { + $localdoku = array( + 'type' => 'local', + 'page' => 'DokuWiki', + 'href' => DOKU_BASE . DOKU_SCRIPT . '?id=DokuWiki' + ); + $expected = array( //no local links + $localdoku, + array( + 'type' => 'extern', + 'page' => 'http://www.freelists.org', + 'href' => 'http://www.freelists.org' + ), + array( + 'type' => 'extern', + 'page' => 'https://tools.ietf.org/html/rfc1855', + 'href' => 'https://tools.ietf.org/html/rfc1855' + ), + array( + 'type' => 'extern', + 'page' => 'http://www.catb.org/~esr/faqs/smart-questions.html', + 'href' => 'http://www.catb.org/~esr/faqs/smart-questions.html' + ), + $localdoku, + $localdoku + ); + $params = array('mailinglist'); + $this->assertEquals($expected, $this->remote->call('wiki.listLinks', $params)); + } + + public function test_coreattachments() { + global $conf; + global $AUTH_ACL, $USERINFO; + + $filecontent = io_readFile(mediaFN('wiki:dokuwiki-128.png'), false); + $params = array('test:dokuwiki-128_2.png', $filecontent, array('ow' => false)); + $this->assertEquals('test:dokuwiki-128_2.png', $this->remote->call('wiki.putAttachment', $params)); //prints a success div + + $params = array('test:dokuwiki-128_2.png'); + $this->assertEquals($filecontent, $this->remote->call('wiki.getAttachment', $params)); + $rev = filemtime(mediaFN('test:dokuwiki-128_2.png')); + + $expected = array( + 'lastModified' => $rev, + 'size' => 27895, + ); + $params = array('test:dokuwiki-128_2.png'); + $this->assertEquals($expected, $this->remote->call('wiki.getAttachmentInfo', $params)); + + $params = array(strtotime("-5 year")); + $expected = array( + array( + 'name' => 'test:dokuwiki-128_2.png', + 'lastModified' => $rev, + 'author' => '', + 'version' => $rev, + 'perms' => 8, + 'size' => 27895 //actual size, not size change + ) + ); + $this->assertEquals($expected, $this->remote->call('wiki.getRecentMediaChanges', $params)); + + sleep(1); + $conf['useacl'] = 1; + $_SERVER['REMOTE_USER'] = 'john'; + $USERINFO['grps'] = array('user'); + $AUTH_ACL = array( + '* @ALL 0', + '* @user 16', + ); + + $params = array('test:dokuwiki-128_2.png'); + $this->assertEquals(0, $this->remote->call('wiki.deleteAttachment', $params)); + + $rev2 = filemtime($conf['media_changelog']); + $expected = array( + 'lastModified' => $rev2, + 'size' => 0, + ); + $params = array('test:dokuwiki-128_2.png'); + $this->assertEquals($expected, $this->remote->call('wiki.getAttachmentInfo', $params)); + + $expected = array( + 'lastModified' => 0, + 'size' => 0, + ); + $params = array('test:nonexisting.png'); + $this->assertEquals($expected, $this->remote->call('wiki.getAttachmentInfo', $params)); + + $media1 = mediaFN('wiki:dokuwiki-128.png'); + $expected = array( + array( + 'id' => 'wiki:dokuwiki-128.png', + 'file' => 'dokuwiki-128.png', + 'size' => filesize($media1), + 'mtime' => filemtime($media1), + 'writable' => 1, + 'isimg' => 1, + 'hash' => md5(io_readFile($media1, false)), + 'perms' => 16, + 'lastModified' => filemtime($media1) + ) + ); + $params = array( + 'wiki:', + array( + 'depth' => 0, // 0 for all + 'hash' => 1, + 'skipacl' => 1, // is ignored + 'showmsg' => true, //useless?? + 'pattern' => '/128/' //filter + ) + ); + $this->assertEquals($expected, $this->remote->call('wiki.getAttachments', $params)); + } + +} diff --git a/_test/tests/inc/remoteapicore_aclcheck.test.php b/_test/tests/inc/remoteapicore_aclcheck.test.php new file mode 100644 index 0000000000000000000000000000000000000000..25aff331f5ed26f451495dba543b9aa96dd84baa --- /dev/null +++ b/_test/tests/inc/remoteapicore_aclcheck.test.php @@ -0,0 +1,141 @@ +<?php + +/** + * Class remoteapicore_test + */ +class remoteapicore_aclcheck_test extends DokuWikiTest { + + protected $userinfo; + protected $oldAuthAcl; + /** @var RemoteAPI */ + protected $remote; + + protected $pluginsEnabled = array('auth_plugin_authplain'); + + protected function reloadUsers() { + global $auth; + + /* auth caches data loaded from file, but recreated object forces reload */ + $auth = new auth_plugin_authplain(); + } + + public function setUp() { + global $config_cascade; + global $conf; + global $USERINFO; + global $AUTH_ACL; + + parent::setUp(); + + $name = $config_cascade['plainauth.users']['default']; + copy($name, $name . ".orig"); + $this->reloadUsers(); + + $this->oldAuthAcl = $AUTH_ACL; + $this->userinfo = $USERINFO; + + $conf['remote'] = 1; + $conf['remoteuser'] = '@user'; + $conf['useacl'] = 0; + + $this->remote = new RemoteAPI(); + + } + + public function tearDown() { + global $USERINFO; + global $AUTH_ACL; + global $config_cascade; + + parent::tearDown(); + + $USERINFO = $this->userinfo; + $AUTH_ACL = $this->oldAuthAcl; + + $name = $config_cascade['plainauth.users']['default']; + copy($name . ".orig", $name); + } + + public function test_checkacl() { + global $conf; + global $AUTH_ACL, $USERINFO; + /** @var auth_plugin_authplain $auth */ + global $auth; + + $conf['useacl'] = 1; + $_SERVER['REMOTE_USER'] = 'john'; + $USERINFO['grps'] = array('user'); + $AUTH_ACL = array( + '* @ALL 0', //none + '* @user 2', //edit + '* @more 4', //create + 'nice_page user2 8' //upload + ); + + $params = array('nice_page'); + $this->assertEquals(AUTH_EDIT, $this->remote->call('wiki.aclCheck', $params)); + + $auth->createUser("user1", "54321", "a User", "you@example.com"); + $auth->createUser("user2", "543210", "You", "he@example.com"); + $auth->createUser("mwuser", "12345", "Wiki User", "me@example.com", array('more')); //not in default group + + $params = array( + 'nice_page', + 'user1' + ); + $this->assertEquals(AUTH_EDIT, $this->remote->call('wiki.aclCheck', $params)); + + $params = array( + 'nice_page', + 'mwuser' // member of group 'more' + ); + $this->assertEquals(AUTH_CREATE, $this->remote->call('wiki.aclCheck', $params)); + + $params = array( + 'nice_page', + 'mwuser', + array() //groups not retrieved + ); + $this->assertEquals(AUTH_NONE, $this->remote->call('wiki.aclCheck', $params)); + + $params = array( + 'nice_page', + 'notexistinguser', + array('more') + ); + $this->assertEquals(AUTH_CREATE, $this->remote->call('wiki.aclCheck', $params)); + + $params = array( + 'nice_page', + 'user2' + ); + $this->assertEquals(AUTH_UPLOAD, $this->remote->call('wiki.aclCheck', $params)); + + $params = array( + 'nice_page', + 'user2', + array() //groups not retrieved + ); + $this->assertEquals(AUTH_UPLOAD, $this->remote->call('wiki.aclCheck', $params)); + + $params = array( + 'unknown_page', + 'user2' + ); + $this->assertEquals(AUTH_EDIT, $this->remote->call('wiki.aclCheck', $params)); + + $params = array( + 'unknown_page', + 'user2', + array() //groups not retrieved + ); + $this->assertEquals(AUTH_NONE, $this->remote->call('wiki.aclCheck', $params)); + + $params = array( + 'nice_page', + 'testuser' // superuser set via conf + ); + $this->assertEquals(AUTH_ADMIN, $this->remote->call('wiki.aclCheck', $params)); + } + +} diff --git a/inc/RemoteAPICore.php b/inc/RemoteAPICore.php index c0e6869f1dbdcf4b8f450498debe73f249d0fc86..407e63185b3ec519abcf00a6f5e23023701ca3d2 100644 --- a/inc/RemoteAPICore.php +++ b/inc/RemoteAPICore.php @@ -3,12 +3,19 @@ /** * Increased whenever the API is changed */ -define('DOKU_API_VERSION', 9); +define('DOKU_API_VERSION', 10); +/** + * Provides the core methods for the remote API. + * The methods are ordered in 'wiki.<method>' and 'dokuwiki.<method>' namespaces + */ class RemoteAPICore { private $api; + /** + * @param RemoteAPI $api + */ public function __construct(RemoteAPI $api) { $this->api = $api; } @@ -18,7 +25,7 @@ class RemoteAPICore { * * @return array */ - function __getRemoteInfo() { + public function __getRemoteInfo() { return array( 'dokuwiki.getVersion' => array( 'args' => array(), @@ -97,7 +104,7 @@ class RemoteAPICore { ), 'wiki.getPageInfo' => array( 'args' => array('string'), 'return' => 'array', - 'doc' => 'Returns a struct with info about the page.', + 'doc' => 'Returns a struct with info about the page, latest version.', 'name' => 'pageInfo' ), 'wiki.getPageInfoVersion' => array( 'args' => array('string', 'int'), @@ -126,9 +133,9 @@ class RemoteAPICore { 'return' => 'array', 'Returns a struct about all recent media changes since given timestamp.' ), 'wiki.aclCheck' => array( - 'args' => array('string'), + 'args' => array('string', 'string', 'array'), 'return' => 'int', - 'doc' => 'Returns the permissions of a given wiki page.' + 'doc' => 'Returns the permissions of a given wiki page. By default, for current user/groups' ), 'wiki.putAttachment' => array( 'args' => array('string', 'file', 'array'), 'return' => 'array', @@ -166,14 +173,14 @@ class RemoteAPICore { /** * @return string */ - function getVersion() { + public function getVersion() { return getVersion(); } /** * @return int unix timestamp */ - function getTime() { + public function getTime() { return time(); } @@ -185,7 +192,7 @@ class RemoteAPICore { * @return string page text. * @throws RemoteAccessDeniedException if no permission for page */ - function rawPage($id,$rev=''){ + public function rawPage($id,$rev=''){ $id = $this->resolvePageId($id); if(auth_quickaclcheck($id) < AUTH_READ){ throw new RemoteAccessDeniedException('You are not allowed to read this file', 111); @@ -208,7 +215,7 @@ class RemoteAPICore { * @throws RemoteAccessDeniedException no permission for media * @throws RemoteException not exist */ - function getAttachment($id){ + public function getAttachment($id){ $id = cleanID($id); if (auth_quickaclcheck(getNS($id).':*') < AUTH_READ) { throw new RemoteAccessDeniedException('You are not allowed to read this file', 211); @@ -231,7 +238,7 @@ class RemoteAPICore { * @param string $id page id * @return array */ - function getAttachmentInfo($id){ + public function getAttachmentInfo($id){ $id = cleanID($id); $info = array( 'lastModified' => $this->api->toDate(0), @@ -239,9 +246,18 @@ class RemoteAPICore { ); $file = mediaFN($id); - if ((auth_quickaclcheck(getNS($id).':*') >= AUTH_READ) && file_exists($file)){ - $info['lastModified'] = $this->api->toDate(filemtime($file)); - $info['size'] = filesize($file); + if(auth_quickaclcheck(getNS($id) . ':*') >= AUTH_READ) { + if(file_exists($file)) { + $info['lastModified'] = $this->api->toDate(filemtime($file)); + $info['size'] = filesize($file); + } else { + //Is it deleted media with changelog? + $medialog = new MediaChangeLog($id); + $revisions = $medialog->getRevisions(0, 1); + if(!empty($revisions)) { + $info['lastModified'] = $this->api->toDate($revisions[0]); + } + } } return $info; @@ -255,7 +271,7 @@ class RemoteAPICore { * @return null|string html * @throws RemoteAccessDeniedException no access to page */ - function htmlPage($id,$rev=''){ + public function htmlPage($id,$rev=''){ $id = $this->resolvePageId($id); if(auth_quickaclcheck($id) < AUTH_READ){ throw new RemoteAccessDeniedException('You are not allowed to read this page', 111); @@ -268,7 +284,7 @@ class RemoteAPICore { * * @return array */ - function listPages(){ + public function listPages(){ $list = array(); $pages = idx_get_indexer()->getPages(); $pages = array_filter(array_filter($pages,'isVisiblePage'),'page_exists'); @@ -298,7 +314,7 @@ class RemoteAPICore { * $opts['hash'] do md5 sum of content? * @return array */ - function readNamespace($ns,$opts){ + public function readNamespace($ns,$opts){ global $conf; if(!is_array($opts)) $opts=array(); @@ -317,7 +333,7 @@ class RemoteAPICore { * @param string $query * @return array */ - function search($query){ + public function search($query){ $regex = array(); $data = ft_pageSearch($query,$regex); $pages = array(); @@ -352,7 +368,7 @@ class RemoteAPICore { * * @return string */ - function getTitle(){ + public function getTitle(){ global $conf; return $conf['title']; } @@ -375,7 +391,7 @@ class RemoteAPICore { * @return array * @throws RemoteAccessDeniedException no access to the media files */ - function listAttachments($ns, $options = array()) { + public function listAttachments($ns, $options = array()) { global $conf; $ns = cleanID($ns); @@ -422,7 +438,7 @@ class RemoteAPICore { * @throws RemoteAccessDeniedException no access for page * @throws RemoteException page not exist */ - function pageInfo($id,$rev=''){ + public function pageInfo($id,$rev=''){ $id = $this->resolvePageId($id); if(auth_quickaclcheck($id) < AUTH_READ){ throw new RemoteAccessDeniedException('You are not allowed to read this page', 111); @@ -458,7 +474,7 @@ class RemoteAPICore { * @throws RemoteAccessDeniedException no write access for page * @throws RemoteException no id, empty new page or locked */ - function putPage($id, $text, $params) { + public function putPage($id, $text, $params) { global $TEXT; global $lang; @@ -519,7 +535,7 @@ class RemoteAPICore { * @param array $params such as summary,minor * @return bool|string */ - function appendPage($id, $text, $params) { + public function appendPage($id, $text, $params) { $currentpage = $this->rawPage($id); if (!is_string($currentpage)) { return $currentpage; @@ -538,7 +554,7 @@ class RemoteAPICore { * @return false|string * @throws RemoteException */ - function putAttachment($id, $file, $params) { + public function putAttachment($id, $file, $params) { $id = cleanID($id); $auth = auth_quickaclcheck(getNS($id).':*'); @@ -572,7 +588,7 @@ class RemoteAPICore { * @throws RemoteAccessDeniedException no permissions * @throws RemoteException file in use or not deleted */ - function deleteAttachment($id){ + public function deleteAttachment($id){ $id = cleanID($id); $auth = auth_quickaclcheck(getNS($id).':*'); $res = media_delete($id, $auth); @@ -588,14 +604,31 @@ class RemoteAPICore { } /** - * Returns the permissions of a given wiki page + * Returns the permissions of a given wiki page for the current user or another user * * @param string $id page id + * @param string|null $user username + * @param array|null $groups array of groups * @return int permission level */ - function aclCheck($id) { + public function aclCheck($id, $user = null, $groups = null) { + /** @var DokuWiki_Auth_Plugin $auth */ + global $auth; + $id = $this->resolvePageId($id); - return auth_quickaclcheck($id); + if($user === null) { + return auth_quickaclcheck($id); + } else { + if($groups === null) { + $userinfo = $auth->getUserData($user); + if($userinfo === false) { + $groups = array(); + } else { + $groups = $userinfo['grps']; + } + } + return auth_aclcheck($id, $user, $groups); + } } /** @@ -607,7 +640,7 @@ class RemoteAPICore { * @return array * @throws RemoteAccessDeniedException no read access for page */ - function listLinks($id) { + public function listLinks($id) { $id = $this->resolvePageId($id); if(auth_quickaclcheck($id) < AUTH_READ){ throw new RemoteAccessDeniedException('You are not allowed to read this page', 111); @@ -618,7 +651,6 @@ class RemoteAPICore { $ins = p_cached_instructions(wikiFN($id)); // instantiate new Renderer - needed for interwiki links - include(DOKU_INC.'inc/parser/xhtml.php'); $Renderer = new Doku_Renderer_xhtml(); $Renderer->interwiki = getInterwiki(); @@ -661,7 +693,7 @@ class RemoteAPICore { * @return array * @throws RemoteException no valid timestamp */ - function getRecentChanges($timestamp) { + public function getRecentChanges($timestamp) { if(strlen($timestamp) != 10) { throw new RemoteException('The provided value is not a valid timestamp', 311); } @@ -699,7 +731,7 @@ class RemoteAPICore { * @return array * @throws RemoteException no valid timestamp */ - function getRecentMediaChanges($timestamp) { + public function getRecentMediaChanges($timestamp) { if(strlen($timestamp) != 10) throw new RemoteException('The provided value is not a valid timestamp', 311); @@ -728,16 +760,18 @@ class RemoteAPICore { /** * Returns a list of available revisions of a given wiki page + * Number of returned pages is set by $conf['recent'] + * However not accessible pages are skipped, so less than $conf['recent'] could be returned * * @author Michael Klier <chi@chimeric.de> * * @param string $id page id - * @param int $first skip the first n changelog lines + * @param int $first skip the first n changelog lines (0 = from current(if exists), 1 = from 1st old rev, 2 = from 2nd old rev, etc) * @return array * @throws RemoteAccessDeniedException no read access for page * @throws RemoteException empty id */ - function pageVersions($id, $first) { + public function pageVersions($id, $first) { $id = $this->resolvePageId($id); if(auth_quickaclcheck($id) < AUTH_READ) { throw new RemoteAccessDeniedException('You are not allowed to read this page', 111); @@ -750,25 +784,19 @@ class RemoteAPICore { throw new RemoteException('Empty page ID', 131); } + $first = (int) $first; + $first_rev = $first - 1; + $first_rev = $first_rev < 0 ? 0 : $first_rev; $pagelog = new PageChangeLog($id); - $revisions = $pagelog->getRevisions($first, $conf['recent']+1); + $revisions = $pagelog->getRevisions($first_rev, $conf['recent']); - if(count($revisions)==0 && $first!=0) { - $first=0; - $revisions = $pagelog->getRevisions($first, $conf['recent']+1); - } - - if(count($revisions)>0 && $first==0) { + if($first == 0) { array_unshift($revisions, ''); // include current revision if ( count($revisions) > $conf['recent'] ){ array_pop($revisions); // remove extra log entry } } - if(count($revisions) > $conf['recent']) { - array_pop($revisions); // remove extra log entry - } - if(!empty($revisions)) { foreach($revisions as $rev) { $file = wikiFN($id,$rev); @@ -800,7 +828,7 @@ class RemoteAPICore { /** * The version of Wiki RPC API supported */ - function wiki_RPCVersion(){ + public function wiki_RPCVersion(){ return 2; } @@ -817,7 +845,7 @@ class RemoteAPICore { * @param array[] $set list pages with array('lock' => array, 'unlock' => array) * @return array */ - function setLocks($set){ + public function setLocks($set){ $locked = array(); $lockfail = array(); $unlocked = array(); @@ -855,7 +883,7 @@ class RemoteAPICore { * * @return int */ - function getAPIVersion(){ + public function getAPIVersion(){ return DOKU_API_VERSION; } @@ -866,7 +894,7 @@ class RemoteAPICore { * @param string $pass * @return int */ - function login($user,$pass){ + public function login($user,$pass){ global $conf; /** @var DokuWiki_Auth_Plugin $auth */ global $auth; @@ -896,12 +924,12 @@ class RemoteAPICore { * * @return int */ - function logoff(){ + public function logoff(){ global $conf; global $auth; if(!$conf['useacl']) return 0; if(!$auth) return 0; - + auth_logoff(); return 1; diff --git a/inc/remote.php b/inc/remote.php index 771d12d252901f6f1de5206e0715db7746e4eba0..2d2e327c826f63eaccf6faa2455f0c9e7ea77313 100644 --- a/inc/remote.php +++ b/inc/remote.php @@ -226,6 +226,7 @@ class RemoteAPI { * Perform access check for current user * * @return bool true if the current user has access to remote api. + * @throws RemoteAccessDeniedException If remote access disabled */ public function hasAccess() { global $conf; diff --git a/lib/exe/xmlrpc.php b/lib/exe/xmlrpc.php index 9ba157b8fdffde7e6741b7bdb4b5f2d668219721..6421c4a48a8465c2975559015b14cabdd7f9fb15 100644 --- a/lib/exe/xmlrpc.php +++ b/lib/exe/xmlrpc.php @@ -11,12 +11,12 @@ if(!$conf['remote']) die('XML-RPC server not enabled.'); * XMLRPC functions. */ class dokuwiki_xmlrpc_server extends IXR_Server { - var $remote; + protected $remote; /** * Constructor. Register methods and run Server */ - function __construct(){ + public function __construct(){ $this->remote = new RemoteAPI(); $this->remote->setDateTransformation(array($this, 'toDate')); $this->remote->setFileTransformation(array($this, 'toFile')); @@ -28,7 +28,7 @@ class dokuwiki_xmlrpc_server extends IXR_Server { * @param array $args * @return IXR_Error|mixed */ - function call($methodname, $args){ + public function call($methodname, $args){ try { $result = $this->remote->call($methodname, $args); return $result; @@ -49,7 +49,7 @@ class dokuwiki_xmlrpc_server extends IXR_Server { * @param string|int $data iso date(yyyy[-]mm[-]dd[ hh:mm[:ss]]) or timestamp * @return IXR_Date */ - function toDate($data) { + public function toDate($data) { return new IXR_Date($data); } @@ -57,7 +57,7 @@ class dokuwiki_xmlrpc_server extends IXR_Server { * @param string $data * @return IXR_Base64 */ - function toFile($data) { + public function toFile($data) { return new IXR_Base64($data); } } diff --git a/lib/plugins/acl/admin.php b/lib/plugins/acl/admin.php index f4baec9941aeca5aaad3ec70eb4ac10c05cc5403..6edc6c6215578f1557a37817527b81e9ea525bb2 100644 --- a/lib/plugins/acl/admin.php +++ b/lib/plugins/acl/admin.php @@ -649,7 +649,6 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin { echo '</div></form>'.NL; } - /** * Returns the permission which were set for exactly the given user/group * and page/namespace. Returns null if no exact match is available diff --git a/lib/plugins/acl/remote.php b/lib/plugins/acl/remote.php index 031686f959ab1c568b3a597e6060c02eb7fe04cc..3771d475d44fab17deeeef43cc34e58907df2467 100644 --- a/lib/plugins/acl/remote.php +++ b/lib/plugins/acl/remote.php @@ -12,7 +12,12 @@ class remote_plugin_acl extends DokuWiki_Remote_Plugin { */ public function _getMethods() { return array( - 'addAcl' => array( + 'listAcls' => array( + 'args' => array(), + 'return' => 'Array of ACLs {scope, user, permission}', + 'name' => 'listAcl', + 'doc' => 'Get the list of all ACLs', + ),'addAcl' => array( 'args' => array('string','string','int'), 'return' => 'int', 'name' => 'addAcl', @@ -26,6 +31,22 @@ class remote_plugin_acl extends DokuWiki_Remote_Plugin { ); } + /** + * List all ACL config entries + * + * @throws RemoteAccessDeniedException + * @return dictionary {Scope: ACL}, where ACL = dictionnary {user/group: permissions_int} + */ + public function listAcls(){ + if(!auth_isadmin()) { + throw new RemoteAccessDeniedException('You are not allowed to access ACLs, superuser permission is required', 114); + } + /** @var admin_plugin_acl $apa */ + $apa = plugin_load('admin', 'acl'); + $apa->_init_acl_config(); + return $apa->acl; + } + /** * Add a new entry to ACL config * diff --git a/lib/plugins/authplain/_test/escaping.test.php b/lib/plugins/authplain/_test/escaping.test.php index 7139aa99b0b2bcc684588ef8c0c39f4a518a0539..a38940e1a7da22597887ba1c5d3138df1a395be0 100644 --- a/lib/plugins/authplain/_test/escaping.test.php +++ b/lib/plugins/authplain/_test/escaping.test.php @@ -103,9 +103,11 @@ class helper_plugin_authplain_escaping_test extends DokuWikiTest { $this->assertEquals($escaped, $result[2]); } } - } +/** + * Class auth_plugin_authplainharness + */ class auth_plugin_authplainharness extends auth_plugin_authplain { /** @@ -115,12 +117,16 @@ class auth_plugin_authplainharness extends auth_plugin_authplain { $this->_pregsplit_safe = $bool; } + /** + * @return bool|mixed + */ public function getPregsplit_safe(){ return $this->_pregsplit_safe; } /** * @param string $line + * @return array */ public function splitUserData($line){ return $this->_splitUserData($line);