Merge 9dbee6765b
into 676e80d42f
commit
cdae50905b
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* PHP Server Monitor
|
||||
* Monitor your servers and websites.
|
||||
*
|
||||
* This file is part of PHP Server Monitor.
|
||||
* PHP Server Monitor is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* PHP Server Monitor is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PHP Server Monitor. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @package phpservermon
|
||||
* @author Pepijn Over <pep@mailbox.org>
|
||||
* @copyright Copyright (c) 2008-2017 Pepijn Over <pep@mailbox.org>
|
||||
* @license http://www.gnu.org/licenses/gpl.txt GNU GPL v3
|
||||
* @version Release: @package_version@
|
||||
* @link http://www.phpservermonitor.org/
|
||||
**/
|
||||
|
||||
require __DIR__.'/../src/bootstrap.php';
|
||||
|
||||
$router->setIsApi(true);
|
||||
|
||||
psm_no_cache();
|
||||
|
||||
$mod = psm_GET('mod');
|
||||
|
||||
try {
|
||||
$router->run($mod);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
// invalid module, try the default one
|
||||
// it that somehow also doesnt exist, we have a bit of an issue
|
||||
// and we really have no reason catch it
|
||||
$router->run(PSM_MODULE_DEFAULT);
|
||||
}
|
|
@ -390,7 +390,7 @@ namespace {
|
|||
* @param string|bool $website_password Password website
|
||||
* @param string|null $request_method Request method like GET, POST etc.
|
||||
* @param string|null $post_field POST data
|
||||
* @return string cURL result
|
||||
* @return array ["result" => cURL result, "info" => cURL info array]
|
||||
*/
|
||||
function psm_curl_get(
|
||||
$href,
|
||||
|
@ -456,6 +456,8 @@ namespace {
|
|||
}
|
||||
|
||||
$result = curl_exec($ch);
|
||||
$info = curl_getinfo($ch);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
if (defined('PSM_DEBUG') && PSM_DEBUG === true && psm_is_cli()) {
|
||||
|
@ -466,7 +468,7 @@ namespace {
|
|||
'==============END cURL Resul for: ' . $href . '===========================================' . PHP_EOL;
|
||||
}
|
||||
|
||||
return $result;
|
||||
return ["result" => $result, "info" => $info];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -551,7 +553,7 @@ namespace {
|
|||
// been more than a week since update, lets go
|
||||
// update last check date
|
||||
psm_update_conf('last_update_check', time());
|
||||
$latest = psm_curl_get(PSM_UPDATE_URL);
|
||||
$latest = psm_curl_get(PSM_UPDATE_URL)["result"];
|
||||
// extract latest version from Github.
|
||||
preg_match('/"tag_name":"[v](([\d][.][\d][.][\d])(-?\w*))"/', $latest, $latest);
|
||||
// add latest version to database
|
||||
|
|
|
@ -84,6 +84,7 @@ $sm_lang = array(
|
|||
'user_name' => 'Uživatelské jméno',
|
||||
'password' => 'Heslo',
|
||||
'password_repeat' => 'Stejné heslo (pro kontrolu)',
|
||||
'api_hash' => 'API hash',
|
||||
'password_leave_blank' => 'Ponechte prázdné pro ponechání beze změn.',
|
||||
'level' => 'Oprávnění',
|
||||
'level_10' => 'Administrátor',
|
||||
|
|
|
@ -102,6 +102,7 @@ $sm_lang = array(
|
|||
'user_name' => 'Username',
|
||||
'password' => 'Password',
|
||||
'password_repeat' => 'Password repeat',
|
||||
'api_hash' => 'API hash',
|
||||
'password_leave_blank' => 'Leave blank to keep unchanged',
|
||||
'level' => 'Level',
|
||||
'level_10' => 'Administrator',
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* PHP Server Monitor
|
||||
* Monitor your servers and websites.
|
||||
*
|
||||
* This file is part of PHP Server Monitor.
|
||||
* PHP Server Monitor is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* PHP Server Monitor is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PHP Server Monitor. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @package phpservermon
|
||||
* @author Pepijn Over <pep@mailbox.org>
|
||||
* @copyright Copyright (c) 2008-2017 Pepijn Over <pep@mailbox.org>
|
||||
* @license http://www.gnu.org/licenses/gpl.txt GNU GPL v3
|
||||
* @version Release: @package_version@
|
||||
* @link http://www.phpservermonitor.org/
|
||||
* */
|
||||
/**
|
||||
* Server module. List all servers, return list as JSON.
|
||||
*/
|
||||
|
||||
namespace psm\Module\Server\Controller;
|
||||
|
||||
use psm\Service\Database;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Twig_Environment;
|
||||
|
||||
/**
|
||||
* Description of ApiStatusController
|
||||
*
|
||||
* @author Matej Kminek <matej.kminek@attendees.eu>, 24. 11. 2019
|
||||
*/
|
||||
class ApiStatusController extends AbstractServerController {
|
||||
|
||||
/**
|
||||
* Current server id
|
||||
* @var int|\PDOStatement $server_id
|
||||
*/
|
||||
protected $server_id;
|
||||
|
||||
function __construct(Database $db, Twig_Environment $twig) {
|
||||
parent::__construct($db, $twig);
|
||||
|
||||
$this->server_id = isset($_GET['id']) ? intval($_GET['id']) : 0;
|
||||
|
||||
$this->setActions(array('detail', 'list'), 'list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the view template
|
||||
*/
|
||||
protected function executeList() {
|
||||
$server = $this->getServers();
|
||||
|
||||
return new JsonResponse($server, Response::HTTP_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the view template
|
||||
*/
|
||||
protected function executeDetail() {
|
||||
if(empty($this->server_id)){
|
||||
return new JsonResponse("Not found", Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$server = $this->getServers($this->server_id);
|
||||
|
||||
if (empty($server)) {
|
||||
return $this->runAction('index');
|
||||
}
|
||||
|
||||
return new JsonResponse($server, Response::HTTP_OK);
|
||||
}
|
||||
|
||||
}
|
|
@ -46,6 +46,7 @@ class ServerModule implements ModuleInterface
|
|||
'log' => __NAMESPACE__ . '\Controller\LogController',
|
||||
'status' => __NAMESPACE__ . '\Controller\StatusController',
|
||||
'update' => __NAMESPACE__ . '\Controller\UpdateController',
|
||||
'api.status' => __NAMESPACE__ . '\Controller\ApiStatusController',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,7 +161,8 @@ class UserController extends AbstractController
|
|||
'pushover_key',
|
||||
'pushover_device',
|
||||
'telegram_id',
|
||||
'email'
|
||||
'email',
|
||||
'api_hash'
|
||||
);
|
||||
|
||||
if ($user_id == 0) {
|
||||
|
@ -257,7 +258,8 @@ class UserController extends AbstractController
|
|||
'pushover_key',
|
||||
'pushover_device',
|
||||
'telegram_id',
|
||||
'email'
|
||||
'email',
|
||||
'api_hash'
|
||||
);
|
||||
$clean = array();
|
||||
foreach ($fields as $field) {
|
||||
|
@ -381,6 +383,7 @@ class UserController extends AbstractController
|
|||
'label_user_name' => psm_get_lang('users', 'user_name'),
|
||||
'label_password' => psm_get_lang('users', 'password'),
|
||||
'label_password_repeat' => psm_get_lang('users', 'password_repeat'),
|
||||
'label_api_hash' => psm_get_lang('users', 'api_hash'),
|
||||
'label_level' => psm_get_lang('users', 'level'),
|
||||
'label_level_description' => psm_get_lang('users', 'level_description'),
|
||||
'label_mobile' => psm_get_lang('users', 'mobile'),
|
||||
|
|
|
@ -53,6 +53,12 @@ class Router
|
|||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* Indication whether this request comes from API
|
||||
* @var boolean
|
||||
*/
|
||||
private $isApi = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->container = $this->buildServiceContainer();
|
||||
|
@ -85,13 +91,19 @@ class Router
|
|||
}
|
||||
$this->buildTwigEnvironment();
|
||||
|
||||
$controller = $this->getController($mod, $controller);
|
||||
$controller = $this->isApi ?
|
||||
$this->getController($mod, $controller, true) :
|
||||
$this->getController($mod, $controller);
|
||||
$action = null;
|
||||
|
||||
try {
|
||||
$this->validateRequest($controller);
|
||||
} catch (\InvalidArgumentException $ex) {
|
||||
switch ($ex->getMessage()) {
|
||||
case 'invalid_api_key':
|
||||
$controller = $this->getController('error');
|
||||
$action = '403';
|
||||
break;
|
||||
case 'login_required':
|
||||
$controller = $this->getController('user', 'login');
|
||||
break;
|
||||
|
@ -116,16 +128,22 @@ class Router
|
|||
* Get an instance of the requested controller.
|
||||
* @param string $module_id
|
||||
* @param string $controller_id if NULL, default controller will be used
|
||||
* @param boolean $isApi
|
||||
* @return \psm\Module\ControllerInterface
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getController($module_id, $controller_id = null)
|
||||
public function getController($module_id, $controller_id = null, $isApi = false)
|
||||
{
|
||||
if ($controller_id === null) {
|
||||
// by default, we use the controller with the same id as the module.
|
||||
$controller_id = $module_id;
|
||||
}
|
||||
|
||||
if ($isApi) {
|
||||
// if this is an api request, serve api.controller
|
||||
$controller_id = "api." . $controller_id;
|
||||
}
|
||||
|
||||
$module = $this->container->get('module.' . $module_id);
|
||||
$controllers = $module->getControllers();
|
||||
if (!isset($controllers[$controller_id]) || !class_exists($controllers[$controller_id])) {
|
||||
|
@ -165,6 +183,10 @@ class Router
|
|||
{
|
||||
$request = Request::createFromGlobals();
|
||||
|
||||
if ($this->isApi) {
|
||||
return $this->validateApiRequest($controller, $request);
|
||||
}
|
||||
|
||||
if ($request->getMethod() == 'POST') {
|
||||
// require CSRF token for all POST calls
|
||||
$session = $this->container->get('user')->getSession();
|
||||
|
@ -200,6 +222,30 @@ class Router
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Api requets before heading to a controller
|
||||
* @param \psm\Module\ControllerInterface $controller
|
||||
* @param Request $request
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function validateApiRequest(\psm\Module\ControllerInterface $controller, Request $request)
|
||||
{
|
||||
$result = $controller->getUser()->loginWithApiKey($request->query->get("key"));
|
||||
|
||||
if (!$result) {
|
||||
throw new \InvalidArgumentException('invalid_api_key');
|
||||
}
|
||||
|
||||
// get min required level for this controller and make sure the user matches
|
||||
$min_lvl = $controller->getMinUserLevelRequired();
|
||||
|
||||
if ($min_lvl < PSM_USER_ANONYMOUS) {
|
||||
// if user is not logged in, load login module
|
||||
if ($this->container->get('user')->getUserLevel() > $min_lvl) {
|
||||
throw new \InvalidArgumentException('invalid_user_level');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a new service container
|
||||
|
@ -247,4 +293,15 @@ class Router
|
|||
|
||||
return $twig;
|
||||
}
|
||||
|
||||
public function getIsApi()
|
||||
{
|
||||
return $this->isApi;
|
||||
}
|
||||
|
||||
public function setIsApi($isApi)
|
||||
{
|
||||
$this->isApi = $isApi;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,6 +156,25 @@ class User
|
|||
return $query_user->fetchObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Search into database for the user data of api key specified as parameter
|
||||
* @return object|boolean user data as an object if existing user
|
||||
*/
|
||||
public function getUserByApiKey($key)
|
||||
{
|
||||
if (empty($key)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// database query, getting all the info of the selected user
|
||||
$query_user = $this->db_connection->prepare('SELECT * FROM ' .
|
||||
PSM_DB_PREFIX . 'users WHERE api_hash = :api_hash');
|
||||
$query_user->bindValue(':api_hash', $key, \PDO::PARAM_STR);
|
||||
$query_user->execute();
|
||||
// get result row (as an object)
|
||||
return $query_user->fetchObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs in with SESSION data.
|
||||
*
|
||||
|
@ -179,6 +198,28 @@ class User
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs in via the api key
|
||||
* @return bool success state of cookie login
|
||||
*/
|
||||
public function loginWithApiKey($key)
|
||||
{
|
||||
$apiKey = trim($key);
|
||||
|
||||
if (empty($apiKey)) {
|
||||
return false;
|
||||
}
|
||||
$user = $this->getUserByApiKey($apiKey);
|
||||
|
||||
if (empty($user)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->setUserLoggedIn($user->user_id, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs in via the Cookie
|
||||
* @return bool success state of cookie login
|
||||
|
|
|
@ -200,6 +200,7 @@ class Installer
|
|||
`password_reset_hash` char(40) DEFAULT NULL COMMENT 'user''s password reset code',
|
||||
`password_reset_timestamp` bigint(20) DEFAULT NULL COMMENT 'timestamp of the password reset request',
|
||||
`rememberme_token` varchar(64) DEFAULT NULL COMMENT 'user''s remember-me cookie token',
|
||||
`api_hash` varchar(255) DEFAULT NULL COMMENT 'user''s hash key to validate API requests',
|
||||
`level` tinyint(2) unsigned NOT NULL DEFAULT '20',
|
||||
`name` varchar(255) NOT NULL,
|
||||
`mobile` varchar(15) NOT NULL,
|
||||
|
|
|
@ -263,30 +263,22 @@ class StatusUpdater
|
|||
$this->server['request_method'],
|
||||
$this->server['post_field']
|
||||
);
|
||||
$this->header = $curl_result;
|
||||
|
||||
$this->header = $curl_result["result"];
|
||||
$code = $curl_result["info"]["http_code"];
|
||||
$redirectUrl = $curl_result["info"]["redirect_url"];
|
||||
|
||||
$this->rtime = (microtime(true) - $starttime);
|
||||
|
||||
// the first line would be the status code..
|
||||
$status_code = strtok($curl_result, "\r\n");
|
||||
// keep it general
|
||||
// $code[2][0] = status code
|
||||
// $code[3][0] = name of status code
|
||||
$code_matches = array();
|
||||
preg_match_all("/[A-Z]{2,5}\/\d(\.\d)?\s(\d{3})\s?(.*)/", $status_code, $code_matches);
|
||||
|
||||
if (empty($code_matches[0])) {
|
||||
|
||||
if (empty($code)) {
|
||||
// somehow we dont have a proper response.
|
||||
$this->error = 'TIMEOUT ERROR: no response from server';
|
||||
$result = false;
|
||||
} else {
|
||||
$code = $code_matches[2][0];
|
||||
$msg = $code_matches[3][0];
|
||||
|
||||
$allow_http_status = explode("|", $this->server['allow_http_status']);
|
||||
// All status codes starting with a 4 or higher mean trouble!
|
||||
if (substr($code, 0, 1) >= '4' && !in_array($code, $allow_http_status)) {
|
||||
$this->error = "HTTP STATUS ERROR: " . $code . ' ' . $msg;
|
||||
$this->error = "HTTP STATUS ERROR: " . $code;
|
||||
$result = false;
|
||||
} else {
|
||||
$result = true;
|
||||
|
@ -299,7 +291,7 @@ class StatusUpdater
|
|||
($this->server['pattern_online'] == 'yes') ==
|
||||
!preg_match(
|
||||
"/{$this->server['pattern']}/i",
|
||||
$curl_result
|
||||
$this->header
|
||||
)
|
||||
) {
|
||||
$this->error = "TEXT ERROR : Pattern '{$this->server['pattern']}' " .
|
||||
|
@ -311,20 +303,11 @@ class StatusUpdater
|
|||
|
||||
// Check if the website redirects to another domain
|
||||
if ($this->server['redirect_check'] == 'bad') {
|
||||
$location_matches = array();
|
||||
preg_match(
|
||||
'/([Ll]ocation: )(https*:\/\/)(www.)?([a-zA-Z.:0-9]*)([\/][[:alnum:][:punct:]]*)/',
|
||||
$curl_result,
|
||||
$location_matches
|
||||
);
|
||||
if (!empty($location_matches)) {
|
||||
$ip_matches = array();
|
||||
preg_match(
|
||||
'/(https*:\/\/)(www.)?([a-zA-Z.:0-9]*)([\/][[:alnum:][:punct:]]*)?/',
|
||||
$this->server['ip'],
|
||||
$ip_matches
|
||||
);
|
||||
if (strtolower($location_matches[4]) !== strtolower($ip_matches[3])) {
|
||||
if (!empty($redirectUrl)) {
|
||||
$redirectPieces = parse_url($redirectUrl);
|
||||
$ipPieces = parse_url($this->server['ip']);
|
||||
|
||||
if (strtolower($redirectPieces['host']) !== strtolower($ipPieces['host'])) {
|
||||
$this->error = "The IP/URL redirects to another domain.";
|
||||
$result = false;
|
||||
}
|
||||
|
@ -335,7 +318,7 @@ class StatusUpdater
|
|||
if ($this->server['header_name'] != '' && $this->server['header_value'] != '') {
|
||||
$header_flag = false;
|
||||
// Only get the header text if the result also includes the body
|
||||
$header_text = substr($curl_result, 0, strpos($curl_result, "\r\n\r\n"));
|
||||
$header_text = substr($this->header, 0, strpos($this->header, "\r\n\r\n"));
|
||||
foreach (explode("\r\n", $header_text) as $i => $line) {
|
||||
if ($i === 0 || strpos($line, ':') == false) {
|
||||
continue; // We skip the status code & other non-header lines. Needed for proxy or redirects
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
{{ macro.input_field("password", "password", null, "password", label_password, edit_value_password, placeholder_password, "255") }}
|
||||
<!-- Password repeat -->
|
||||
{{ macro.input_field("password", "password_repeat", null, "password_repeat", label_password_repeat, edit_value_password_repeat, placeholder_password, "255") }}
|
||||
<!-- API authentication hash -->
|
||||
{{ macro.input_field("text", "api_hash", null, "api_hash", label_api_hash, edit_value_api_hash, placeholder_api_hash, "255") }}
|
||||
<!-- Email -->
|
||||
{{ macro.input_field("email", "email", null, "email", label_email, edit_value_email, null, "255") }}
|
||||
<!-- Mobile -->
|
||||
|
|
Loading…
Reference in New Issue