diff --git a/README.md b/README.md index 0556e77..6141a3c 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ [![JS](https://img.shields.io/badge/JS-red.svg)](https://github.com/GamerClassN7/Smart_Home/search?l=js) [![HTML](https://img.shields.io/badge/HTML-blue.svg)](https://github.com/GamerClassN7/Smart_Home/search?l=html) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -[![Discord](https://img.shields.io/discord/604697675430101003.svg?color=Blue&label=Discord&logo=Discord)](https://discord.gg/6BPErAS) +[![Discord](https://img.shields.io/discord/604697675430101003.svg?color=Blue&label=Discord&logo=Discord)](https://discord.gg/XJpT3UQ) ## About Smart_Home diff --git a/_INSTALATION/_SQL_TABLES.sql b/_INSTALATION/_SQL_TABLES.sql index 9223dd5..a7bc3a2 100644 --- a/_INSTALATION/_SQL_TABLES.sql +++ b/_INSTALATION/_SQL_TABLES.sql @@ -141,7 +141,7 @@ CREATE TABLE `users` ( `username` varchar(255) NOT NULL, `password` varchar(255) NOT NULL, `startPage` int(11) NOT NULL, - `at_home` varchar(255) NOT NULL + `at_home` varchar(255) NOT NULL DEFAULT 'false' ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/app/class/UserManager.php b/app/class/UserManager.php index af04549..0b1e4ed 100644 --- a/app/class/UserManager.php +++ b/app/class/UserManager.php @@ -172,10 +172,5 @@ class UserManager return false; } } - - public function setOta($code, $secret){ - $userId = $_SESSION['user']['id']; - Db::edit ('users', ['ota' => $secret], 'WHERE user_id = ?', array($userId)); - } } ?> diff --git a/app/controls/settings.php b/app/controls/settings.php new file mode 100644 index 0000000..dcda809 --- /dev/null +++ b/app/controls/settings.php @@ -0,0 +1,17 @@ + 'Vytvořit', 'b_edit' => 'Upravit', 'b_remove' => 'Smazat', + 'b_finish' => 'Dokončit', 'b_approve' => 'Povolit', 'b_disable' => 'Zakázat', 'b_save' => 'Uložit', - + 'b_logOut' => 'Odhlásit', + 'b_sendTestNotification' => 'Odeslat testovací notifikaci', + 'b_rooms' => 'Místnosti', + 'b_restart' => 'Restart', + 'b_disable' => 'Deaktivovat', + 'b_select' => 'Zvolit', //labels 'l_choseDevice' => 'Zvolte zařízení:', @@ -46,14 +52,24 @@ return $lang = [ 'l_atHome' => 'Doma Jsou', 'l_nameAt' => 'Název', 'l_lastSeen' => 'Naposledy připojeno', + 'l_notificationStatus' => 'Notification status', + 'l_userName' => 'Uživatelské jméno', + 'l_password' => 'Heslo', + 'l_oldPassword' => 'Staré Heslo', + 'l_newPassword' => 'Nové Heslo', //Title 't_createScene' => 'Vytvořit scénu', 't_editScene' => 'Upravit scénu', - 't_createAutomation' => 'Vytvořit Automatizaci', - + 't_addDevice' => 'Přidat Zařízení', 't_editDevice' => 'Upravit Zařízení', + 't_pageAfterLogIn' => 'stránka po přihlášení', + 't_profile' => 'Profil', + 't_notification' => 'Notificatifikace', + 't_experimental' => 'Experimental', + 't_createuser' => 'Vytvořit Uživatele', + 't_changePassword' => 'Změnit Heslo', //constants 'temp' => 'Teplota', @@ -74,6 +90,21 @@ return $lang = [ 'w_neni' => 'Není', 'w_is' => 'je', + //tables + 't_time' => 'Čas', + 't_state' => 'Stav', + 't_userName' => 'Uživatelské Jméno', + 't_action' => 'Akce', + + //Days Long + 'd_monday' => 'Pondělí', + 'd_tuesday' => 'Ůterí', + 'd_wednesday' => 'Středa', + 'd_thursday' => 'Čtvrtek', + 'd_friday' => 'Pátek', + 'd_saturday' => 'Sobota', + 'd_sunday' => 'Neděle', + //example '' => '', ]; diff --git a/app/lang/en.php b/app/lang/en.php index 762d19f..4cded3a 100644 --- a/app/lang/en.php +++ b/app/lang/en.php @@ -29,7 +29,6 @@ return $lang = [ 'b_disable' => 'disabele', 'b_select' => 'Select', - //labels 'l_choseDevice' => 'Chose device:', 'l_inHome' => 'When entering', @@ -54,6 +53,10 @@ return $lang = [ 'l_nameAt' => 'Name', 'l_lastSeen' => 'Last Seen', 'l_notificationStatus' => 'Notification status', + 'l_userName' => 'Username', + 'l_password' => 'Password', + 'l_oldPassword' => 'Old Password', + 'l_newPassword' => 'New Password', //Title 't_createScene' => 'Create Scene', @@ -65,6 +68,8 @@ return $lang = [ 't_profile' => 'Profile', 't_notification' => 'Notification', 't_experimental' => 'Experimental', + 't_createuser' => 'Create User', + 't_changePassword' => 'Change Password', //constants 'humi' => 'Humidity', @@ -88,6 +93,8 @@ return $lang = [ //tables 't_time' => 'Time', 't_state' => 'State', + 't_userName' => 'State', + 't_action' => 'Action', //Days Long 'd_monday' => 'Monday', diff --git a/app/lang/pl.php b/app/lang/pl.php index ff9a762..087fb7e 100644 --- a/app/lang/pl.php +++ b/app/lang/pl.php @@ -18,6 +18,7 @@ return $lang = [ 'b_create' => 'Utwórz', 'b_edit' => 'Edytuj', 'b_remove' => 'Usuń', + 'b_finish' => 'Dokončit', //newOne 'b_approve' => 'Zaakceptuj', 'b_disable' => 'Wyłącz', 'b_save' => 'Zapisz', @@ -50,9 +51,12 @@ return $lang = [ 'l_sleepTime' => 'Czas snu urządzenia', 'l_atHome' => 'W domu', 'l_nameAt' => 'Nazwa', - 'l_nameAt' => 'Nazwa', 'l_lastSeen' => 'Ostatnio zaktualizowany', 'l_notificationStatus' => 'Stan powiadomienia', + 'l_userName' => 'Username', //newOne + 'l_password' => 'Password', //newOne + 'l_oldPassword' => 'Old Password', //newOne + 'l_newPassword' => 'New Password', //newOne //Title 't_createScene' => 'Utwórz scenariusz', @@ -64,6 +68,8 @@ return $lang = [ 't_profile' => 'Profil', 't_notification' => 'Powiadomienie', 't_experimental' => 'Eksperymentalne', + 't_createuser' => 'Vytvořit Uživatele', //newOne + 't_changePassword' => 'Změnit Heslo', //newOne //constants 'humi' => 'Wilgotność', @@ -87,6 +93,8 @@ return $lang = [ //tables 't_time' => 'Czas', 't_state' => 'Stan', + 't_userName' => 'State', //newOne + 't_action' => 'Action', //newOne //Days Long 'd_monday' => 'Poniedziałek', diff --git a/app/templates/css/override.css b/app/templates/css/override.css new file mode 100644 index 0000000..5fc5698 --- /dev/null +++ b/app/templates/css/override.css @@ -0,0 +1,16 @@ +table.table td, table.table th { + border: 2px solid #121a2b; + padding: 8px; +} + +/*tr:nth-child(even){background-color: #f2f2f2;}*/ + +table.table tr:hover {background-color: #121a2b;} + +table.table th { + padding-top: 12px; + padding-bottom: 12px; + text-align: left; + background-color: #121a2b; + color: white; +} \ No newline at end of file diff --git a/app/templates/js/setting.js b/app/templates/js/setting.js index 16614c8..664069a 100644 --- a/app/templates/js/setting.js +++ b/app/templates/js/setting.js @@ -37,4 +37,22 @@ function sendTestNotification(){ console.log("ERROR ", request, error); } }); -} \ No newline at end of file +} + +$( "button[name='deactivateOta']" ).click(function(){ + console.log("Didabling ota"); + $.ajax({ + url: 'ajax', + type: 'POST', + data: { + "ota" : 'X', + "action": 'disable' + }, + success: function(data){ + console.log(data); + }, + error: function (request, status, error) { + console.log("ERROR ", request, error); + } + }); +}) diff --git a/app/templates/login.phtml b/app/templates/login.phtml index 6c37b8b..ae0636b 100644 --- a/app/templates/login.phtml +++ b/app/templates/login.phtml @@ -8,26 +8,16 @@ <?php echo $TITLE ?> - + prepare('ota',$ota); + $partial->render(); + } else { + $partial = new Partial('loginForm'); + $partial->render(); + } + ?> + diff --git a/app/templates/part/loginForm.phtml b/app/templates/part/loginForm.phtml new file mode 100644 index 0000000..c06b535 --- /dev/null +++ b/app/templates/part/loginForm.phtml @@ -0,0 +1,20 @@ + diff --git a/app/templates/part/loginOta.phtml b/app/templates/part/loginOta.phtml new file mode 100644 index 0000000..3e8d294 --- /dev/null +++ b/app/templates/part/loginOta.phtml @@ -0,0 +1,13 @@ + diff --git a/app/vendor/GoogleAuthenticator.php b/app/vendor/GoogleAuthenticator.php new file mode 100644 index 0000000..bf7d116 --- /dev/null +++ b/app/vendor/GoogleAuthenticator.php @@ -0,0 +1,252 @@ +_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; + } +} diff --git a/index.php b/index.php index 5dc8647..e10f582 100644 --- a/index.php +++ b/index.php @@ -13,7 +13,7 @@ mb_internal_encoding ("UTF-8"); //Autoloader -foreach (["class", "views"] as $dir) { +foreach (["vendor","class", "views"] as $dir) { $files = scandir('./app/'.$dir.'/'); $files = array_diff($files, array('.', '..', 'app')); @@ -47,9 +47,10 @@ Db::connect (DBHOST, DBUSER, DBPASS, DBNAME); //TODO: Přesunout do Login Pohledu $userManager = new UserManager(); -if (isset($_POST['username']) && isset($_POST['password']) ) { - $userManager->login($_POST['username'], $_POST['password'], (isset ($_POST['remember']) ? $_POST['remember'] : 'false')); -} + +// if (isset($_POST['username']) && isset($_POST['password']) ) { +// $userManager->login($_POST['username'], $_POST['password'], (isset ($_POST['remember']) ? $_POST['remember'] : 'false')); +// } //Logs $logManager = new LogManager();