Exemple #1
0
 public static function validatePath(RecordValidator $validator, Endpoint $Endpoint)
 {
     if (!$Endpoint->Path) {
         $validator->addError('Path', 'Path must not be empty');
         return;
     }
     if ($Endpoint->Path[0] == '/') {
         $validator->addError('Path', 'Path must not start with /');
         return;
     }
     if (substr($Endpoint->Path, -1) == '/') {
         $validator->addError('Path', 'Path must not end with /');
         return;
     }
     if (!preg_match(static::$validPathRegex, $Endpoint->Path)) {
         $validator->addError('Path', 'Path must start with a letter and only contain letters, numbers, periods, hyphens, and underscores');
         return;
     }
     $duplicateConditions = ['Path' => $Endpoint->Path];
     if ($Endpoint->ID) {
         $duplicateConditions[] = 'ID != ' . $Endpoint->ID;
     }
     if (Endpoint::getByWhere($duplicateConditions)) {
         $validator->addError('Path', 'Path matches an existing endpoint\'s');
         return;
     }
 }
 public static function handleBrowseRequest($options = [], $conditions = [], $responseID = null, $responseData = [])
 {
     // apply status filter
     if (empty($_GET['status'])) {
         $status = 'open';
     } elseif ($_GET['status'] == 'any') {
         $status = null;
     } elseif (in_array($_GET['status'], AbstractAlert::getFieldOptions('Status', 'values'))) {
         $status = $_GET['status'];
     } else {
         $status = 'open';
     }
     if ($status) {
         $responseData['status'] = $conditions['Status'] = $status;
     }
     // apply endpoint filter
     if (!empty($_GET['endpoint'])) {
         if (!($Endpoint = Endpoint::getByHandle($_GET['endpoint']))) {
             return static::throwNotFoundError('Endpoint not found');
         }
     }
     if (isset($Endpoint)) {
         $conditions['EndpointID'] = $Endpoint->ID;
         $responseData['Endpoint'] = $Endpoint;
     }
     return parent::handleBrowseRequest($options, $conditions, $responseID, $responseData);
 }
