From 541ea0002f84fef515b68e0b0234b1461a68bfc2 Mon Sep 17 00:00:00 2001 From: GamerClassN7 Date: Mon, 5 Apr 2021 10:43:30 +0200 Subject: [PATCH] Simple Home (Google Oauth 2.0) Flow type - code --- .htaccess | 3 +- app/Bootstrap.php | 2 + app/Routes.php | 8 +- app/api/EndpointsApi.php | 112 +++++++++++++++++++---- app/api/WidgetApi.php | 25 +++++ app/controllers/oauthController.php | 29 ++++-- app/models/managers/SubDeviceManager.php | 16 +++- app/views/Oauth.php | 74 +++++++++++++-- app/views/templates/oauth.phtml | 1 + library/Template.php | 10 +- public/.htaccess | 2 +- public/index.php | 1 + test.php | 2 + 13 files changed, 243 insertions(+), 42 deletions(-) create mode 100644 test.php diff --git a/.htaccess b/.htaccess index 289a0f5..d4152d0 100644 --- a/.htaccess +++ b/.htaccess @@ -17,6 +17,7 @@ RewriteCond %{REQUEST_FILENAME} \. RewriteRule (.*) ./public/$1 [L] # serve all other request as query parameters -RewriteRule (.*) ./public/index.php?url=$1 [L,QSA] +# RewriteRule (.*) ./public/index.php?url=$1 [L,QSA] +RewriteRule ^(.*?\.php)/([^/]*)/([^/]*)(/.+)? ./public/index.php?url=$1&$2&$3 [NC,N,QSA] AddType application/x-httpd-php .php .phtml diff --git a/app/Bootstrap.php b/app/Bootstrap.php index eb4e007..0acbba0 100644 --- a/app/Bootstrap.php +++ b/app/Bootstrap.php @@ -3,6 +3,8 @@ error_reporting(E_ALL); ini_set( 'display_errors','1'); + + //setup parse_str($_SERVER['QUERY_STRING'], $params); if (defined ("BASEDIR")) { diff --git a/app/Routes.php b/app/Routes.php index 9430f50..a872904 100644 --- a/app/Routes.php +++ b/app/Routes.php @@ -10,6 +10,7 @@ $router->setDefault(function(){ unset($logManager); }); + //Pages $router->any('/', 'Log'); $router->any('/log', 'Log'); @@ -46,6 +47,7 @@ $router->get('/api/server/log', 'ServerApi@logStatus'); $router->post('/api/widgets/{widgetId}/run', 'WidgetApi@run'); $router->get('/api/widgets/{widgetId}/detail', 'WidgetApi@detail'); $router->get('/api/widgets/{widgetId}/detail/{period}', 'WidgetApi@detail'); +$router->post('/api/widgets/{widgetId}/edit', 'WidgetApi@edit'); //Vue APP - Automations Endpoints $router->get('/api/automations', 'AutomationsApi@default'); @@ -61,7 +63,8 @@ $router->post('/cron/automations', 'CronApi@automations'); //Google Home - API -$router->any('/api/HA/auth', 'Oauth'); +$router->any('/api/HA/auth', 'Oauth@default'); +$router->any('/api/HA/token', 'Oauth@token'); $router->any('/api/HA', 'GoogleHomeApi@response'); @@ -71,6 +74,9 @@ $router->any('/api/update/', 'UpdatesApi@default'); $router->any('/api/users/status', 'UsersApi@status'); $router->any('/api/users/subscribe', 'UsersApi@subscribe'); +//Endpoints API - V2 +$router->post('/api/v2/endpoint/', 'EndpointsApi@default_v2'); +$router->post('/api/v2/endpoint/cofiguration', 'EndpointsApi@cofiguration_v2'); // examples $router->any('/api/example', 'ExampleApi@example'); diff --git a/app/api/EndpointsApi.php b/app/api/EndpointsApi.php index a062f74..cb0caca 100644 --- a/app/api/EndpointsApi.php +++ b/app/api/EndpointsApi.php @@ -1,6 +1,8 @@ requireAuth(); $obj = $this->input; @@ -8,7 +10,7 @@ class EndpointsApi extends ApiController{ $command = "null"; //Log - $logManager = new LogManager('../logs/api/'. date("Y-m-d").'.log'); + $logManager = new LogManager('../logs/api/' . date("Y-m-d") . '.log'); $logManager->setLevel(LOGLEVEL); //Token Checks @@ -65,7 +67,7 @@ class EndpointsApi extends ApiController{ DeviceManager::setHeartbeat($device['device_id']); //Diagnostic - if (isset($obj['settings'])){ + if (isset($obj['settings'])) { $data = ['mac' => $obj['settings']["network"]["mac"], 'ip_address' => $obj['settings']["network"]["ip"]]; if (array_key_exists("firmware_hash", $obj['settings'])) { $data['firmware_hash'] = $obj['settings']["firmware_hash"]; @@ -74,11 +76,11 @@ class EndpointsApi extends ApiController{ } //Log Data Save - if (isset($obj['logs'])){ + if (isset($obj['logs'])) { foreach ($obj['logs'] as $log) { - $deviceLogManager = new LogManager('../logs/devices/'. date("Y-m-d").'.log'); + $deviceLogManager = new LogManager('../logs/devices/' . date("Y-m-d") . '.log'); $deviceLogManager->setLevel(LOGLEVEL); - if ($log != 'HTTP_UPDATE_FAILD code-102 messageFile Not Found (404)'){ + if ($log != 'HTTP_UPDATE_FAILD code-102 messageFile Not Found (404)') { $deviceLogManager->write("[Device Log Msg] Device_ID " . $device['device_id'] . "->" . $log, LogRecordTypes::ERROR); } unset($deviceLogManager); @@ -91,13 +93,12 @@ class EndpointsApi extends ApiController{ } // Issuing command - if ($command == "null"){ + if ($command == "null") { $deviceCommand = $device["command"]; - if ($deviceCommand != '' && $deviceCommand != null && $deviceCommand != "null") - { + if ($deviceCommand != '' && $deviceCommand != null && $deviceCommand != "null") { $command = $deviceCommand; $data = [ - 'command'=>'null' + 'command' => 'null' ]; DeviceManager::editByToken($obj['token'], $data); $logManager->write("[API] Device_ID " . $device['device_id'] . " executing command " . $command, LogRecordTypes::INFO); @@ -115,7 +116,7 @@ class EndpointsApi extends ApiController{ } $subDeviceLastReordValue[$key] = $value['value']; - RecordManager::create($device['device_id'], $key, round($value['value'],3), 'device'); + RecordManager::create($device['device_id'], $key, round($value['value'], 3), 'device'); $logManager->write("[API] Device_ID " . $device['device_id'] . " writed value " . $key . ' ' . $value['value'], LogRecordTypes::INFO); //notification @@ -127,20 +128,20 @@ class EndpointsApi extends ApiController{ case 'door': $notificationData = [ 'title' => 'Info', - 'body' => 'Someone just open up '.$device['name'], + 'body' => 'Someone just open up ' . $device['name'], 'icon' => BASEDIR . '/app/templates/images/icon-192x192.png', ]; - break; + break; case 'water': $notificationData = [ 'title' => 'Alert', - 'body' => 'Wather leak detected by '.$device['name'], + 'body' => 'Wather leak detected by ' . $device['name'], 'icon' => BASEDIR . '/app/templates/images/icon-192x192.png', ]; - break; + break; } - if (DEBUGMOD) $notificationData['body'] .= ' value='.$value['value']; + if (DEBUGMOD) $notificationData['body'] .= ' value=' . $value['value']; if ($notificationData != []) { $subscribers = $notificationMng::getSubscription(); foreach ($subscribers as $key => $subscriber) { @@ -169,9 +170,9 @@ class EndpointsApi extends ApiController{ foreach ($subDevicesData as $key => $subDeviceData) { $subDeviceId = $subDeviceData['subdevice_id']; $subDeviceLastReord = RecordManager::getLastRecord($subDeviceId); - if (!empty ($subDeviceLastReord)) { + if (!empty($subDeviceLastReord)) { $subDeviceLastReordValue[$subDeviceData['type']] = $subDeviceLastReord['value']; - if ($subDeviceLastReord['execuded'] == 0){ + if ($subDeviceLastReord['execuded'] == 0) { $logManager->write("[API] subDevice_ID " . $subDeviceId . " executed comand with value " . json_encode($subDeviceLastReordValue) . " executed " . $subDeviceLastReord['execuded'], LogRecordTypes::INFO); RecordManager::setExecuted($subDeviceLastReord['record_id']); } @@ -193,4 +194,77 @@ class EndpointsApi extends ApiController{ //unset($logManager); //TODO: Opravit die(); } + + protected function requireAuth() + { + if (isset($_SERVER['HTTP_AUTHORIZATION'])) { + // TODO: call appropriate class/method + $deviceManager = new DeviceManager(); + list($type, $hash) = explode(' ', $_SERVER['HTTP_AUTHORIZATION']); + $this->authenticated = $deviceManager->approved($hash); + return $hash; + if (!$this->authenticated) { + throw new Exception("Authorization required", 401); + } + } else { + throw new Exception("Authorization required", 401); + } + } + + public function default_v2() + { + $token = $this->requireAuth(); + $obj = $this->input; + $response = []; + + $device = DeviceManager::getDeviceByToken($token); + DeviceManager::setHeartbeat($device['device_id']); + + // Issue command + $deviceCommand = $device["command"]; + if ($deviceCommand != '' && $deviceCommand != null && $deviceCommand != "null") { + $response['command'] = $deviceCommand; + DeviceManager::editByToken($obj['token'], ['command' => 'null']); + } + + $subDevicesData = SubDeviceManager::getAllSubDevices($device['device_id']); + if (count($subDevicesData) > 0) { + foreach ($subDevicesData as $key => $subDeviceData) { + $subDeviceId = $subDeviceData['subdevice_id']; + $subDeviceLastReord = RecordManager::getLastRecord($subDeviceId); + if (!empty($subDeviceLastReord)) { + $response['values'][$subDeviceData['type']] = $subDeviceLastReord['value']; + if ($subDeviceLastReord['execuded'] == 0) { + RecordManager::setExecuted($subDeviceLastReord['record_id']); + } + } + } + } + + $this->response($response, 200); + } + + public function cofiguration_v2() + { + $token = $this->requireAuth(); + $response = []; + + $device = DeviceManager::getDeviceByToken($token); + DeviceManager::setHeartbeat($device['device_id']); + + if (!empty($device["name"]) && isset($device["name"])) $response["nettwork"]['hostname'] = $this->nameToHostname($device["name"]); + if (!empty($device["ip_address"]) && isset($device["ip_address"])) $response["nettwork"]['ip'] = $device["ip_address"]; + if (!empty($device["gateway"]) && isset($device["gateway"])) $response["nettwork"]['gateway'] = $device["gateway"]; + if (!empty($device["dns"]) && isset($device["dns"])) $response["nettwork"]['dns'] = $device["dns"]; + if (!empty($device["sleep_time"]) && isset($device["sleep_time"])) $response["sleep"] = $device["sleep_time"]; + + $this->response($response, 200); + } + + private function nameToHostname(string $name = null) + { + $hostname = ""; + $hostname = strtolower($name); + return str_replace(' ', '_', $hostname); + } } diff --git a/app/api/WidgetApi.php b/app/api/WidgetApi.php index 7c94d68..46152fe 100644 --- a/app/api/WidgetApi.php +++ b/app/api/WidgetApi.php @@ -134,4 +134,29 @@ class WidgetApi extends ApiController } return RANGES['']; } + + public function edit($subDeviceId) + { + $this->requireAuth(); + $allow = ["icon", "name"]; + + $response = null; + $obj = $this->input; + + foreach ($obj as $key => $value) { + if (!in_array($key, $allow)){ + unset($obj[$key]); + } + } + + $subDeviceData = SubDeviceManager::edit($subDeviceId, $obj); + + $response = [ + "value" => "OK" + ]; + + $this->response($response); + } + + } diff --git a/app/controllers/oauthController.php b/app/controllers/oauthController.php index 16f33bd..1af81b6 100644 --- a/app/controllers/oauthController.php +++ b/app/controllers/oauthController.php @@ -14,19 +14,34 @@ if ( $state = $_POST["state"]; $clientId = $_POST["clientId"]; $ota = $userManager->haveOtaEnabled($userName); + if ($ota == "") { $token = (new AuthManager)->getToken($userName,$userPassword, $clientId); if (!$token) { throw new Exception("Auth failed", 401); } - $get = [ - "access_token"=>$token, - "token_type"=>"Bearer", - "state"=>$state, - ]; - - header('Location: ' . $_POST["redirectUrl"] . '#' . http_build_query($get)); + $get=[]; + if ($_POST['response_type'] = 'code') { + $get = [ + "state"=>$state, + "code"=>$token, + "access_token"=>$token, + "state"=>$state, + ]; + } else { + $get = [ + "access_token"=>$token, + "token_type"=>"Bearer", + "state"=>$state, + ]; + } + + //Log + $logManager = new LogManager(__DIR__ . '/../../logs/auth/' . date("Y-m-d") . '.log'); + $logManager->setLevel(LOGLEVEL); + $logManager->write("[OAUTH] Response " . $_POST["redirectUrl"] . '?' . http_build_query($get), LogRecordTypes::WARNING); + header('Location: ' . $_POST["redirectUrl"] . '?' . http_build_query($get)); die(); } diff --git a/app/models/managers/SubDeviceManager.php b/app/models/managers/SubDeviceManager.php index 6e37cdd..d67b8ef 100644 --- a/app/models/managers/SubDeviceManager.php +++ b/app/models/managers/SubDeviceManager.php @@ -66,6 +66,20 @@ class SubDeviceManager } } + public static function edit($subDeviceId, $values) + { + $record = []; + foreach ($values as $key => $value) { + $record[$key] = $value; + } + try { + Db::edit('subdevices', $record, 'WHERE subdevice_id = ?', array ($subDeviceId)); + } catch (PDOException $error) { + echo $error->getMessage(); + die(); + } + } + public static function remove($subDeviceId) { RecordManager::cleanSubdeviceRecords($subDeviceId); @@ -78,7 +92,7 @@ class SubDeviceManager //TODO: @Patrik Check line 89 $rows = Db::loadAll(" - SELECT d.room_id, d.sleep_time, sd.subdevice_id, sd.device_id, d.icon, d.name, sd.type, sd.unit, r.value, r.time FROM subdevices sd + SELECT d.room_id, d.sleep_time, sd.subdevice_id, sd.device_id, COALESCE(sd.icon, d.icon) AS icon, COALESCE(sd.name, d.name) AS name, sd.type, sd.unit, r.value, r.time FROM subdevices sd JOIN devices d ON sd.device_id = d.device_id JOIN records r ON r.subdevice_id = sd.subdevice_id WHERE d.room_id IN (" . str_repeat("?,", count($roomIds) - 1) . "?) diff --git a/app/views/Oauth.php b/app/views/Oauth.php index a4a0d8a..834a3c2 100644 --- a/app/views/Oauth.php +++ b/app/views/Oauth.php @@ -1,9 +1,19 @@ setLevel(LOGLEVEL); + $logManager->write("[OAUTH] GET " . json_encode($_GET), LogRecordTypes::WARNING); + $logManager->write("[OAUTH] DATA " . file_get_contents('php://input'), LogRecordTypes::WARNING); + $logManager->write("[OAUTH] URL " . $_SERVER['REQUEST_URI'], LogRecordTypes::WARNING); + + $userManager = new UserManager(); $langMng = new LanguageManager('en'); $template = new Template('oauth'); @@ -11,18 +21,66 @@ class Oauth extends Template $template->prepare('baseUrl', BASEURL); $template->prepare('title', 'Simple Home - Oauth'); - if (isset($_GET['redirect_uri'])) { + if (isset($_GET['response_type']) && $_GET['response_type'] == 'code') { $template->prepare('responseType', $_GET['response_type']); $template->prepare('redirectUrl', $_GET['redirect_uri']); $template->prepare('clientId', $_GET['client_id']); + $template->prepare('scope', $_GET['scope']); $template->prepare('state', $_GET['state']); } else { - $template->prepare('responseType', $_POST['responseType']); - $template->prepare('redirectUrl', $_POST['redirectUrl']); - $template->prepare('clientId', $_POST['clientId']); - $template->prepare('state', $_POST['state']); + if (isset($_GET['redirect_uri'])) { + $template->prepare('responseType', $_GET['response_type']); + $template->prepare('redirectUrl', $_GET['redirect_uri']); + $template->prepare('clientId', $_GET['client_id']); + $template->prepare('state', $_GET['state']); + } else { + $template->prepare('responseType', $_POST['responseType']); + $template->prepare('redirectUrl', $_POST['redirectUrl']); + $template->prepare('clientId', $_POST['clientId']); + $template->prepare('state', $_POST['state']); + } } $template->render(); } + + function token() + { + //Log + $logManager = new LogManager(__DIR__ . '/../../logs/auth/' . date("Y-m-d") . '.log'); + $logManager->setLevel(LOGLEVEL); + $logManager->write("[OAUTH] GET " . json_encode($_GET), LogRecordTypes::WARNING); + $logManager->write("[OAUTH] POST " . json_encode($_POST), LogRecordTypes::WARNING); + $logManager->write("[OAUTH] DATA " . file_get_contents('php://input'), LogRecordTypes::WARNING); + $logManager->write("[OAUTH] URL " . $_SERVER['REQUEST_URI'], LogRecordTypes::WARNING); + + // $template = new Template('oauth'); + // $template->prepare('baseDir', BASEDIR); + // $template->prepare('baseUrl', BASEURL); + // $template->prepare('title', 'Simple Home - Oauth'); + // $template->render(); + + $token = $_POST["code"]; + $get = [ + "access_token" => $token, + "token_type" => "bearer", + "refresh_token" => $token, + "scope" => 'user', + ]; + + $logManager->write("[OAUTH] Response " . json_encode($get), LogRecordTypes::WARNING); + echo json_encode($get); + die(); + } + + function httpPost($url, $data) + { + $curl = curl_init($url); + curl_setopt($curl, CURLOPT_POST, true); + curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data)); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + $response = curl_exec($curl); + curl_close($curl); + return $response; + } } diff --git a/app/views/templates/oauth.phtml b/app/views/templates/oauth.phtml index cc1e7f4..36ea8f5 100644 --- a/app/views/templates/oauth.phtml +++ b/app/views/templates/oauth.phtml @@ -4,6 +4,7 @@ prepare('baseDir',$BASEDIR); + $partial->prepare('baseUrl',$BASEURL); $partial->render(); ?> <?php echo $TITLE ?> diff --git a/library/Template.php b/library/Template.php index 65ce1c0..08af1a6 100644 --- a/library/Template.php +++ b/library/Template.php @@ -7,10 +7,12 @@ class Template{ function __construct($path = "", $debug = false) { $this->debug = $debug; - if (!empty('../app/views/templates/' . $path . '.phtml') && file_exists('../app/views/templates/' . $path . '.phtml')) { + + if (!empty(__DIR__ . '/../app/views/templates/' . $path . '.phtml') && file_exists(__DIR__ . '/../app/views/templates/' . $path . '.phtml')) { $this->path = $path; } else { echo '
';
+			echo __DIR__ . '/../app/views/templates/' . $path . '.phtml
'; echo 'PHTML: Template File ' . $path . ' not found'; echo '
'; die(); @@ -26,9 +28,9 @@ class Template{ function render() { extract($this->assignedValues); - if (!empty('../app/controllers/' . $this->path . 'Controller.php') && file_exists('../app/controllers/' . $this->path . 'Controller.php')) { - include('../app/controllers/' . $this->path . 'Controller.php'); + if (!empty(__DIR__ . '/../app/controllers/' . $this->path . 'Controller.php') && file_exists(__DIR__ . '/../app/controllers/' . $this->path . 'Controller.php')) { + include(__DIR__ . '/../app/controllers/' . $this->path . 'Controller.php'); } - require_once('../app/views/templates/' . $this->path . '.phtml'); + require_once(__DIR__ . '/../app/views/templates/' . $this->path . '.phtml'); } } diff --git a/public/.htaccess b/public/.htaccess index da6c340..b180865 100644 --- a/public/.htaccess +++ b/public/.htaccess @@ -5,7 +5,7 @@ RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !.css RewriteCond %{REQUEST_FILENAME} !.js -RewriteRule (.*) ./index.php?url=$1#$2 [QSA,L] +RewriteRule (.*) ./index.php?url=$1 [QSA,L] #token to HTTP_AUTHORIZATION RewriteCond %{HTTP:Authorization} ^(.*) diff --git a/public/index.php b/public/index.php index 71d1710..df4cf6f 100644 --- a/public/index.php +++ b/public/index.php @@ -1,3 +1,4 @@