X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=actions%2Fapi.php;h=d2f0a2eff0f7a47c1038939970d1fe0fd9a2cd32;hb=34d904b180e5caa17eb945292a8a64656424d5d0;hp=69fda2e224f82cd4c77a39d28115c658f9d5a2e9;hpb=140689800b03ff704f6c70260c2b740ad41578c0;p=quix0rs-gnu-social.git diff --git a/actions/api.php b/actions/api.php index 69fda2e224..d2f0a2eff0 100644 --- a/actions/api.php +++ b/actions/api.php @@ -10,123 +10,201 @@ * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * along with this program. If not, see . */ if (!defined('LACONICA')) { exit(1); } -class ApiAction extends Action { - - var $user; - var $content_type; - var $api_arg; - var $api_method; - var $api_action; - - function handle($args) { - parent::handle($args); - - $this->api_action = $this->arg('apiaction'); - $method = $this->arg('method'); - $argument = $this->arg('argument'); - - if (isset($argument)) { - $cmdext = explode('.', $argument); - $this->api_arg = $cmdext[0]; - $this->api_method = $method; - $this->content_type = strtolower($cmdext[1]); - } else { - #content type will be an extension on the method - $cmdext = explode('.', $method); - $this->api_method = $cmdext[0]; - $this->content_type = strtolower($cmdext[1]); - } - - # XXX Maybe check to see if the command actually exists first? - if($this->requires_auth()) { - if (!isset($_SERVER['PHP_AUTH_USER'])) { - - # This header makes basic auth go - header('WWW-Authenticate: Basic realm="Laconica API"'); - - # if the user hits cancel -- bam! - $this->show_basic_auth_error(); - } else { - $nickname = $_SERVER['PHP_AUTH_USER']; - $password = $_SERVER['PHP_AUTH_PW']; - $user = common_check_user($nickname, $password); - +class ApiAction extends Action +{ + + var $user; + var $content_type; + var $api_arg; + var $api_method; + var $api_action; + + function handle($args) + { + parent::handle($args); + + $this->api_action = $this->arg('apiaction'); + $method = $this->arg('method'); + $argument = $this->arg('argument'); + + if (isset($argument)) { + $cmdext = explode('.', $argument); + $this->api_arg = $cmdext[0]; + $this->api_method = $method; + $this->content_type = strtolower($cmdext[1]); + } else { + + # Requested format / content-type will be an extension on the method + $cmdext = explode('.', $method); + $this->api_method = $cmdext[0]; + $this->content_type = strtolower($cmdext[1]); + } + + if ($this->requires_auth()) { + if (!isset($_SERVER['PHP_AUTH_USER'])) { + + # This header makes basic auth go + header('WWW-Authenticate: Basic realm="Laconica API"'); + + # If the user hits cancel -- bam! + $this->show_basic_auth_error(); + } else { + $nickname = $_SERVER['PHP_AUTH_USER']; + $password = $_SERVER['PHP_AUTH_PW']; + $user = common_check_user($nickname, $password); + + if ($user) { + $this->user = $user; + $this->process_command(); + } else { + # basic authentication failed + $this->show_basic_auth_error(); + } + } + } else { + + # Caller might give us a username even if not required + if (isset($_SERVER['PHP_AUTH_USER'])) { + $user = User::staticGet('nickname', $_SERVER['PHP_AUTH_USER']); if ($user) { $this->user = $user; - $this->process_command(); - } else { - # basic authentication failed - $this->show_basic_auth_error(); - } - } - } else { - $this->process_command(); - } - } - - function process_command() { - $action = "twitapi$this->api_action"; - $actionfile = INSTALLDIR."/actions/$action.php"; - if (file_exists($actionfile)) { - require_once($actionfile); - $action_class = ucfirst($action)."Action"; - $action_obj = new $action_class(); - - if (method_exists($action_obj, $this->api_method)) { - - $apidata = array( 'content-type' => $this->content_type, - 'api_method' => $this->api_method, - 'api_arg' => $this->api_arg, - 'user' => $this->user); - - call_user_func(array($action_obj, $this->api_method), $_REQUEST, $apidata); - # all API methods should exit() - } - } - common_user_error("API method not found!", $code=404); - } - - - # Whitelist of API methods that don't need authentication - function requires_auth() { - static $noauth = array( 'statuses/public_timeline', - 'statuses/show', - 'help/test', - 'help/downtime_schedule'); - static $bareauth = array('statuses/user_timeline', 'statuses/friends'); - - $fullname = "$this->api_action/$this->api_method"; - - if (in_array($fullname, $bareauth)) { - # bareauth: only needs auth if without an argument - if ($this->api_arg) { - return false; - } else { - return true; + } + # Twitter doesn't throw an error if the user isn't found } - } else if (in_array($fullname, $noauth)) { - # noauth: never needs auth - return false; - } else { - # everybody else needs auth - return true; - } - } - - function show_basic_auth_error() { - header('HTTP/1.1 401 Unauthorized'); - header('Content-type: text/plain'); - print("Could not authenticate you."); # exactly what Twitter says - no \n - exit(); - } - + + $this->process_command(); + } + } + + function process_command() + { + $action = "twitapi$this->api_action"; + $actionfile = INSTALLDIR."/actions/$action.php"; + + if (file_exists($actionfile)) { + require_once($actionfile); + $action_class = ucfirst($action)."Action"; + $action_obj = new $action_class(); + + if (!$action_obj->prepare($this->args)) { + return; + } + + if (method_exists($action_obj, $this->api_method)) { + $apidata = array( 'content-type' => $this->content_type, + 'api_method' => $this->api_method, + 'api_arg' => $this->api_arg, + 'user' => $this->user); + + call_user_func(array($action_obj, $this->api_method), $_REQUEST, $apidata); + } else { + $this->clientError("API method not found!", $code=404); + } + } else { + $this->clientError("API method not found!", $code=404); + } + } + + # Whitelist of API methods that don't need authentication + function requires_auth() + { + static $noauth = array( 'statuses/public_timeline', + 'statuses/show', + 'users/show', + 'help/test', + 'help/downtime_schedule', + 'laconica/version', + 'laconica/config', + 'laconica/wadl'); + + static $bareauth = array('statuses/user_timeline', + 'statuses/friends_timeline', + 'statuses/friends', + 'statuses/replies', + 'statuses/followers', + 'favorites/favorites'); + + $fullname = "$this->api_action/$this->api_method"; + + // If the site is "private", all API methods except laconica/config + // need authentication + if (common_config('site', 'private')) { + return $fullname != 'laconica/config' || false; + } + + if (in_array($fullname, $bareauth)) { + # bareauth: only needs auth if without an argument + if ($this->api_arg) { + return false; + } else { + return true; + } + } else if (in_array($fullname, $noauth)) { + # noauth: never needs auth + return false; + } else { + # everybody else needs auth + return true; + } + } + + function show_basic_auth_error() + { + header('HTTP/1.1 401 Unauthorized'); + $msg = 'Could not authenticate you.'; + + if ($this->content_type == 'xml') { + header('Content-Type: application/xml; charset=utf-8'); + $this->startXML(); + $this->elementStart('hash'); + $this->element('error', null, $msg); + $this->element('request', null, $_SERVER['REQUEST_URI']); + $this->elementEnd('hash'); + $this->endXML(); + } else if ($this->content_type == 'json') { + header('Content-Type: application/json; charset=utf-8'); + $error_array = array('error' => $msg, 'request' => $_SERVER['REQUEST_URI']); + print(json_encode($error_array)); + } else { + header('Content-type: text/plain'); + print "$msg\n"; + } + } + + function isReadOnly($args) + { + $apiaction = $args['apiaction']; + $method = $args['method']; + + list($cmdtext, $fmt) = explode('.', $method); + + static $write_methods = array( + 'account' => array('update_location', 'update_delivery_device', 'end_session'), + 'blocks' => array('create', 'destroy'), + 'direct_messages' => array('create', 'destroy'), + 'favorites' => array('create', 'destroy'), + 'friendships' => array('create', 'destroy'), + 'help' => array(), + 'notifications' => array('follow', 'leave'), + 'statuses' => array('update', 'destroy'), + 'users' => array() + ); + + if (array_key_exists($apiaction, $write_methods)) { + if (!in_array($cmdtext, $write_methods[$apiaction])) { + return true; + } + } + + return false; + } }