Exemple #3
0
 public function getUnlinkedEndpoints()
 {
     $currentEndpoints = array_map(function ($Endpoint) {
         return $Endpoint->ID;
     }, $this->Endpoints);
     return count($currentEndpoints) ? Endpoint::getAllByWhere('ID NOT IN (' . implode(',', $currentEndpoints) . ')') : Endpoint::getAll();
 }
 public static function handleEndpointsCurrentRequest()
 {
     $GLOBALS['Session']->requireAccountLevel('Staff');
     $results = [];
     foreach (Endpoint::getAll() as $Endpoint) {
         $results[] = ['EndpointID' => $Endpoint->ID, 'requests' => $Endpoint->getCounterMetric('requests'), 'responseTime' => $Endpoint->getAverageMetric('responseTime', 'requests'), 'responsesExecuted' => $Endpoint->getCounterMetric('responsesExecuted'), 'responsesCached' => $Endpoint->getCounterMetric('responsesCached'), 'bytesExecuted' => $Endpoint->getCounterMetric('bytesExecuted'), 'bytesCached' => $Endpoint->getCounterMetric('bytesCached')];
     }
     return static::respond('currentEndpointMetrics', ['data' => $results]);
 }
 public static function handleBrowseRequest($options = [], $conditions = [], $responseID = null, $responseData = [])
 {
     // apply endpoint filter
     if (!empty($_REQUEST['endpoint'])) {
         if (!($Endpoint = Endpoint::getByHandle($_REQUEST['endpoint']))) {
             return static::throwNotFoundError('Endpoint not found');
         }
         $conditions['EndpointID'] = $Endpoint->ID;
         $responseData['Endpoint'] = $Endpoint;
     }
     // apply method filter
     if (!empty($_REQUEST['method'])) {
         $conditions['Method'] = $_REQUEST['method'];
     }
     // apply path filter
     if (!empty($_REQUEST['path-substring'])) {
         $conditions[] = 'Path LIKE "%' . DB::escape($_REQUEST['path-substring']) . '%"';
     }
     // apply path filter
     if (!empty($_REQUEST['query-substring'])) {
         $conditions[] = 'Query LIKE "%' . DB::escape($_REQUEST['query-substring']) . '%"';
     }
     // apply IP filter
     if (!empty($_REQUEST['ip'])) {
         if (!filter_var($_REQUEST['ip'], FILTER_VALIDATE_IP)) {
             return static::throwError('IP is invalid');
         }
         $conditions['ClientIP'] = ip2long($_REQUEST['ip']);
     }
     // apply key filter
     if (!empty($_REQUEST['key'])) {
         if (!($Key = Key::getByKey($_REQUEST['key']))) {
             return static::throwError('key is invalid');
         }
         $conditions['KeyID'] = $Key->ID;
     }
     // apply time filter
     if (!empty($_REQUEST['time-max']) && ($timeMax = strtotime($_REQUEST['time-max']))) {
         $conditions[] = 'Created <= "' . date('Y-m-d H:i:s', $timeMax) . '"';
     }
     if (!empty($_REQUEST['time-min']) && ($timeMin = strtotime($_REQUEST['time-min']))) {
         $conditions[] = 'Created >= "' . date('Y-m-d H:i:s', $timeMin) . '"';
     }
     // apply type filter
     if (!empty($_REQUEST['type'])) {
         if ($_REQUEST['type'] == 'ping') {
             $conditions['Class'] = PingTransaction::class;
         } elseif ($_REQUEST['type'] == 'consumer') {
             $conditions['Class'] = Transaction::class;
         }
     }
     return parent::handleBrowseRequest($options, $conditions, $responseID, $responseData);
 }
 public static function handleRequest()
 {
     $GLOBALS['Session']->requireAccountLevel('Staff');
     if (empty($_REQUEST['endpoint'])) {
         return static::throwInvalidRequestError('endpoint required');
     } elseif (!($Endpoint = Endpoint::getByHandle($_REQUEST['endpoint']))) {
         return static::throwNotFoundError('Endpoint not found');
     }
     $cachedResponses = $Endpoint->getCachedResponses();
     $limit = isset($_GET['limit']) && ctype_digit($_GET['limit']) ? (int) $_GET['limit'] : static::$defaultLimit;
     $offset = isset($_GET['offset']) && ctype_digit($_GET['offset']) ? (int) $_GET['offset'] : 0;
     return static::respond('cachedResponses', ['success' => true, 'data' => $limit ? array_slice($cachedResponses, $offset, $limit) : $cachedResponses, 'total' => count($cachedResponses), 'limit' => $limit, 'offset' => $offset, 'Endpoint' => $Endpoint]);
 }
 public static function handleRequest()
 {
     // get request totals for trailing week
     if (false === ($weeklyRequestsByEndpoint = Cache::fetch('endpoints-requests-week'))) {
         $weeklyRequestsByEndpoint = array_map('intval', DB::valuesTable('EndpointID', 'requests', 'SELECT' . '  SUBSTRING_INDEX(@context := SUBSTRING_INDEX(`Key`, "/", 2), "/", -1) AS EndpointID,' . '  SUM(Value) AS requests' . ' FROM `%s`' . ' WHERE' . '  `Timestamp` BETWEEN DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 1 WEEK) AND CURRENT_TIMESTAMP AND ' . '  `Key` LIKE "endpoints/%%" AND' . '  `Key` REGEXP "^endpoints/[[:digit:]]+/requests$"' . ' GROUP BY EndpointID', [MetricSample::$tableName]));
         Cache::store('endpoints-requests-week', $weeklyRequestsByEndpoint, static::$popularityTTL);
     }
     // get public endpoints
     if (false === ($publicEndpointIds = Cache::fetch('endpoints-public'))) {
         try {
             $publicEndpointIds = array_map('intval', DB::allValues('ID', 'SELECT ID FROM `%s` WHERE Public', Endpoint::$tableName));
         } catch (TableNotFoundException $e) {
             $publicEndpointIds = [];
         }
         Cache::store('endpoints-public', $publicEndpointIds, static::$publicTTL);
     }
     // fetch endpoint instances
     $publicEndpoints = array_map(function ($endpointId) {
         return Endpoint::getByID($endpointId);
     }, $publicEndpointIds);
     // determine requested order
     if (!empty($_GET['order']) && $_GET['order'] == 'alpha') {
         $order = 'alpha';
         $sortFn = function ($a, $b) {
             return strcasecmp($a->Path, $b->Path);
         };
     } elseif (!empty($_GET['order']) && $_GET['order'] == 'newest') {
         $order = 'newest';
         $sortFn = function ($a, $b) {
             if ($a->ID == $b->ID) {
                 return 0;
             }
             return $a->ID < $b->ID ? 1 : -1;
         };
     } else {
         $order = 'popularity';
         $sortFn = function ($a, $b) use($weeklyRequestsByEndpoint) {
             $a = isset($weeklyRequestsByEndpoint[$a->ID]) ? $weeklyRequestsByEndpoint[$a->ID] : 0;
             $b = isset($weeklyRequestsByEndpoint[$b->ID]) ? $weeklyRequestsByEndpoint[$b->ID] : 0;
             if ($a == $b) {
                 return 0;
             }
             return $a < $b ? 1 : -1;
         };
     }
     // apply order
     usort($publicEndpoints, $sortFn);
     static::respond('home', ['data' => $publicEndpoints, 'order' => $order]);
 }
 public static function handleRequest()
 {
     if (empty(Site::$pathStack) || empty(Site::$pathStack[0])) {
         return static::throwInvalidRequestError();
     }
     // get endpoint
     if (!($Endpoint = Endpoints\Endpoint::getFromPath(Site::$pathStack))) {
         return static::throwNotFoundError('Endpoint not found');
     }
     // check access
     if (!$Endpoint->Public) {
         $GLOBALS['Session']->requireAccountLevel('Staff');
     }
     return static::respond('docs', $Endpoint->getSwaggerData());
 }
 public static function handleRequest()
 {
     $GLOBALS['Session']->requireAccountLevel('Staff');
     if (empty($_GET['time-max']) || !($timeMax = strtotime($_GET['time-max']))) {
         $timeMax = time();
     }
     if (empty($_GET['time-min']) || !($timeMin = strtotime($_GET['time-min']))) {
         $timeMin = $timeMax - 3600 * 24 * 7;
         // 1 week
     }
     if (!empty($_GET['endpoint'])) {
         if (!($Endpoint = Endpoint::getByHandle($_GET['endpoint']))) {
             return static::throwNotFoundError('endpoint not found');
         }
     }
     $topUsers = DB::allRecords('SELECT' . '  @user := SUBSTRING_INDEX(SUBSTRING_INDEX(`Key`, "/", -2), "/", 1) AS User,' . '  SUBSTRING_INDEX(@user, ":", 1) AS UserType,' . '  SUBSTRING_INDEX(@user, ":", -1) AS UserIdentifier,' . '  SUM(Value) AS TotalRequests,' . '  MIN(Timestamp) AS EarliestRequest,' . '  MAX(Timestamp) AS LatestRequest' . ' FROM `%s`' . ' WHERE' . '  `Timestamp` BETWEEN "%s" AND "%s" AND ' . '  `Key` LIKE "endpoints/%s/users/%%/requests"' . ' GROUP BY User' . ' ORDER BY TotalRequests DESC' . ' LIMIT %u', [MetricSample::$tableName, date('Y-m-d H:i:s', $timeMin), date('Y-m-d H:i:s', $timeMax), $Endpoint ? $Endpoint->ID : '%', !empty($_GET['limit']) && ctype_digit($_GET['limit']) ? $_GET['limit'] : 20]);
     return static::respond('topUsers', ['data' => $topUsers, 'Endpoint' => $Endpoint]);
 }
 public static function handleEndpointsRequest(Key $Key)
 {
     if ($endpointId = static::shiftPath()) {
         $Endpoint = Endpoint::getByID($endpointId);
         if (!$Endpoint || !in_array($Endpoint, $Key->Endpoints)) {
             return static::throwNotFoundError('Requested endpoint not added to this key');
         }
         return static::handleEndpointRequest($Key, $Endpoint);
     }
     switch ($_SERVER['REQUEST_METHOD']) {
         case 'GET':
             return static::respond('keyEndpoints', ['data' => KeyEndpoint::getAllByWhere(['KeyID' => $Key->ID])]);
         case 'POST':
             $GLOBALS['Session']->requireAccountLevel('Staff');
             if (empty($_POST['EndpointID']) || !($Endpoint = Endpoint::getByID($_POST['EndpointID']))) {
                 return static::throwInvalidRequestError('Valid EndpointID must be provided');
             }
             if (KeyEndpoint::getByWhere(['KeyID' => $Key->ID, 'EndpointID' => $Endpoint->ID])) {
                 return static::throwInvalidRequestError('Provided endpoint already added to this key');
             }
             $KeyEndpoint = KeyEndpoint::create(['KeyID' => $Key->ID, 'EndpointID' => $Endpoint->ID], true);
             return static::respond('keyEndpointAdded', ['success' => true, 'data' => $KeyEndpoint]);
             break;
         default:
             return static::throwInvalidRequestError('Method not supported');
     }
 }
<?php

namespace Gatekeeper;

use DB;
use HttpProxy;
use Gatekeeper\Alerts\TestFailed;
use Gatekeeper\Endpoints\Endpoint;
use Gatekeeper\Transactions\PingTransaction;
// find all endpoints that are overdue or near due for a ping
$endpoints = Endpoint::getAllByQuery('SELECT Endpoint.*' . ' FROM `%s` Endpoint' . ' WHERE' . '  Endpoint.PingFrequency IS NOT NULL AND' . '  IFNULL((' . '    SELECT Created FROM `%s` Transaction WHERE EndpointID = Endpoint.ID AND Class = "%s" ORDER BY ID DESC LIMIT 1' . '  ), 0) < DATE_SUB(CURRENT_TIMESTAMP, INTERVAL (Endpoint.PingFrequency * 0.7) MINUTE)', [Endpoint::$tableName, PingTransaction::$tableName, DB::escape(PingTransaction::class)]);
// loop through all endpoints to execute, test, and record the ping URI
foreach ($endpoints as $Endpoint) {
    printf('Testing endpoint %s...', $Endpoint->getTitle());
    // execute and capture request
    // TODO: use curl_multi_exec somehow?
    $response = HttpProxy::relayRequest(['autoAppend' => false, 'autoQuery' => false, 'url' => rtrim($Endpoint->InternalEndpoint, '/') . '/' . ltrim($Endpoint->PingURI, '/'), 'interface' => ApiRequestHandler::$sourceInterface, 'timeout' => 15, 'timeoutConnect' => 5, 'returnResponse' => true]);
    // evaluate success
    $testPassed = $response['info']['http_code'] == 200 && (!$Endpoint->PingTestPattern || preg_match($Endpoint->PingTestPattern, $response['body']));
    // record transaction
    list($path, $query) = explode('?', $Endpoint->PingURI);
    $Transaction = PingTransaction::create(['Endpoint' => $Endpoint, 'ClientIP' => ip2long($response['info']['local_ip']), 'Method' => 'GET', 'Path' => $path, 'Query' => $query, 'ResponseTime' => $response['info']['starttransfer_time'] * 1000, 'ResponseCode' => $response['info']['http_code'], 'ResponseBytes' => $response['info']['size_download'], 'TestPassed' => $testPassed], true);
    // open alert if necessary, or close any existing one
    if (!$testPassed) {
        TestFailed::open($Endpoint, ['transactionId' => $Transaction->ID, 'request' => ['uri' => $Endpoint->PingURI], 'response' => ['status' => $Transaction->ResponseCode, 'headers' => $response['headers'], 'body' => $response['body'], 'bytes' => $Transaction->ResponseBytes, 'time' => $Transaction->ResponseTime]]);
    } else {
        $OpenAlert = TestFailed::getByWhere(['Class' => TestFailed::class, 'EndpointID' => $Endpoint->ID, 'Status' => 'open']);
        if ($OpenAlert) {
            $OpenAlert->Status = 'closed';
            $OpenAlert->save();
        }
<?php

namespace Gatekeeper;

use Gatekeeper\Endpoints\Endpoint;
// detect endpoint if it has not already been set
if (!$_EVENT['request']->getEndpoint()) {
    if (!($Endpoint = Endpoint::getFromPath($_EVENT['request']->getPathStack()))) {
        return ApiRequestHandler::throwNotFoundError('No endpoint was found that can handle this path');
    }
    // trim path stack
    $_EVENT['request']->setPathStack(array_slice($_EVENT['request']->getPathStack(), substr_count($Endpoint->Path, '/') + 1));
    // save determined endpoint to request object
    $_EVENT['request']->setEndpoint($Endpoint);
}