index.php 8.84 KiB
<?php
/* ======================================================================
*
* A P I F O R C I S E R V E R
*
* GET /api/v1/projects/
* GET /api/v1/project/[ID]/build/[name-of-branch]
* POST /api/v1/project/[ID]/build/[name-of-branch]
* GET /api/v1/project/[ID]/phases
*
* ----------------------------------------------------------------------
* 2020-06-16 v0.9 <axel.hahn@iml.unibe.ch>
* ======================================================================
*/
$bDebug=false;
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once("../../config/inc_projects_config.php");
$sDirClasses=__DIR__.'/../deployment/classes/';
require_once($sDirClasses.'/project.class.php');
require_once($sDirClasses.'logger.class.php');
$iMaxAge=60;
// ----------------------------------------------------------------------
// FUNCTIONS
// ----------------------------------------------------------------------
/**
* write debug text (if enabled)
* @global boolean $bDebug
* @param string $s message
* @param string $sLevel level; one of info|
* @return boolean
*/
function _wd($s, $sLevel='info'){
global $bDebug;
if ($bDebug){
echo '<div class="debug debug-'.$sLevel.'">DEBUG: '.$s.'</div>';
}
return true;
}
/**
* abort execution with error
* @param string $s message
* @param integer $iStatus http status code to send
*/
function _quit($s, $iStatus=400){
$aStatus=array(
400=>'HTTP/1.0 400 Bad Request',
403=>'HTTP/1.0 403 Access denied',
404=>'HTTP/1.0 404 Not found',
);
header($aStatus[$iStatus]);
_done(array('status'=>$iStatus, 'info'=>$aStatus[$iStatus], 'message'=>$s));
}
/**
* end with OK output
* @param type $Data
*/
function _done($Data){
echo is_array($Data)
? json_encode($Data, JSON_PRETTY_PRINT)
: $Data
;
die();
}
/**
* Check authorization in the http request header and age of timestamp
* On a failed check the request will be terminated
* @global int $iMaxAge max allowed age
* @param type $sProjectSecret
* @return boolean
*/
function _checkAuth($sProjectSecret){
global $iMaxAge;
$aReqHeaders=apache_request_headers();
_wd('<pre>'.print_r($aReqHeaders, 1).'</pre>');
if(!isset($aReqHeaders['Authorization'])){
_quit('Access denied. Missing authorization.', 403);
}
$sGotHash= preg_replace('/^.*\:/', '', $aReqHeaders['Authorization']);
$sGotDate= $aReqHeaders['Date'];
$sGotMethod=$_SERVER['REQUEST_METHOD'];
$sGotReq=$_SERVER['REQUEST_URI'];
$sMyData="${sGotMethod}\n${sGotReq}\n${sGotDate}\n";
$sMyHash= base64_encode(hash_hmac("sha1", $sMyData, $sProjectSecret));
_wd('Hash: '.$sGotHash.' -- from header');
_wd('Hash: '.$sMyHash.' -- rebuilt');
if($sGotHash!==$sMyHash){
_quit('Access denied. Invalid hash.', 403);
}
$iAge=date('U')-date('U', strtotime($sGotDate));
_wd('Date: '.$sGotDate.' - age: '.$iAge.' sec');
if($iAge>$iMaxAge){
_quit('Access denied. Hash is out of date: '.$iAge. ' sec is older '.$iMaxAge.' sec', 403);
}
return true;
}
// ----------------------------------------------------------------------
// MAIN
// ----------------------------------------------------------------------
if (!$bDebug){
header('Content-Type: application/json');
}
_wd('Start: '.date('Y-m-d H:i:s').'<style>body{background:#eee; color:#456;}
.debug{background:#ddd; margin-bottom: 2px;}
</style>');
_wd('request uri is '.$_SERVER["REQUEST_URI"]);
_wd('<pre>GET: '.print_r($_GET, 1).'</pre>');
// ---------- SPLIT URL
$aUriSplit= explode('/', preg_replace('/\?.*$/', '', $_SERVER["REQUEST_URI"]));
array_shift($aUriSplit);
array_shift($aUriSplit);
_wd('<pre>$aUriSplit: '.print_r($aUriSplit, 1).'</pre>');
/*
/api/v1/projects/ci/build?auth=123
$aUriSplit: Array
(
[0] => v1
[1] => projects
[2] => ci
[3] => build
)
*/
$sApiVersion = isset($aUriSplit[0]) ? $aUriSplit[0] : false;
$sApiItem = isset($aUriSplit[1]) ? $aUriSplit[1] : false;
if(!$sApiVersion){
_quit('ERROR: no param for api version was found.');
}
if(!$sApiItem){
_quit('ERROR: no param for item was found.');
}
switch ($sApiVersion){
case 'v1':
switch($sApiItem){
case 'projects':
$oProject=new project();
$aList=$oProject->getProjects();
_wd('<pre>'.print_r($aList,1).'</pre>');
_done($aList);
break;;
case 'project':
// path /api/v1/project
$sPrjId = isset($aUriSplit[2]) ? $aUriSplit[2] : false;
$sPrjAction = isset($aUriSplit[3]) ? $aUriSplit[3] : false;
$sParam4 = isset($aUriSplit[4]) ? $aUriSplit[4] : false;
$sParam5 = isset($aUriSplit[5]) ? $aUriSplit[5] : false;
$sMethod = $_SERVER['REQUEST_METHOD'];
_wd('$sPrjId = '.$sPrjId);
_wd('$sPrjAction = '.$sPrjAction);
$oCLog = new logger();
// try to init the given project
try{
ob_start();
$oProject=new project($sPrjId);
// $oProject->setProjectById($sPrjId);
ob_end_clean();
} catch (Exception $exc) {
_quit('ERROR: project with id ['.$sPrjId.'] does not exist.', 404);
}
// get secret
$aPrjCfg=$oProject->getConfig();
$sProjectSecret=isset($aPrjCfg['api']['secret']) ? $aPrjCfg['api']['secret'] : false;
if(!$sProjectSecret){
_quit('Access denied. API access is disabled.');
}
// check authorization
_checkAuth($sProjectSecret);
// echo "OK: request was authorized successfully.\n";
$oProject->oUser->setUser('api');
switch($sPrjAction){
case "build":
if ($sParam4){
$aResult=$oProject->setBranchname($sParam4 . ($sParam5 ? '/'.$sParam5 : ''));
}
$sBranchname=$oProject->getBranchname();
$aRepodata = $oProject->getRemoteBranches(true);
if(!isset($aRepodata[$sBranchname])){
_quit('ERROR: branch not found: '.$sBranchname, 404);
}
// echo "branch is set to ".$oProject->getBranchname()."\n";
if ($sMethod==='GET'){
$sNext=$oProject->getNextPhase();
_done(array(
'branch'=>$sBranchname,
'phase'=>$sNext,
'repo'=>$aRepodata[$sBranchname]
));
}
if ($sMethod==='POST'){
echo "starting build() ...";
flush();
echo $oProject->build();
}
break;;
case "phases":
_done($oProject->getAllPhaseInfos());
break;;
default:
_quit('ERROR: Wrong action ['.$sApiItem.'].');
}
break;;
default:
_quit('ERROR: item ['.$sApiItem.'] is invalid.');
}
break;
default:
_quit('ERROR: Wrong (unsupported) api version.');
}