Proper Oauth for Google Home
This commit is contained in:
parent
1af11f3f58
commit
fef3c1e57f
@ -13,6 +13,7 @@ $router->any('/logout', 'Logout');
|
||||
$router->any('/automation', 'Automation');
|
||||
$router->any('/setting', 'Setting');
|
||||
$router->any('/ajax', 'Ajax');
|
||||
$router->any('/oauth', 'Oauth');
|
||||
|
||||
$router->post('/api/login', 'AuthApi@login');
|
||||
$router->post('/api/logout', 'AuthApi@logout');
|
||||
@ -20,7 +21,7 @@ $router->post('/api/logout', 'AuthApi@logout');
|
||||
$router->get('/api/devices', 'DevicesApi@default');
|
||||
$router->get('/api/rooms', 'RoomsApi@default');
|
||||
|
||||
$router->get('/api/HA/auth', 'GoogleHomeApi@autorize');
|
||||
$router->any('/api/HA/auth', 'Oauth');
|
||||
$router->any('/api/HA', 'GoogleHomeApi@response');
|
||||
|
||||
// examples
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
class GoogleHomeApi {
|
||||
class GoogleHomeApi{
|
||||
static function response(){
|
||||
|
||||
//$this->requireAuth();
|
||||
$json = file_get_contents('php://input');
|
||||
$obj = json_decode($json, true);
|
||||
|
||||
|
26
app/api/RecordApi.php
Normal file
26
app/api/RecordApi.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
class RecordApi extends ApiController{
|
||||
|
||||
public function default(){
|
||||
//$this->requireAuth();
|
||||
$response = [];
|
||||
$roomIds = [];
|
||||
$roomsData = RoomManager::getRoomsDefault();
|
||||
|
||||
foreach ($roomsData as $roomKey => $room) {
|
||||
$roomIds[] = $room['room_id'];
|
||||
}
|
||||
|
||||
$subDevicesData = SubDeviceManager::getSubdevicesByRoomIds($roomIds);
|
||||
|
||||
foreach ($roomsData as $roomKey => $roomData) {
|
||||
$response[] = [
|
||||
'room_id' => $roomData['room_id'],
|
||||
'name' => $roomData['name'],
|
||||
'widgets' => isset($subDevicesData[$roomData['room_id']]) ? $subDevicesData[$roomData['room_id']] : [],
|
||||
];
|
||||
}
|
||||
$this->response($response);
|
||||
}
|
||||
}
|
75
app/controllers/oauthController.php
Normal file
75
app/controllers/oauthController.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
global $userManager;
|
||||
|
||||
|
||||
if (
|
||||
isset($_POST['username']) &&
|
||||
$_POST['username'] != '' &&
|
||||
isset($_POST['password']) &&
|
||||
$_POST['password'] != ''
|
||||
){
|
||||
$ota = false;
|
||||
$userName = $_POST['username'];
|
||||
$userPassword = $_POST['password'];
|
||||
$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));
|
||||
die();
|
||||
}
|
||||
|
||||
$_SESSION['USERNAME'] = $userName;
|
||||
$_SESSION['PASSWORD'] = $userPassword;
|
||||
$_SESSION['OTA'] = $ota;
|
||||
$_SESSION['STATE'] = $state;
|
||||
$_SESSION['REDIRECT'] = $_POST["redirectUrl"];
|
||||
$_SESSION['CLIENT'] = $clientId;
|
||||
|
||||
|
||||
} else if (
|
||||
isset($_POST['otaCode']) &&
|
||||
$_POST['otaCode'] != ''
|
||||
) {
|
||||
$otaCode = $_POST['otaCode'];
|
||||
$otaSecret = $_POST['otaSecret'];
|
||||
|
||||
$userName = $_SESSION['USERNAME'];
|
||||
$userPassword = $_SESSION['PASSWORD'];
|
||||
$ota = $_SESSION['OTA'];
|
||||
$oauthState = $_SESSION['STATE'];
|
||||
$oauthRedirect = $_SESSION['REDIRECT'];
|
||||
$oauthClientId = $_SESSION['CLIENT'];
|
||||
|
||||
$ga = new PHPGangsta_GoogleAuthenticator();
|
||||
$checkResult = $ga->verifyCode($otaSecret, $otaCode, 2); // 2 = 2*30sec clock tolerance
|
||||
if ($checkResult) {
|
||||
$token = (new AuthManager)->getToken($userName,$userPassword, $oauthClientId);
|
||||
if (!$token) {
|
||||
throw new Exception("Auth failed", 401);
|
||||
}
|
||||
|
||||
$get = [
|
||||
"access_token"=>$token,
|
||||
"token_type"=>"Bearer",
|
||||
"state"=>$oauthState,
|
||||
];
|
||||
|
||||
header('Location: ' . $oauthRedirect . '#' . http_build_query($get));
|
||||
echo 'OK';
|
||||
} else {
|
||||
echo 'FAILED';
|
||||
}
|
||||
die();
|
||||
}
|
@ -14,9 +14,8 @@ if (isset($_POST) && !empty($_POST)){
|
||||
header('Location: ' . BASEURL . 'setting');
|
||||
die();
|
||||
} else if (isset($_POST['submitEnableOta']) && $_POST['submitEnableOta'] != "") {
|
||||
echo $otaCode = $_POST['otaCode'];
|
||||
echo $otaSecret = $_POST['otaSecret'];
|
||||
|
||||
$otaCode = $_POST['otaCode'];
|
||||
$otaSecret = $_POST['otaSecret'];
|
||||
|
||||
$ga = new PHPGangsta_GoogleAuthenticator();
|
||||
$checkResult = $ga->verifyCode($otaSecret, $otaCode, 2); // 2 = 2*30sec clock tolerance
|
||||
|
@ -12,6 +12,11 @@ class GoogleHome {
|
||||
|
||||
//Google Compatibile Action Type
|
||||
$actionType = GoogleHomeDeviceTypes::getAction($subDeviceData['type']);
|
||||
|
||||
if (strpos($deviceData['name'], 'Světlo') !== false || strpos($deviceData['name'], 'světlo') !== false) {
|
||||
$actionType = 'action.devices.types.LIGHT';
|
||||
}
|
||||
|
||||
$tempDevice = [
|
||||
'id' => (string) $subDeviceData['subdevice_id'],
|
||||
'type' => $actionType,
|
||||
@ -78,181 +83,181 @@ class GoogleHome {
|
||||
$deviceId['id'] => [
|
||||
'online' => $online,
|
||||
'status'=> $status,
|
||||
]
|
||||
];
|
||||
]
|
||||
];
|
||||
|
||||
if ($subDeviceData['type'] == "temp_cont"){
|
||||
$tempDevice[$deviceId['id']]['thermostatMode'] = 'off';
|
||||
if (RecordManager::getLastRecord($deviceId['id'])['value'] != 0) {
|
||||
$tempDevice[$deviceId['id']]['thermostatMode'] = 'heat';
|
||||
}
|
||||
if ($subDeviceData['type'] == "temp_cont"){
|
||||
$tempDevice[$deviceId['id']]['thermostatMode'] = 'off';
|
||||
if (RecordManager::getLastRecord($deviceId['id'])['value'] != 0) {
|
||||
$tempDevice[$deviceId['id']]['thermostatMode'] = 'heat';
|
||||
}
|
||||
$tempDevice[$deviceId['id']]['thermostatTemperatureAmbient'] = RecordManager::getLastRecord($deviceId['id'])['value'];
|
||||
$tempDevice[$deviceId['id']]['thermostatTemperatureSetpoint'] = RecordManager::getLastRecord($deviceId['id'])['value'];
|
||||
} else {
|
||||
$tempDevice[$deviceId['id']]['on'] = $state;
|
||||
}
|
||||
$devices = $tempDevice;
|
||||
if (count($devices)> 1){
|
||||
$devices[] = $tempDevice;
|
||||
}
|
||||
}
|
||||
|
||||
$response = [
|
||||
'requestId' => $requestId,
|
||||
'payload' => [
|
||||
'devices' => $devices,
|
||||
],
|
||||
];
|
||||
|
||||
$apiLogManager = new LogManager('../logs/api/HA/'. date("Y-m-d").'.log');
|
||||
$apiLogManager->write("[API][$requestId] request response\n" . json_encode($response, JSON_PRETTY_PRINT), LogRecordType::INFO);
|
||||
echo json_encode($response);
|
||||
}
|
||||
|
||||
static function execute($requestId, $payload){
|
||||
$commands = [];
|
||||
|
||||
foreach ($payload['commands'] as $key => $command) {
|
||||
foreach ($command['devices'] as $key => $device) {
|
||||
$executionCommand = $command['execution'][0];
|
||||
if (isset($command['execution'][$key])) {
|
||||
$executionCommand = $command['execution'][$key];
|
||||
} else {
|
||||
$tempDevice[$deviceId['id']]['on'] = $state;
|
||||
}
|
||||
|
||||
$subDeviceId = $device['id'];
|
||||
|
||||
switch ($executionCommand['command']) {
|
||||
case 'action.devices.commands.OnOff':
|
||||
$commands[] = self::executeSwitch($subDeviceId, $executionCommand);
|
||||
break;
|
||||
|
||||
case 'action.devices.commands.ThermostatTemperatureSetpoint':
|
||||
$commands[] = self::executeTermostatValue($subDeviceId, $executionCommand);
|
||||
break;
|
||||
|
||||
case 'action.devices.commands.ThermostatSetMode':
|
||||
$commands[] = self::executeTermostatMode($subDeviceId, $executionCommand);
|
||||
break;
|
||||
$devices = $tempDevice;
|
||||
if (count($devices)> 1){
|
||||
$devices[] = $tempDevice;
|
||||
}
|
||||
}
|
||||
|
||||
$response = [
|
||||
'requestId' => $requestId,
|
||||
'payload' => [
|
||||
'devices' => $devices,
|
||||
],
|
||||
];
|
||||
|
||||
$apiLogManager = new LogManager('../logs/api/HA/'. date("Y-m-d").'.log');
|
||||
$apiLogManager->write("[API][$requestId] request response\n" . json_encode($response, JSON_PRETTY_PRINT), LogRecordType::INFO);
|
||||
echo json_encode($response);
|
||||
}
|
||||
|
||||
$response = [
|
||||
'requestId' => $requestId,
|
||||
'payload' => [
|
||||
'commands' => $commands,
|
||||
],
|
||||
];
|
||||
$apiLogManager = new LogManager('../logs/api/HA/'. date("Y-m-d").'.log');
|
||||
$apiLogManager->write("[API][EXECUTE][$requestId]\n" . json_encode($response, JSON_PRETTY_PRINT), LogRecordType::INFO);
|
||||
static function execute($requestId, $payload){
|
||||
$commands = [];
|
||||
|
||||
echo json_encode($response);
|
||||
}
|
||||
foreach ($payload['commands'] as $key => $command) {
|
||||
foreach ($command['devices'] as $key => $device) {
|
||||
$executionCommand = $command['execution'][0];
|
||||
if (isset($command['execution'][$key])) {
|
||||
$executionCommand = $command['execution'][$key];
|
||||
}
|
||||
|
||||
static function executeSwitch($subDeviceId, $executionCommand){
|
||||
$value = 0;
|
||||
$status = 'SUCCESS';
|
||||
if ($executionCommand['params']['on']) $value = 1;
|
||||
$subDeviceId = $device['id'];
|
||||
|
||||
RecordManager::createWithSubId($subDeviceId, $value);
|
||||
switch ($executionCommand['command']) {
|
||||
case 'action.devices.commands.OnOff':
|
||||
$commands[] = self::executeSwitch($subDeviceId, $executionCommand);
|
||||
break;
|
||||
|
||||
$executed = 0;
|
||||
$waiting = 0;
|
||||
foreach (RecordManager::getLastRecord($subDeviceId, 4) as $key => $value) {
|
||||
if ($value['execuded'] == 1){
|
||||
$executed++;
|
||||
} else {
|
||||
$waiting++;
|
||||
case 'action.devices.commands.ThermostatTemperatureSetpoint':
|
||||
$commands[] = self::executeTermostatValue($subDeviceId, $executionCommand);
|
||||
break;
|
||||
|
||||
case 'action.devices.commands.ThermostatSetMode':
|
||||
$commands[] = self::executeTermostatMode($subDeviceId, $executionCommand);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($waiting < $executed){
|
||||
$status = "PENDING";
|
||||
} else {
|
||||
$status = "OFFLINE";
|
||||
|
||||
$response = [
|
||||
'requestId' => $requestId,
|
||||
'payload' => [
|
||||
'commands' => $commands,
|
||||
],
|
||||
];
|
||||
$apiLogManager = new LogManager('../logs/api/HA/'. date("Y-m-d").'.log');
|
||||
$apiLogManager->write("[API][EXECUTE][$requestId]\n" . json_encode($response, JSON_PRETTY_PRINT), LogRecordType::INFO);
|
||||
|
||||
echo json_encode($response);
|
||||
}
|
||||
|
||||
$commandTemp = [
|
||||
'ids' => [$subDeviceId],
|
||||
'status' => $status,
|
||||
'states' => [
|
||||
'on' => $executionCommand['params']['on'],
|
||||
],
|
||||
];
|
||||
return $commandTemp;
|
||||
}
|
||||
static function executeSwitch($subDeviceId, $executionCommand){
|
||||
$value = 0;
|
||||
$status = 'SUCCESS';
|
||||
if ($executionCommand['params']['on']) $value = 1;
|
||||
|
||||
static function executeTermostatValue($subDeviceId, $executionCommand){
|
||||
$value = 0;
|
||||
$status = 'SUCCESS';
|
||||
RecordManager::createWithSubId($subDeviceId, $value);
|
||||
|
||||
if (isset($executionCommand['params']['thermostatTemperatureSetpoint'])) {
|
||||
$value = $executionCommand['params']['thermostatTemperatureSetpoint'];
|
||||
}
|
||||
|
||||
RecordManager::createWithSubId($subDeviceId, $value);
|
||||
|
||||
$executed = 0;
|
||||
$waiting = 0;
|
||||
foreach (RecordManager::getLastRecord($subDeviceId, 4) as $key => $lastValue) {
|
||||
if ($lastValue['execuded'] == 1){
|
||||
$executed++;
|
||||
} else {
|
||||
$waiting++;
|
||||
$executed = 0;
|
||||
$waiting = 0;
|
||||
foreach (RecordManager::getLastRecord($subDeviceId, 4) as $key => $value) {
|
||||
if ($value['execuded'] == 1){
|
||||
$executed++;
|
||||
} else {
|
||||
$waiting++;
|
||||
}
|
||||
}
|
||||
if ($waiting < $executed){
|
||||
$status = "PENDING";
|
||||
} else {
|
||||
$status = "OFFLINE";
|
||||
}
|
||||
|
||||
$commandTemp = [
|
||||
'ids' => [$subDeviceId],
|
||||
'status' => $status,
|
||||
'states' => [
|
||||
'on' => $executionCommand['params']['on'],
|
||||
],
|
||||
];
|
||||
return $commandTemp;
|
||||
}
|
||||
if ($waiting < $executed){
|
||||
$status = "PENDING";
|
||||
|
||||
static function executeTermostatValue($subDeviceId, $executionCommand){
|
||||
$value = 0;
|
||||
$status = 'SUCCESS';
|
||||
|
||||
if (isset($executionCommand['params']['thermostatTemperatureSetpoint'])) {
|
||||
$value = $executionCommand['params']['thermostatTemperatureSetpoint'];
|
||||
}
|
||||
|
||||
RecordManager::createWithSubId($subDeviceId, $value);
|
||||
|
||||
$executed = 0;
|
||||
$waiting = 0;
|
||||
foreach (RecordManager::getLastRecord($subDeviceId, 4) as $key => $lastValue) {
|
||||
if ($lastValue['execuded'] == 1){
|
||||
$executed++;
|
||||
} else {
|
||||
$waiting++;
|
||||
}
|
||||
}
|
||||
if ($waiting < $executed){
|
||||
$status = "PENDING";
|
||||
$status = "SUCCESS";
|
||||
} else {
|
||||
$status = "OFFLINE";
|
||||
}
|
||||
|
||||
$commandTemp = [
|
||||
'ids' => [$subDeviceId],
|
||||
'status' => $status,
|
||||
'states' => [
|
||||
'thermostatMode' => 'heat',
|
||||
'thermostatTemperatureSetpoint' => $value,
|
||||
'thermostatTemperatureAmbient' => $value,
|
||||
//ambient z dalšího zenzoru v roomu
|
||||
],
|
||||
];
|
||||
return $commandTemp;
|
||||
}
|
||||
|
||||
static function executeTermostatMode($subDeviceId, $executionCommand){
|
||||
$mode = "off";
|
||||
$value = 0;
|
||||
$status = "SUCCESS";
|
||||
} else {
|
||||
$status = "OFFLINE";
|
||||
}
|
||||
|
||||
$commandTemp = [
|
||||
'ids' => [$subDeviceId],
|
||||
'status' => $status,
|
||||
'states' => [
|
||||
'thermostatMode' => 'heat',
|
||||
'thermostatTemperatureSetpoint' => $value,
|
||||
'thermostatTemperatureAmbient' => $value,
|
||||
//ambient z dalšího zenzoru v roomu
|
||||
],
|
||||
];
|
||||
return $commandTemp;
|
||||
}
|
||||
|
||||
static function executeTermostatMode($subDeviceId, $executionCommand){
|
||||
$mode = "off";
|
||||
$value = 0;
|
||||
$status = "SUCCESS";
|
||||
|
||||
if (isset($executionCommand['params']['thermostatMode']) && $executionCommand['params']['thermostatMode'] != 'off') {
|
||||
$mode = $executionCommand['params']['thermostatMode'];
|
||||
$value = RecordManager::getLastRecordNotNull($subDeviceId)['value'];
|
||||
}
|
||||
|
||||
RecordManager::createWithSubId($subDeviceId, $value);
|
||||
|
||||
$executed = 0;
|
||||
$waiting = 0;
|
||||
foreach (RecordManager::getLastRecord($subDeviceId, 4) as $key => $value) {
|
||||
if ($value['execuded'] == 1){
|
||||
$executed++;
|
||||
} else {
|
||||
$waiting++;
|
||||
if (isset($executionCommand['params']['thermostatMode']) && $executionCommand['params']['thermostatMode'] != 'off') {
|
||||
$mode = $executionCommand['params']['thermostatMode'];
|
||||
$value = RecordManager::getLastRecordNotNull($subDeviceId)['value'];
|
||||
}
|
||||
}
|
||||
if ($waiting < $executed){
|
||||
$status = "PENDING";
|
||||
}
|
||||
|
||||
$commandTemp = [
|
||||
'ids' => [$subDeviceId],
|
||||
'status' => $status,
|
||||
'states' => [
|
||||
'thermostatMode' => $mode
|
||||
],
|
||||
];
|
||||
RecordManager::createWithSubId($subDeviceId, $value);
|
||||
|
||||
return $commandTemp;
|
||||
$executed = 0;
|
||||
$waiting = 0;
|
||||
foreach (RecordManager::getLastRecord($subDeviceId, 4) as $key => $value) {
|
||||
if ($value['execuded'] == 1){
|
||||
$executed++;
|
||||
} else {
|
||||
$waiting++;
|
||||
}
|
||||
}
|
||||
if ($waiting < $executed){
|
||||
$status = "PENDING";
|
||||
}
|
||||
|
||||
$commandTemp = [
|
||||
'ids' => [$subDeviceId],
|
||||
'status' => $status,
|
||||
'states' => [
|
||||
'thermostatMode' => $mode
|
||||
],
|
||||
];
|
||||
|
||||
return $commandTemp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
<?php
|
||||
|
||||
class AuthManager {
|
||||
public function getToken($username, $password){
|
||||
public function getToken($username, $password, $userAgent = null){
|
||||
if ($userAgent == null) {
|
||||
$userAgent = $this->headers['HTTP_USER_AGENT'];
|
||||
}
|
||||
|
||||
$userManager = new UserManager();
|
||||
if ($username != '' || $password != ''){
|
||||
$userLogedIn = $userManager->loginNew($username, $password);
|
||||
@ -10,7 +14,11 @@ class AuthManager {
|
||||
// Create token header as a JSON string
|
||||
$header = json_encode(['typ' => 'JWT', 'alg' => 'HS256']);
|
||||
// Create token payload as a JSON string
|
||||
$payload = json_encode(['user_id' => $userLogedIn]);
|
||||
$payload = json_encode([
|
||||
'user_id' => $userLogedIn,
|
||||
'exp' => date('Y-m-d H:i:s',strtotime("+90 Days")),
|
||||
'iat' => date('Y-m-d H:i:s',time()),
|
||||
]);
|
||||
// Encode Header to Base64Url String
|
||||
$base64UrlHeader = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
|
||||
// Encode Payload to Base64Url String
|
||||
@ -22,7 +30,17 @@ class AuthManager {
|
||||
// Create JWT
|
||||
$jwt = $base64UrlHeader . "." . $base64UrlPayload . "." . $base64UrlSignature;
|
||||
|
||||
return $jwt;
|
||||
|
||||
$token = [
|
||||
'user_id' => $userLogedIn,
|
||||
'user_agent' => $userAgent,
|
||||
'token' => $jwt,
|
||||
'expire' => date('Y-m-d H:i:s',strtotime("+90 Days")),
|
||||
'issued' => date('Y-m-d H:i:s',time()),
|
||||
];
|
||||
if (Db::add ('tokens', $token)){
|
||||
return $jwt;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -206,5 +206,15 @@ class UserManager
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function setOta($otaCode, $otaSecret){
|
||||
$ga = new PHPGangsta_GoogleAuthenticator();
|
||||
$checkResult = $ga->verifyCode($otaSecret, $otaCode, 2); // 2 = 2*30sec clock tolerance
|
||||
if ($checkResult) {
|
||||
self::setUserData('ota', $otaSecret);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
30
app/views/Oauth.php
Normal file
30
app/views/Oauth.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
class Oauth extends Template
|
||||
{
|
||||
function __construct()
|
||||
{
|
||||
global $userManager;
|
||||
global $lang;
|
||||
|
||||
$template = new Template('oauth');
|
||||
$template->prepare('baseDir', BASEDIR);
|
||||
$template->prepare('title', 'Home');
|
||||
|
||||
$template->prepare('lang', $lang);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
33
app/views/templates/oauth.phtml
Normal file
33
app/views/templates/oauth.phtml
Normal file
@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<?php
|
||||
$partial = new Partial('head');
|
||||
$partial->prepare('baseDir',$BASEDIR);
|
||||
$partial->render();
|
||||
?>
|
||||
<title><?php echo $TITLE ?></title>
|
||||
</head>
|
||||
<body class="no-transitions">
|
||||
|
||||
<?php
|
||||
if (isset($ota) && $ota != '') {
|
||||
$partial = new Partial('oauthLoginOta');
|
||||
$partial->prepare('ota',$ota);
|
||||
$partial->render();
|
||||
} else {
|
||||
$partial = new Partial('oauthLoginForm');
|
||||
$partial->prepare('responseType',$RESPONSETYPE);
|
||||
$partial->prepare('redirectUrl',$REDIRECTURL);
|
||||
$partial->prepare('clientId',$CLIENTID);
|
||||
$partial->prepare('state',$STATE);
|
||||
$partial->render();
|
||||
}
|
||||
?>
|
||||
|
||||
<?php
|
||||
$partial = new Partial('footer');
|
||||
$partial->render();
|
||||
?>
|
||||
</body>
|
||||
</html>
|
@ -18,9 +18,9 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<link rel="stylesheet" href="./css/main.css?v2">
|
||||
<link rel="stylesheet" href="./css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="./css/modal.css">
|
||||
<link rel="stylesheet" href="./css/pre.css">
|
||||
<link rel="stylesheet" href="./css/loading.css">
|
||||
<link rel="stylesheet" href="./css/override.css">
|
||||
<link rel="stylesheet" href="<?php echo $BASEDIR; ?>public/css/main.css?v2">
|
||||
<link rel="stylesheet" href="<?php echo $BASEDIR; ?>public/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="<?php echo $BASEDIR; ?>public/css/modal.css">
|
||||
<link rel="stylesheet" href="<?php echo $BASEDIR; ?>public/css/pre.css">
|
||||
<link rel="stylesheet" href="<?php echo $BASEDIR; ?>public/css/loading.css">
|
||||
<link rel="stylesheet" href="<?php echo $BASEDIR; ?>public/css/override.css">
|
||||
|
22
app/views/templates/part/oauthLoginForm.phtml
Normal file
22
app/views/templates/part/oauthLoginForm.phtml
Normal file
@ -0,0 +1,22 @@
|
||||
<div class="modal-container">
|
||||
<div class="modal">
|
||||
<h4 class="mb-4">Login</h4>
|
||||
<form method="post">
|
||||
<div class="field">
|
||||
<div class="label">Name:</div>
|
||||
<input class="input" type="text" name="username" placeholder="Jméno.."/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="label">Password:</div>
|
||||
<input class="input" type="password" name="password" placeholder="Heslo.."/>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="responseType" value="<?php echo $RESPONSETYPE; ?>"/>
|
||||
<input type="hidden" name="redirectUrl" value="<?php echo $REDIRECTURL; ?>"/>
|
||||
<input type="hidden" name="clientId" value="<?php echo $CLIENTID; ?>"/>
|
||||
<input type="hidden" name="state" value="<?php echo $STATE; ?>"/>
|
||||
|
||||
<input type="submit" class="button" name="login" value="Login"/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
16
app/views/templates/part/oauthLoginOta.phtml
Normal file
16
app/views/templates/part/oauthLoginOta.phtml
Normal file
@ -0,0 +1,16 @@
|
||||
<div class="modal-container">
|
||||
<div class="modal">
|
||||
<h4 class="mb-4">OTA</h4>
|
||||
<form method="post">
|
||||
<input type="hidden" name="otaSecret" value="<?php echo $OTA; ?>"/>
|
||||
<div class="field">
|
||||
<div class="label">Code:</div>
|
||||
<?php
|
||||
|
||||
?>
|
||||
<input class="input" type="text" name="otaCode" placeholder=""/>
|
||||
</div>
|
||||
<input type="submit" class="button" name="login" value="Login"/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
@ -95,7 +95,6 @@
|
||||
<h4 class="mb-4"><?php $LANGMNG->echo('t_ota') ?></h4>
|
||||
<?php if (!empty($QRURL)) {?>
|
||||
<img src="<?php echo $QRURL;?>" />
|
||||
<?php echo $OTACODE; ?>
|
||||
<form method="post" action="setting">
|
||||
<div class="field">
|
||||
<div class="label"><?php $LANGMNG->echo('l_gooleAutenticatorOtaCode') ?>:</div>
|
||||
|
252
library/vendor/GoogleAuthenticator.php
vendored
252
library/vendor/GoogleAuthenticator.php
vendored
@ -1,252 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Class for handling Google Authenticator 2-factor authentication.
|
||||
*
|
||||
* @author Michael Kliewe
|
||||
* @copyright 2012 Michael Kliewe
|
||||
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
|
||||
*
|
||||
* @link http://www.phpgangsta.de/
|
||||
*/
|
||||
class PHPGangsta_GoogleAuthenticator
|
||||
{
|
||||
protected $_codeLength = 6;
|
||||
|
||||
/**
|
||||
* Create new secret.
|
||||
* 16 characters, randomly chosen from the allowed base32 characters.
|
||||
*
|
||||
* @param int $secretLength
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function createSecret($secretLength = 16)
|
||||
{
|
||||
$validChars = $this->_getBase32LookupTable();
|
||||
|
||||
// Valid secret lengths are 80 to 640 bits
|
||||
if ($secretLength < 16 || $secretLength > 128) {
|
||||
throw new Exception('Bad secret length');
|
||||
}
|
||||
$secret = '';
|
||||
$rnd = false;
|
||||
if (function_exists('random_bytes')) {
|
||||
$rnd = random_bytes($secretLength);
|
||||
} elseif (function_exists('mcrypt_create_iv')) {
|
||||
$rnd = mcrypt_create_iv($secretLength, MCRYPT_DEV_URANDOM);
|
||||
} elseif (function_exists('openssl_random_pseudo_bytes')) {
|
||||
$rnd = openssl_random_pseudo_bytes($secretLength, $cryptoStrong);
|
||||
if (!$cryptoStrong) {
|
||||
$rnd = false;
|
||||
}
|
||||
}
|
||||
if ($rnd !== false) {
|
||||
for ($i = 0; $i < $secretLength; ++$i) {
|
||||
$secret .= $validChars[ord($rnd[$i]) & 31];
|
||||
}
|
||||
} else {
|
||||
throw new Exception('No source of secure random');
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the code, with given secret and point in time.
|
||||
*
|
||||
* @param string $secret
|
||||
* @param int|null $timeSlice
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCode($secret, $timeSlice = null)
|
||||
{
|
||||
if ($timeSlice === null) {
|
||||
$timeSlice = floor(time() / 30);
|
||||
}
|
||||
|
||||
$secretkey = $this->_base32Decode($secret);
|
||||
|
||||
// Pack time into binary string
|
||||
$time = chr(0).chr(0).chr(0).chr(0).pack('N*', $timeSlice);
|
||||
// Hash it with users secret key
|
||||
$hm = hash_hmac('SHA1', $time, $secretkey, true);
|
||||
// Use last nipple of result as index/offset
|
||||
$offset = ord(substr($hm, -1)) & 0x0F;
|
||||
// grab 4 bytes of the result
|
||||
$hashpart = substr($hm, $offset, 4);
|
||||
|
||||
// Unpak binary value
|
||||
$value = unpack('N', $hashpart);
|
||||
$value = $value[1];
|
||||
// Only 32 bits
|
||||
$value = $value & 0x7FFFFFFF;
|
||||
|
||||
$modulo = pow(10, $this->_codeLength);
|
||||
|
||||
return str_pad($value % $modulo, $this->_codeLength, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get QR-Code URL for image, from google charts.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $secret
|
||||
* @param string $title
|
||||
* @param array $params
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getQRCodeGoogleUrl($name, $secret, $title = null, $params = array())
|
||||
{
|
||||
$width = !empty($params['width']) && (int) $params['width'] > 0 ? (int) $params['width'] : 200;
|
||||
$height = !empty($params['height']) && (int) $params['height'] > 0 ? (int) $params['height'] : 200;
|
||||
$level = !empty($params['level']) && array_search($params['level'], array('L', 'M', 'Q', 'H')) !== false ? $params['level'] : 'M';
|
||||
|
||||
$urlencoded = urlencode('otpauth://totp/'.$name.'?secret='.$secret.'');
|
||||
if (isset($title)) {
|
||||
$urlencoded .= urlencode('&issuer='.urlencode($title));
|
||||
}
|
||||
|
||||
return "https://api.qrserver.com/v1/create-qr-code/?data=$urlencoded&size=${width}x${height}&ecc=$level";
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the code is correct. This will accept codes starting from $discrepancy*30sec ago to $discrepancy*30sec from now.
|
||||
*
|
||||
* @param string $secret
|
||||
* @param string $code
|
||||
* @param int $discrepancy This is the allowed time drift in 30 second units (8 means 4 minutes before or after)
|
||||
* @param int|null $currentTimeSlice time slice if we want use other that time()
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function verifyCode($secret, $code, $discrepancy = 1, $currentTimeSlice = null)
|
||||
{
|
||||
if ($currentTimeSlice === null) {
|
||||
$currentTimeSlice = floor(time() / 30);
|
||||
}
|
||||
|
||||
if (strlen($code) != 6) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for ($i = -$discrepancy; $i <= $discrepancy; ++$i) {
|
||||
$calculatedCode = $this->getCode($secret, $currentTimeSlice + $i);
|
||||
if ($this->timingSafeEquals($calculatedCode, $code)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the code length, should be >=6.
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @return PHPGangsta_GoogleAuthenticator
|
||||
*/
|
||||
public function setCodeLength($length)
|
||||
{
|
||||
$this->_codeLength = $length;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to decode base32.
|
||||
*
|
||||
* @param $secret
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
protected function _base32Decode($secret)
|
||||
{
|
||||
if (empty($secret)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$base32chars = $this->_getBase32LookupTable();
|
||||
$base32charsFlipped = array_flip($base32chars);
|
||||
|
||||
$paddingCharCount = substr_count($secret, $base32chars[32]);
|
||||
$allowedValues = array(6, 4, 3, 1, 0);
|
||||
if (!in_array($paddingCharCount, $allowedValues)) {
|
||||
return false;
|
||||
}
|
||||
for ($i = 0; $i < 4; ++$i) {
|
||||
if ($paddingCharCount == $allowedValues[$i] &&
|
||||
substr($secret, -($allowedValues[$i])) != str_repeat($base32chars[32], $allowedValues[$i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$secret = str_replace('=', '', $secret);
|
||||
$secret = str_split($secret);
|
||||
$binaryString = '';
|
||||
for ($i = 0; $i < count($secret); $i = $i + 8) {
|
||||
$x = '';
|
||||
if (!in_array($secret[$i], $base32chars)) {
|
||||
return false;
|
||||
}
|
||||
for ($j = 0; $j < 8; ++$j) {
|
||||
$x .= str_pad(base_convert(@$base32charsFlipped[@$secret[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT);
|
||||
}
|
||||
$eightBits = str_split($x, 8);
|
||||
for ($z = 0; $z < count($eightBits); ++$z) {
|
||||
$binaryString .= (($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48) ? $y : '';
|
||||
}
|
||||
}
|
||||
|
||||
return $binaryString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array with all 32 characters for decoding from/encoding to base32.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function _getBase32LookupTable()
|
||||
{
|
||||
return array(
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 7
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 15
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 23
|
||||
'Y', 'Z', '2', '3', '4', '5', '6', '7', // 31
|
||||
'=', // padding char
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A timing safe equals comparison
|
||||
* more info here: http://blog.ircmaxell.com/2014/11/its-all-about-time.html.
|
||||
*
|
||||
* @param string $safeString The internal (safe) value to be checked
|
||||
* @param string $userString The user submitted (unsafe) value
|
||||
*
|
||||
* @return bool True if the two strings are identical
|
||||
*/
|
||||
private function timingSafeEquals($safeString, $userString)
|
||||
{
|
||||
if (function_exists('hash_equals')) {
|
||||
return hash_equals($safeString, $userString);
|
||||
}
|
||||
$safeLen = strlen($safeString);
|
||||
$userLen = strlen($userString);
|
||||
|
||||
if ($userLen != $safeLen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = 0;
|
||||
|
||||
for ($i = 0; $i < $userLen; ++$i) {
|
||||
$result |= (ord($safeString[$i]) ^ ord($userString[$i]));
|
||||
}
|
||||
|
||||
// They are only identical strings if $result is exactly 0...
|
||||
return $result === 0;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user