Skip to content
Snippets Groups Projects
Commit eea7a809 authored by Hahn Axel (hahn)'s avatar Hahn Axel (hahn)
Browse files

update api/index.php

parent 652d9b45
No related branches found
No related tags found
1 merge request!66php8 only; added variable types; short array syntax; remove glyphicons
......@@ -11,245 +11,271 @@
* ----------------------------------------------------------------------
* 2020-06-16 v0.9 <axel.hahn@iml.unibe.ch>
* 2021-03-29 v1.2 <axel.hahn@iml.unibe.ch> support slashes in branch names
* 2024-09-02 v1.3 <axel.hahn@unibe.ch> php8 only; added variable types; short array syntax
* ======================================================================
*/
$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;
$bDebug = false;
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
/**
* Path to deployment classes
* @var string
*/
$sDirClasses = __DIR__ . '/../deployment/classes/';
/**
* Allowed time delta for client or server
* @var integer
*/
$iMaxAge = 60;
require_once("../../config/inc_projects_config.php");
require_once($sDirClasses . '/project.class.php');
require_once($sDirClasses . 'logger.class.php');
// ----------------------------------------------------------------------
// FUNCTIONS
// ----------------------------------------------------------------------
/**
* Write debug text (if enabled)
*
* @global boolean $bDebug
*
* @param string $s message
* @param string $sLevel level; one of info|
* @return boolean
*/
function _wd(string $s, string $sLevel = 'info'): bool
{
global $bDebug;
if ($bDebug) {
echo "<div class=\"debug debug-$sLevel\">DEBUG: $s</div>";
}
/**
* 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));
return true;
}
/**
* Abort execution of API requestwith error
*
* @param string $s message
* @param integer $iStatus http status code to send
*/
function _quit(string $s, int $iStatus = 400): void
{
$aStatus = [
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(['status' => $iStatus, 'info' => $aStatus[$iStatus], 'message' => $s]);
}
/**
* End with OK output
*
* @param array $Data array data to show as JSON
* @return void
*/
function _done(array $Data): void
{
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 string $sProjectSecret
* @return boolean
*/
function _checkAuth(string $sProjectSecret): bool
{
global $iMaxAge;
$aReqHeaders = apache_request_headers();
_wd('<pre>' . print_r($aReqHeaders, 1) . '</pre>');
if (!isset($aReqHeaders['Authorization'])) {
_quit('Access denied. Missing authorization.', 403);
}
/**
* end with OK output
* @param type $Data
*/
function _done($Data){
echo is_array($Data)
? json_encode($Data, JSON_PRETTY_PRINT)
: $Data
;
die();
if (!isset($aReqHeaders['Date'])) {
_quit('Access denied. Missing field "Date:" in the request header.', 403);
}
/**
* 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 string $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);
}
if(!isset($aReqHeaders['Date'])){
_quit('Access denied. Missing field "Date:" in the request header.', 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. Maybe client or server is out of sync.', 403);
}
if($iAge<-$iMaxAge){
_quit('Access denied. Hash is '.$iAge. ' sec in future but only '.$iMaxAge.' sec are allowed. Maybe client or server is out of sync.', 403);
}
return true;
$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. Maybe client or server is out of sync.', 403);
}
// ----------------------------------------------------------------------
// MAIN
// ----------------------------------------------------------------------
if (!$bDebug){
header('Content-Type: application/json');
if ($iAge < -$iMaxAge) {
_quit('Access denied. Hash is ' . $iAge . ' sec in future but only ' . $iMaxAge . ' sec are allowed. Maybe client or server is out of sync.', 403);
}
_wd('Start: '.date('Y-m-d H:i:s').'<style>body{background:#eee; color:#456;}
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/...
$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;
$sBranch = implode('/', array_slice($aUriSplit, 4));
// $sParam4 = isset($aUriSplit[4]) ? $aUriSplit[4] : false;
// $sParam5 = isset($aUriSplit[5]) ? $aUriSplit[5] : false;
$sMethod = $_SERVER['REQUEST_METHOD'];
_wd('$sPrjId = '.$sPrjId);
_wd('$sPrjAction = '.$sPrjAction);
_wd('$sBranch = ' . $sBranch);
$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 ($sBranch){
$aResult=$oProject->setBranchname($sBranch);
}
$sBranchname=$oProject->getBranchname();
$aRepodata = $oProject->getRemoteBranches(true); // ignore cache = 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.');
}
\ No newline at end of file
_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/...
$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;
$sBranch = implode('/', array_slice($aUriSplit, 4));
// $sParam4 = isset($aUriSplit[4]) ? $aUriSplit[4] : false;
// $sParam5 = isset($aUriSplit[5]) ? $aUriSplit[5] : false;
$sMethod = $_SERVER['REQUEST_METHOD'];
_wd('$sPrjId = ' . $sPrjId);
_wd('$sPrjAction = ' . $sPrjAction);
_wd('$sBranch = ' . $sBranch);
$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 ($sBranch) {
$aResult = $oProject->setBranchname($sBranch);
}
$sBranchname = $oProject->getBranchname();
$aRepodata = $oProject->getRemoteBranches(true); // ignore cache = 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([
'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.');
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment