forked from osTicket/osTicket-1.7
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request osTicket#461 from protich/feature/api_revisited
Feature/api revisited
- Loading branch information
Showing
31 changed files
with
805 additions
and
417 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
/********************************************************************* | ||
api.inc.php | ||
File included on every API page...handles security and abuse issues | ||
File included on every API page...handles common includes. | ||
Peter Rotich <[email protected]> | ||
Copyright (c) 2006-2012 osTicket | ||
|
@@ -13,74 +13,9 @@ | |
vim: expandtab sw=4 ts=4 sts=4: | ||
**********************************************************************/ | ||
//postfix exit codes see /usr/include/sysexits.h | ||
define('EX_DATAERR', 65); /* data format error */ | ||
define('EX_NOINPUT', 66); /* cannot open input */ | ||
define('EX_UNAVAILABLE', 69); /* service unavailable */ | ||
define('EX_IOERR', 74); /* input/output error */ | ||
define('EX_TEMPFAIL',75); /* temp failure; user is invited to retry */ | ||
define('EX_NOPERM', 77); /* permission denied */ | ||
define('EX_CONFIG', 78); /* configuration error */ | ||
|
||
define('EX_SUCCESS',0); /* success baby */ | ||
|
||
if(!file_exists('../main.inc.php')) exit(EX_CONFIG); | ||
file_exists('../main.inc.php') or die('System Error'); | ||
require_once('../main.inc.php'); | ||
if(!defined('INCLUDE_DIR')) exit(EX_CONFIG); | ||
|
||
require_once(INCLUDE_DIR.'class.http.php'); | ||
require_once(INCLUDE_DIR.'class.api.php'); | ||
|
||
define('OSTAPIINC',TRUE); // Define tag that included files can check | ||
|
||
$remotehost=(isset($_SERVER['HTTP_HOST']) || isset($_SERVER['REMOTE_ADDR']))?TRUE:FALSE; | ||
/* API exit helper */ | ||
function api_exit($code,$msg='') { | ||
global $remotehost, $ost; | ||
|
||
if($code!=EX_SUCCESS) { | ||
//Error occured... | ||
$_SESSION['api']['errors']+=1; | ||
$_SESSION['api']['time']=time(); | ||
$ost->logWarning("API error - code #$code", $msg, ($_SESSION['api']['errors']>10)); | ||
//echo "API Error:.$msg"; | ||
} | ||
if($remotehost){ | ||
switch($code) { | ||
case EX_SUCCESS: | ||
Http::response(200,$code,'text/plain'); | ||
break; | ||
case EX_UNAVAILABLE: | ||
Http::response(405,$code,'text/plain'); | ||
break; | ||
case EX_NOPERM: | ||
Http::response(403,$code,'text/plain'); | ||
break; | ||
case EX_DATAERR: | ||
case EX_NOINPUT: | ||
default: | ||
Http::response(416,$code,'text/plain'); | ||
} | ||
} | ||
exit($code); | ||
} | ||
|
||
//Remote hosts need authorization. | ||
$apikey = null; | ||
if($remotehost) { | ||
//Upto 10 consecutive errors allowed...before a 2 minute timeout. | ||
//One more error during timeout and timeout starts a new clock | ||
if($_SESSION['api']['errors']>10 && (time()-$_SESSION['api']['time'])<=2*60) // timeout! | ||
api_exit(EX_NOPERM, 'Remote host ['.$_SERVER['REMOTE_ADDR'].'] in timeout - error #'.$_SESSION['api']['errors']); | ||
|
||
if(!isset($_SERVER['HTTP_X_API_KEY']) || !isset($_SERVER['REMOTE_ADDR'])) | ||
api_exit(EX_NOPERM, 'API key required'); | ||
elseif(!($apikey=API::lookupByKey($_SERVER['HTTP_X_API_KEY'], $_SERVER['REMOTE_ADDR'])) | ||
|| !$apikey->isActive() | ||
|| $apikey->getIPAddr()!=$_SERVER['REMOTE_ADDR']) | ||
api_exit(EX_NOPERM, 'API key not found/active or source IP not authorized'); | ||
|
||
//At this point we know the remote host/IP is allowed. | ||
$_SESSION['api']['errors']=0; //clear errors for the session. | ||
} | ||
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
/********************************************************************* | ||
cron.php | ||
File to handle cron job calls (local and remote). | ||
File to handle LOCAL cron job calls. | ||
Peter Rotich <[email protected]> | ||
Copyright (c) 2006-2012 osTicket | ||
|
@@ -13,9 +13,11 @@ | |
vim: expandtab sw=4 ts=4 sts=4: | ||
**********************************************************************/ | ||
if (substr(php_sapi_name(), 0, 3) != 'cli') | ||
die('cron.php only supports local cron jobs - use http -> api/task/cron'); | ||
|
||
@chdir(realpath(dirname(__FILE__)).'/'); //Change dir. | ||
require('api.inc.php'); | ||
require_once(INCLUDE_DIR.'class.cron.php'); | ||
Cron::run(); | ||
$ost->logDebug('Cron Job','External cron job executed ['.$_SERVER['REMOTE_ADDR'].']'); | ||
require_once(INCLUDE_DIR.'api.cron.php'); | ||
LocalCronApiController::call(); | ||
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ | |
/********************************************************************* | ||
pipe.php | ||
Converts piped emails to ticket. Both local and remote! | ||
Converts piped emails to ticket. Just local - remote must use /api/tickets.email | ||
Peter Rotich <[email protected]> | ||
Copyright (c) 2006-2012 osTicket | ||
|
@@ -14,122 +14,14 @@ | |
vim: expandtab sw=4 ts=4 sts=4: | ||
**********************************************************************/ | ||
@chdir(realpath(dirname(__FILE__)).'/'); //Change dir. | ||
ini_set('memory_limit', '256M'); //The concern here is having enough mem for emails with attachments. | ||
$apikey = null; | ||
require('api.inc.php'); | ||
require_once(INCLUDE_DIR.'class.mailparse.php'); | ||
require_once(INCLUDE_DIR.'class.email.php'); | ||
|
||
//Make sure piping is enabled! | ||
if(!$cfg->isEmailPipingEnabled()) | ||
api_exit(EX_UNAVAILABLE,'Email piping not enabled - check MTA settings.'); | ||
elseif($apikey && !$apikey->canCreateTickets()) //apikey is ONLY set on remote post - local post don't need a key (for now). | ||
api_exit(EX_NOPERM, 'API key not authorized'); | ||
|
||
//Get the input | ||
$data=isset($_SERVER['HTTP_HOST'])?file_get_contents('php://input'):file_get_contents('php://stdin'); | ||
if(empty($data)){ | ||
api_exit(EX_NOINPUT,'No data'); | ||
} | ||
|
||
//Parse the email. | ||
$parser= new Mail_Parse($data); | ||
if(!$parser->decode()){ //Decode...returns false on decoding errors | ||
api_exit(EX_DATAERR,'Email parse failed ['.$parser->getError()."]\n\n".$data); | ||
} | ||
|
||
|
||
|
||
//Check from address. make sure it is not a banned address. | ||
$fromlist = $parser->getFromAddressList(); | ||
//Check for parsing errors on FROM address. | ||
if(!$fromlist || PEAR::isError($fromlist)){ | ||
api_exit(EX_DATAERR,'Invalid FROM address ['.$fromlist?$fromlist->getMessage():''."]\n\n".$data); | ||
} | ||
|
||
$from=$fromlist[0]; //Default. | ||
foreach($fromlist as $fromobj){ | ||
if(!Validator::is_email($fromobj->mailbox.'@'.$fromobj->host)) | ||
continue; | ||
$from=$fromobj; | ||
break; | ||
} | ||
|
||
//TO Address:Try to figure out the email associated with the message. | ||
$tolist = $parser->getToAddressList(); | ||
foreach ($tolist as $toaddr){ | ||
if(($emailId=Email::getIdByEmail($toaddr->mailbox.'@'.$toaddr->host))){ | ||
//We've found target email. | ||
break; | ||
} | ||
} | ||
if(!$emailId && ($cclist=$parser->getCcAddressList())) { | ||
foreach ($cclist as $ccaddr){ | ||
if(($emailId=Email::getIdByEmail($ccaddr->mailbox.'@'.$ccaddr->host))){ | ||
break; | ||
} | ||
} | ||
} | ||
//TODO: Options to reject emails without a matching To address in db? May be it was Bcc? Current Policy: If you pipe, we accept policy | ||
|
||
require_once(INCLUDE_DIR.'class.ticket.php'); //We now need this bad boy! | ||
//Only local piping supported via pipe.php | ||
if (substr(php_sapi_name(), 0, 3) != 'cli') | ||
die('pipe.php only supports local piping - use http -> api/tickets.email'); | ||
|
||
$var=array(); | ||
$deptId=0; | ||
$name=trim($from->personal,'"'); | ||
if($from->comment && $from->comment[0]) | ||
$name.=' ('.$from->comment[0].')'; | ||
$subj=utf8_encode($parser->getSubject()); | ||
if(!($body=Format::stripEmptyLines($parser->getBody()))) | ||
$body=$subj?$subj:'(EMPTY)'; | ||
|
||
$var['mid']=$parser->getMessageId(); | ||
$var['email']=$from->mailbox.'@'.$from->host; | ||
$var['name']=$name?utf8_encode($name):$var['email']; | ||
$var['emailId']=$emailId?$emailId:$cfg->getDefaultEmailId(); | ||
$var['subject']=$subj?$subj:'[No Subject]'; | ||
$var['message']=utf8_encode(Format::stripEmptyLines($body)); | ||
$var['header']=$parser->getHeader(); | ||
$var['priorityId']=$cfg->useEmailPriority()?$parser->getPriority():0; | ||
|
||
$ticket=null; | ||
if(preg_match ("[[#][0-9]{1,10}]", $var['subject'], $regs)) { | ||
$extid=trim(preg_replace("/[^0-9]/", "", $regs[0])); | ||
if(!($ticket=Ticket::lookupByExtId($extid, $var['email'])) || strcasecmp($ticket->getEmail(), $var['email'])) | ||
$ticket = null; | ||
} | ||
|
||
$errors=array(); | ||
$msgid=0; | ||
if($ticket) { | ||
//post message....postMessage does the cleanup. | ||
if(!($msgid=$ticket->postMessage($var['message'], 'Email',$var['mid'],$var['header']))) | ||
api_exit(EX_DATAERR, 'Unable to post message'); | ||
|
||
} elseif(($ticket=Ticket::create($var, $errors, 'email'))) { // create new ticket. | ||
$msgid=$ticket->getLastMsgId(); | ||
} else { // failure.... | ||
|
||
// report success on hard rejection | ||
if(isset($errors['errno']) && $errors['errno'] == 403) | ||
api_exit(EX_SUCCESS); | ||
|
||
// check if it's a bounce! | ||
if($var['header'] && TicketFilter::isAutoBounce($var['header'])) { | ||
$ost->logWarning('Bounced email', $var['message'], false); | ||
api_exit(EX_SUCCESS); | ||
} | ||
|
||
api_exit(EX_DATAERR, 'Ticket create Failed '.implode("\n",$errors)."\n\n"); | ||
} | ||
|
||
//Ticket created...save attachments if enabled. | ||
if($ticket && $cfg->allowEmailAttachments() && ($attachments=$parser->getAttachments())) { | ||
foreach($attachments as $attachment) { | ||
if($attachment['filename'] && $ost->isFileTypeAllowed($attachment['filename'])) | ||
$ticket->saveAttachment(array('name' => $attachment['filename'], 'data' => $attachment['body']), $msgid, 'M'); | ||
} | ||
} | ||
api_exit(EX_SUCCESS); | ||
ini_set('memory_limit', '256M'); //The concern here is having enough mem for emails with attachments. | ||
@chdir(realpath(dirname(__FILE__)).'/'); //Change dir. | ||
require('api.inc.php'); | ||
require_once(INCLUDE_DIR.'api.tickets.php'); | ||
PipeApiController::process(); | ||
?> |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<?php | ||
|
||
include_once INCLUDE_DIR.'class.cron.php'; | ||
|
||
class CronApiController extends ApiController { | ||
|
||
function execute() { | ||
|
||
if(!($key=$this->requireApiKey()) || !$key->canExecuteCronJob()) | ||
return $this->exerr(401, 'API key not authorized'); | ||
|
||
$this->run(); | ||
} | ||
|
||
/* private */ | ||
function run() { | ||
global $ost; | ||
|
||
Cron::run(); | ||
|
||
$ost->logDebug('Cron Job','Cron job executed ['.$_SERVER['REMOTE_ADDR'].']'); | ||
$this->response(200,'Completed'); | ||
} | ||
} | ||
|
||
class LocalCronApiController extends CronApiController { | ||
|
||
function response($code, $resp) { | ||
|
||
if($code == 200) //Success - exit silently. | ||
exit(0); | ||
|
||
//On error echo the response (error) | ||
echo $resp; | ||
exit(1); | ||
} | ||
|
||
function call() { | ||
$cron = new LocalCronApiController(); | ||
$cron->run(); | ||
} | ||
} | ||
?> |
Oops, something went wrong.