Server IP : 184.154.167.98 / Your IP : 3.137.214.16 Web Server : Apache System : Linux pink.dnsnetservice.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 User : puertode ( 1767) PHP Version : 7.2.34 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /home/puertode/www/mesa/include/ |
Upload File : |
<?php /********************************************************************* class.api.php API Peter Rotich <peter@osticket.com> Copyright (c) 2006-2013 osTicket http://www.osticket.com Released under the GNU General Public License WITHOUT ANY WARRANTY. See LICENSE.TXT for details. vim: expandtab sw=4 ts=4 sts=4: **********************************************************************/ include_once INCLUDE_DIR.'class.controller.php'; class API { var $id; var $ht; function __construct($id) { $this->id = 0; $this->load($id); } function load($id=0) { if(!$id && !($id=$this->getId())) return false; $sql='SELECT * FROM '.API_KEY_TABLE.' WHERE id='.db_input($id); if(!($res=db_query($sql)) || !db_num_rows($res)) return false; $this->ht = db_fetch_array($res); $this->id = $this->ht['id']; return true; } function reload() { return $this->load(); } function getId() { return $this->id; } function getKey() { return $this->ht['apikey']; } function getIPAddr() { return $this->ht['ipaddr']; } function getNotes() { return $this->ht['notes']; } function getHashtable() { return $this->ht; } function isActive() { return ($this->ht['isactive']); } function canCreateTickets() { return ($this->ht['can_create_tickets']); } function canExecuteCron() { return ($this->ht['can_exec_cron']); } function update($vars, &$errors) { if(!API::save($this->getId(), $vars, $errors)) return false; $this->reload(); return true; } function delete() { $sql='DELETE FROM '.API_KEY_TABLE.' WHERE id='.db_input($this->getId()).' LIMIT 1'; return (db_query($sql) && ($num=db_affected_rows())); } /** Static functions **/ static function add($vars, &$errors) { return API::save(0, $vars, $errors); } static function validate($key, $ip) { return ($key && $ip && self::getIdByKey($key, $ip)); } static function getIdByKey($key, $ip='') { $sql='SELECT id FROM '.API_KEY_TABLE.' WHERE apikey='.db_input($key); if($ip) $sql.=' AND ipaddr='.db_input($ip); if(($res=db_query($sql)) && db_num_rows($res)) list($id) = db_fetch_row($res); return $id; } static function lookupByKey($key, $ip='') { return self::lookup(self::getIdByKey($key, $ip)); } static function lookup($id) { return ($id && is_numeric($id) && ($k= new API($id)) && $k->getId()==$id)?$k:null; } static function save($id, $vars, &$errors) { if(!$id && (!$vars['ipaddr'] || !Validator::is_ip($vars['ipaddr']))) $errors['ipaddr'] = __('Valid IP is required'); if($errors) return false; $sql=' updated=NOW() ' .',isactive='.db_input($vars['isactive']) .',can_create_tickets='.db_input($vars['can_create_tickets']) .',can_exec_cron='.db_input($vars['can_exec_cron']) .',notes='.db_input(Format::sanitize($vars['notes'])); if($id) { $sql='UPDATE '.API_KEY_TABLE.' SET '.$sql.' WHERE id='.db_input($id); if(db_query($sql)) return true; $errors['err']=sprintf(__('Unable to update %s.'), __('this API key')) .' '.__('Internal error occurred'); } else { $sql='INSERT INTO '.API_KEY_TABLE.' SET '.$sql .',created=NOW() ' .',ipaddr='.db_input($vars['ipaddr']) .',apikey='.db_input(strtoupper(md5(time().$vars['ipaddr'].md5(Misc::randCode(16))))); if(db_query($sql) && ($id=db_insert_id())) return $id; $errors['err']=sprintf('%s %s', sprintf(__('Unable to add %s.'), __('this API key')), __('Correct any errors below and try again.')); } return false; } } /** * Controller for API methods. Provides methods to check to make sure the * API key was sent and that the Client-IP and API-Key have been registered * in the database, and methods for parsing and validating data sent in the * API request. */ class ApiController extends Controller { private $sapi; private $key; public function __construct($sapi = null) { // Set API Interface the request is coming from $this->sapi = $sapi ?: (osTicket::is_cli() ? 'cli' : 'http'); } public function isCli() { return (strcasecmp($this->sapi, 'cli') === 0); } private function getInputStream() { return $this->isCli() ? 'php://stdin' : 'php://input'; } protected function getRemoteAddr() { return $_SERVER['REMOTE_ADDR']; } protected function getApiKey() { return $_SERVER['HTTP_X_API_KEY']; } function requireApiKey() { // Require a valid API key sent as X-API-Key HTTP header // see getApiKey method. if (!($key=$this->getKey())) return $this->exerr(401, __('Valid API key required')); elseif (!$key->isActive() || $key->getIPAddr() != $this->getRemoteAddr()) return $this->exerr(401, __('API key not found/active or source IP not authorized')); return $key; } function getKey() { // Lookup record using sent API Key && IP Addr if (!$this->key && ($key=$this->getApiKey()) && ($ip=$this->getRemoteAddr())) $this->key = API::lookupByKey($key, $ip); return $this->key; } /** * Retrieves the body of the API request and converts it to a common * hashtable. For JSON formats, this is mostly a noop, the conversion * work will be done for XML requests */ function getRequest($format, $validate=true) { $input = $this->getInputStream(); if (!($stream = @fopen($input, 'r'))) $this->exerr(400, sprintf('%s (%s)', __("Unable to read request body"), $input)); return $this->parseRequest($stream, $format, $validate); } function getEmailRequest() { if (!($data=$this->getRequest('email', false))) $this->exerr(400, __("Unable to read email request")); return $data; } function parseRequest($stream, $format, $validate=true) { $parser = null; switch(strtolower($format)) { case 'xml': if (!function_exists('xml_parser_create')) return $this->exerr(501, __('XML extension not supported')); $parser = new ApiXmlDataParser(); break; case 'json': $parser = new ApiJsonDataParser(); break; case 'email': $parser = new ApiEmailDataParser(); break; default: return $this->exerr(415, __('Unsupported data format')); } if (!($data = $parser->parse($stream)) || !is_array($data)) { $this->exerr(400, $parser->lastError()); } //Validate structure of the request. if ($validate && $data) $this->validate($data, $format, false); return $data; } function parseEmail($content) { return $this->parseRequest($content, 'email', false); } /** * Structure to validate the request against -- must be overridden to be * useful */ function getRequestStructure($format, $data=null) { return array(); } /** * Simple validation that makes sure the keys of a parsed request are * expected. It is assumed that the functions actually implementing the * API will further validate the contents of the request */ function validateRequestStructure($data, $structure, $prefix="", $strict=true) { global $ost; foreach ($data as $key=>$info) { if (is_array($structure) && (is_array($info) || $info instanceof ArrayAccess)) { $search = (isset($structure[$key]) && !is_numeric($key)) ? $key : "*"; if (isset($structure[$search])) { $this->validateRequestStructure($info, $structure[$search], "$prefix$key/", $strict); continue; } } elseif (in_array($key, $structure)) { continue; } $error = sprintf(__("%s: Unexpected data received in API request"), "$prefix$key"); $this->onError(400, $error, __('Unexpected Data'), !$strict); } return true; } /** * Validate request. * */ function validate(&$data, $format, $strict=true) { return $this->validateRequestStructure( $data, $this->getRequestStructure($format, $data), "", $strict); } protected function debug($subj, $msg) { return $this->log($subj, $msg, LOG_DEBUG); } protected function logError($subj, $msg, $fatal=false) { // If error is not fatal then log it as a warning return $this->log($subj, $msg, $fatal ? LOG_ERR : LOG_WARN); } protected function log($title, $msg, $level = LOG_WARN) { global $ost; switch ($level) { case LOG_WARN: case LOG_ERR: // We are disabling email alerts on API errors / warnings // due to potential abuse or loops that might cause email DOS $ost->log($level, $title, $msg, false); break; case LOG_DEBUG: default: $ost->logDebug($title, $msg); } return true; } /** * API error & logging and response! * * final - don not override downstream. */ final public function onError($code, $error, $title = null, $logOnly = false) { // Unpack the errors to string if error is an array if ($error && is_array($error)) $error = Format::array_implode(": ", "\n", $error); // Log the error $msg = $error; // TODO: Only include API Key when in debug mode to avoid // potentialialy leaking a valid key in system logs if (($key=$this->getApiKey())) $msg .= "\n[$key]\n"; $title = sprintf('%s (%s)', $title ?: __('API Error'), $code); $this->logError($title, $msg, $logOnly); // If the error is not deemed fatal then simply return if ($logOnly) return; // If the API Interface is CLI then throw a TicketApiError exception // so the caller can handle the error gracefully. // Note that we set the error code as well if ($this->isCli()) throw new TicketApiError($error, $code); // Respond and exit since HTTP endpoint requests // are considered stateless $this->response($code, $error); } } include_once "class.xml.php"; class ApiXmlDataParser extends XmlDataParser { function parse($stream) { return $this->fixup(parent::parse($stream)); } /** * Perform simple operations to make data consistent between JSON and * XML data types */ function fixup($current) { global $cfg; if($current['ticket']) $current = $current['ticket']; if (!is_array($current)) return $current; foreach ($current as $key=>&$value) { if ($key == "phone" && is_array($value)) { $value = $value[":text"]; } else if ($key == "alert") { $value = (bool) (strtolower($value) === 'false' ? false : $value); } else if ($key == "autorespond") { $value = (bool) (strtolower($value) === 'false' ? false : $value); } else if ($key == "message") { if (!is_array($value)) { $value = array( "body" => $value, "type" => "text/plain", # Use encoding from root <xml> node ); } else { $value["body"] = $value[":text"]; unset($value[":text"]); } if (isset($value['encoding'])) $value['body'] = Charset::utf8($value['body'], $value['encoding']); if (!strcasecmp($value['type'], 'text/html')) $value = new HtmlThreadEntryBody($value['body']); else $value = new TextThreadEntryBody($value['body']); } else if ($key == "attachments") { if(isset($value['file']) && !isset($value['file'][':text'])) $value = $value['file']; if($value && is_array($value)) { foreach ($value as &$info) { $info["data"] = $info[":text"]; unset($info[":text"]); } unset($info); } } else if(is_array($value)) { $value = $this->fixup($value); } } unset($value); return $current; } } include_once "class.json.php"; class ApiJsonDataParser extends JsonDataParser { static function parse($stream, $tidy=false) { return self::fixup(parent::parse($stream)); } static function fixup($current) { if (!is_array($current)) return $current; foreach ($current as $key=>&$value) { if ($key == "phone") { $value = strtoupper($value); } else if ($key == "alert") { $value = (bool)$value; } else if ($key == "autorespond") { $value = (bool)$value; } elseif ($key == "message") { // Allow message specified in RFC 2397 format $data = Format::strip_emoticons(Format::parseRfc2397($value, 'utf-8')); if (isset($data['type']) && $data['type'] == 'text/html') $value = new HtmlThreadEntryBody($data['data']); else $value = new TextThreadEntryBody($data['data']); } else if ($key == "attachments") { foreach ($value as &$info) { $data = reset($info); # PHP5: fopen("data://$data[5:]"); $contents = Format::parseRfc2397($data, 'utf-8', false); $info = array( "data" => $contents['data'], "type" => $contents['type'], "name" => key($info), ); } unset($info); } } unset($value); return $current; } } /* Email parsing */ include_once "class.mailparse.php"; class ApiEmailDataParser extends EmailDataParser { function parse($stream) { return $this->fixup(parent::parse($stream)); } function fixup($data) { global $cfg; if (!$data) return $data; $data['source'] = 'Email'; if (!$data['subject']) $data['subject'] = '[No Subject]'; if (!$data['emailId']) $data['emailId'] = $cfg->getDefaultEmailId(); if( !$cfg->useEmailPriority()) unset($data['priorityId']); return $data; } } ?>