Skip to content
Snippets Groups Projects
Select Git revision
  • deaa8c7581984c2bc281dac350152f99885f64a6
  • master default protected
  • 7771-harden-postgres-backup
  • pgsql-dump-with-snapshots
  • update-colors
  • update-docs-css
  • usb-repair-stick
  • desktop-notification
  • 7000-corrections
  • db-detector
10 results

check_clientbackup.sh

Blame
  • index.php 9.43 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>  
     * 2021-03-29  v1.2  <axel.hahn@iml.unibe.ch>  support slashes in branch names
     * ======================================================================
     */
    
        $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);
            }         
            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;
        }
        // ----------------------------------------------------------------------
        // 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.');
        }