Skip to content

Commit

Permalink
Added user management by buildings and signup links with permission c…
Browse files Browse the repository at this point in the history
…hecks
  • Loading branch information
michnovka committed Oct 9, 2020
1 parent 740f2a6 commit af0ff11
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 51 deletions.
60 changes: 51 additions & 9 deletions admin_edit_user.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,27 +55,59 @@
$error['name'] = "Invalid name";
}

if (trim($_POST['apartment']) && !preg_match('/Z[0-9]\.B[0-9]\.[0-9]{3}/i',$_POST['apartment'])){
$group_for_new_user = null;

if (trim($_POST['apartment']) && !preg_match('/Z([0-9])\.B([0-9])\.[0-9]{3}/i',$_POST['apartment'], $m)){
$error['apartment'] = "Use format ZX.BY.NNN for apartment";
}

if(!_check_permission('super_admin')) {
$_POST['default_garage'] = 'z'.$m[1];

if(!_check_admin_building_permission($_SESSION['id'], $_POST['apartment'])){
$error['apartment'] = "You cannot use this apartment, check your permissions";
}
}

$group_for_new_user = 'Z'.$m[1].'.B'.$m[2];

$edit_user['name'] = htmlspecialchars($_POST['name']);
$edit_user['enabled'] = !empty($_POST['enabled']);
$edit_user['can_create_guests'] = !empty($_POST['can_create_guests']);
$edit_user['has_camera_access'] = !empty($_POST['has_camera_access']);

if (empty($_POST['groups'])){
$error['groups'] = "Choose at least one group";
if(_check_permission('super_admin')) {
if (empty($_POST['groups'])) {
$error['groups'] = "Choose at least one group";
}
}

$user_groups = $_POST['groups'];

if(!$_POST['id']){
$group_for_new_user2 = $group_for_new_user;
$group_for_new_user = $db->fetch('SELECT id FROM `groups` WHERE name=?', $group_for_new_user);

if(empty($group_for_new_user)){
$error['groups'] = "No applicable group. Contact super admin".$group_for_new_user2;
}
}

if($_POST['id'] && !_check_admin_permission_for_user($_SESSION['id'], $_POST['id'])){
$error['permission'] = "You are not authorized to edit this user.";
}

if(empty($error)){
$smarty->assign('success', 'Successfully saved');

// save all except pwd
if(!$_POST['id']){
// create new user
$db->query('INSERT INTO users SET username=?, password=?,name=?,created=NOW(),enabled=#,has_camera_access=#,can_create_guests=#,apartment=?,default_garage=?,email=?,phone=?', $_POST['username'],PasswordTools::getHashedPassword($_POST['password']), $_POST['name'], $_POST['enabled'] ? 1 : 0, $_POST['has_camera_access'] ? 1 : 0,$_POST['can_create_guests'] ? 1 : 0, $_POST['apartment'],$_POST['default_garage'], $_POST['email'], $_POST['phone']);
$db->query('INSERT INTO users SET username=?, password=?,name=?,created=NOW(),enabled=#,has_camera_access=#,can_create_guests=#,apartment=?,default_garage=?,email=?,phone=?,created_by=#', $_POST['username'],PasswordTools::getHashedPassword($_POST['password']), $_POST['name'], $_POST['enabled'] ? 1 : 0, $_POST['has_camera_access'] ? 1 : 0,$_POST['can_create_guests'] ? 1 : 0, $_POST['apartment'],$_POST['default_garage'], $_POST['email'], $_POST['phone'], $_SESSION['id']);
$_GET['id'] = $_POST['id'] = $db->lastinsertid();

$db->query('INSERT INTO user_group SET user_id=#, group_id=#', $_POST['id'], $group_for_new_user);

}else{
// update user
$db->query('UPDATE users SET username=?, name=?,enabled=#,has_camera_access=#,can_create_guests=#,apartment=?,default_garage=?,email=?,phone=? WHERE id=#', $_POST['username'], $_POST['name'], $_POST['enabled'] ? 1 : 0, $_POST['has_camera_access'] ? 1 : 0,$_POST['can_create_guests'] ? 1 : 0, $_POST['apartment'],$_POST['default_garage'], $_POST['email'], $_POST['phone'], $_POST['id']);
Expand All @@ -86,10 +118,12 @@
}
}

// save groups
$db->query('DELETE FROM user_group WHERE user_id=#', $_POST['id']);
foreach ($_POST['groups'] as $g){
$db->query('INSERT INTO user_group SET user_id=#, group_id=#', $_POST['id'], $g);
if(_check_permission('super_admin')) {
// save groups
$db->query('DELETE FROM user_group WHERE user_id=#', $_POST['id']);
foreach ($_POST['groups'] as $g) {
$db->query('INSERT INTO user_group SET user_id=#, group_id=#', $_POST['id'], $g);
}
}

}else{
Expand All @@ -98,12 +132,20 @@
}

}elseif($_POST['action'] == 'delete'){
$db->query('DELETE FROM users WHERE id=#', $_POST['id']);
// check if permissions and also, cannot delete yourself
if(_check_admin_permission_for_user($_SESSION['id'], $_POST['id']) && $_SESSION['id'] != $_POST['id']) {
$db->query('DELETE FROM users WHERE id=#', $_POST['id']);
}
header('Location: admin_users.php');
exit;
}
}

if($_GET['id'] && !_check_admin_permission_for_user($_SESSION['id'], $_GET['id'])){
header('Location: admin_users.php');
exit;
}

$user = _get_user_array();

$smarty->assign('user', $user);
Expand Down
37 changes: 28 additions & 9 deletions admin_users.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,33 @@
exit;
}

if($_GET['change_signup_key']){
$new_key = PasswordTools::generateRandomHash(16, 16);
$db->query('INSERT INTO config SET `key`=?, `value`=? ON DUPLICATE KEY UPDATE `value` = ?', 'signup_key', $new_key, $new_key);
header('Location:admin_users.php?signup_key_changed=1#signup_url');
exit;
if($_POST['create_new_signup_key']){
$error = false;

// check apartment_mask
if(!_check_permission('super_admin')){
if(!preg_match('/Z([0-9])\.B([0-9])\.?([0-9]{3})?$/i', $_POST['apartment_mask'], $m)){
$error = 'Invalid mask';
}elseif(!_check_admin_building_permission($_SESSION['id'], 'Z'.$m[1].'.B'.$m[2])){
$error = 'Not authorized';
}else{
$_POST['apartment_mask'] = strtoupper($_POST['apartment_mask']);
}
}

if($error){
$smarty->assign('signup_key_error', $error);
}else {

$new_key = PasswordTools::generateRandomHash(16, 16);
$new_key_expires = date('Y-m-d H:i:s', time() + (86400 * 7));

$db->query('INSERT INTO signup_codes SET hash=?, admin_id=#, expires = ?, apartment_mask=?, created_time=NOW()', $new_key, $_SESSION['id'], $new_key_expires, $_POST['apartment_mask']);

$smarty->assign('signup_key_created', true);
$smarty->assign('signup_key_expires', $new_key_expires);
$smarty->assign('signup_url', 'https://' . $_SERVER['HTTP_HOST'] . '/signup.php?key=' . $new_key);
}
}

$user = _get_user_array();
Expand All @@ -25,7 +47,7 @@
$db->queryall('SELECT * FROM groups ORDER BY name', $groups);

$users = null;
$db->queryall('SELECT GROUP_CONCAT(g.name) `groups_names`,u.* FROM users u INNER JOIN user_group ug on u.id = ug.user_id INNER JOIN groups g ON g.id = ug.group_id GROUP BY u.id ORDER BY u.id', $users);
$db->queryall('SELECT GROUP_CONCAT(g.name) `groups_names`,u.* FROM users u INNER JOIN user_group ug on u.id = ug.user_id INNER JOIN groups g ON g.id = ug.group_id '.(_check_permission('super_admin') ? '' : ' WHERE apartment REGEXP (SELECT GROUP_CONCAT(CONCAT("^",ab.building) SEPARATOR "|") FROM admin_buildings ab INNER JOIN `groups` g ON g.id = ab.admin_group_id INNER JOIN group_permission gp on g.id = gp.group_id INNER JOIN user_group u on g.id = u.group_id WHERE gp.permission="admin" AND u.user_id='.intval($user['id']).')').' GROUP BY u.id ORDER BY u.id', $users);

$last_command_times = null;
$db->queryall('SELECT MAX(time_created) last_command_time, user_id FROM action_queue GROUP BY user_id', $last_command_times, '%user_id@last_command_time');
Expand All @@ -39,9 +61,6 @@
$smarty->assign('users', $users);

$smarty->assign('groups', $groups);
$smarty->assign('signup_key_changed', !empty($_GET['signup_key_changed']));

$smarty->assign('signup_url', 'https://'.$_SERVER['HTTP_HOST'].'/signup.php?key='.$_CONFIG['signup_key']);
$smarty->display('admin_users.tpl');

?>
10 changes: 7 additions & 3 deletions camera.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,16 @@
}

if(!empty($cameras[2]['photo_data'])){
$thumb = imagecreatetruecolor(1920, 2160);

$img1 = imagecreatefromstring($cameras[1]['photo_data']);
list($width, $height, $type, $attr) = getimagesizefromstring($cameras[1]['photo_data']);

$thumb = imagecreatetruecolor($width, $height*2);
$img1 = imagecreatefromstring($cameras[1]['photo_data']);
$img2 = imagecreatefromstring($cameras[2]['photo_data']);

imagecopy($thumb, $img1, 0, 0, 0, 0, 1920, 1080); //have to play with these numbers for it to work for you, etc.
imagecopy($thumb, $img2, 0, 1080, 0, 0, 1920, 1080); //have to play with these numbers for it to work for you, etc.
imagecopy($thumb, $img1, 0, 0, 0, 0, $width, $height); //have to play with these numbers for it to work for you, etc.
imagecopy($thumb, $img2, 0, $height, 0, 0, $width, $height); //have to play with these numbers for it to work for you, etc.
header('Content-type: image/jpeg');

imagejpeg($thumb);
Expand Down
2 changes: 2 additions & 0 deletions cron/db_cleanup.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
$db->query('DELETE FROM nuki_logs WHERE time < DATE_SUB(NOW(), INTERVAL # DAY)', $CRON_FONFIG['nuki_logs_timelife_days']);
$db->query('DELETE FROM webauthn_registrations WHERE last_used_time < DATE_SUB(NOW(), INTERVAL # DAY)', $CRON_FONFIG['webauthn_registrations_unused_timelife_days']);

$db->query('DELETE FROM signup_codes WHERE expires < NOW()');

$now = date('Y-m-d H:i:s');
$db->query('INSERT INTO config SET `key`=?, `value`=? ON DUPLICATE KEY UPDATE `value` = ?', 'last_cron_db_cleanup_time', $now, $now);

Expand Down
26 changes: 26 additions & 0 deletions libs/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,32 @@ function _check_permission($permission, $user = null)

return $_SESSION['permissions'][$permission] == 1;
}

/**
* @param int $admin_id
* @param int $user_id
* @return bool
* @throws EDatabase
*/
function _check_admin_permission_for_user($admin_id, $user_id){
global $db;

if(_check_permission('super_admin')) return true;

return $db->fetch('SELECT 1 FROM users u INNER JOIN user_group ug on u.id = ug.user_id INNER JOIN groups g ON g.id = ug.group_id WHERE u.id=# '.(_check_permission('super_admin') ? '' : ' AND apartment REGEXP (SELECT GROUP_CONCAT(CONCAT("^",ab.building) SEPARATOR "|") FROM admin_buildings ab INNER JOIN `groups` g ON g.id = ab.admin_group_id INNER JOIN group_permission gp on g.id = gp.group_id INNER JOIN user_group u on g.id = u.group_id WHERE gp.permission="admin" AND u.user_id='.intval($admin_id).')').' GROUP BY u.id ORDER BY u.id', $user_id) ? true : false;
}

/**
* @param int $admin_id
* @param string $building
* @return mixed|null
* @throws EDatabase
*/
function _check_admin_building_permission($admin_id, $building){
global $db;
return $db->fetch("SELECT ? REGEXP (SELECT GROUP_CONCAT(CONCAT('^',ab.building) SEPARATOR '|') FROM admin_buildings ab INNER JOIN `groups` g ON g.id = ab.admin_group_id INNER JOIN group_permission gp on g.id = gp.group_id INNER JOIN user_group u on g.id = u.group_id WHERE gp.permission='admin' AND u.user_id=#)", $building, $admin_id) ? true : false;
}

/**
* @param int $nuki_id
* @param null|array $user
Expand Down
1 change: 1 addition & 0 deletions login.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
// check username and pwd
$user = $db->queryfirst('SELECT * FROM users WHERE username=? AND enabled=1 LIMIT 1', $_POST['username']);

//if($user['username']!='lubospirek')
if(empty($user) || !PasswordTools::checkPassword($_POST['password'], $user['password'])){
$error = 'Invalid username or password';
}
Expand Down
11 changes: 8 additions & 3 deletions signup.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
header('Location: /');
exit;
}
$signup_code = $db->queryfirst('SELECT * FROM signup_codes WHERE hash=? AND expires > NOW() LIMIT 1', $_GET['key']);

if($_GET['key'] != $_CONFIG['signup_key']){
if(empty($signup_code)){
echo "Invalid signup key";
exit;
}

$edit_user = array();
$edit_user = array('apartment' => $signup_code['apartment_mask']);

if(!empty($_POST['action'])){
if($_POST['action'] == 'save'){
Expand Down Expand Up @@ -59,6 +60,8 @@

if (!preg_match('/^Z([0-9])\.B([0-9])\.([0-9]{3})$/i',$_POST['apartment'], $apartment_parts)){
$error['apartment'] = "Use format ZX.BY.NNN for apartment";
}elseif(!preg_match('/^'.$signup_code['apartment_mask'].'/i', $_POST['apartment'])){
$error['apartment'] = "The apartment code is not allowed. Use format ZX.BY.NNN and allowed mask is ".$signup_code['apartment_mask'];
}

$edit_user['apartment'] = htmlspecialchars($_POST['apartment']);
Expand All @@ -80,12 +83,14 @@
}else {

// create new user
$db->query('INSERT INTO users SET username=?, password=?,name=?,created=NOW(),enabled=#,apartment=?,default_garage=?,email=?,phone=?', $_POST['username'], PasswordTools::getHashedPassword($_POST['password']), $_POST['name'], 1, $_POST['apartment'], $default_garage, $_POST['email'], $_POST['phone']);
$db->query('INSERT INTO users SET username=?, password=?,name=?,created=NOW(),enabled=#,apartment=?,default_garage=?,email=?,phone=?,created_by=#', $_POST['username'], PasswordTools::getHashedPassword($_POST['password']), $_POST['name'], 1, $_POST['apartment'], $default_garage, $_POST['email'], $_POST['phone'], $signup_code['admin_id']);
$user_id = $db->lastinsertid();

// save groups
$db->query('INSERT INTO user_group SET user_id=#, group_id=#', $user_id, $group_id);

$db->query('UPDATE signup_codes SET signups_count = signups_count+1 WHERE hash = ?', $signup_code['hash']);

header('Location: login.php?username=' . urlencode($_POST['username']));
exit;
}
Expand Down
5 changes: 3 additions & 2 deletions smarty/templates/admin_edit_user.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
<div class="uk-margin">
<label class="uk-form-label" for="apartment">Apartment</label>
<div class="uk-form-controls">
<input class="uk-input {if $error.phone}uk-form-danger{/if}" id="apartment" type="text" placeholder="ZX.BY.NNN" value="{$edit_user.apartment}" name="apartment">
<input class="uk-input {if $error.apartment}uk-form-danger{/if}" id="apartment" type="text" placeholder="ZX.BY.NNN" value="{$edit_user.apartment}" name="apartment">
</div>
</div>

Expand Down Expand Up @@ -99,7 +99,7 @@
</div>
</div>


{if $permissions.super_admin}
<div class="uk-margin">
<div class="uk-form-label">Groups</div>
<div class="uk-form-controls uk-form-controls-text">
Expand All @@ -108,6 +108,7 @@
{/section}
</div>
</div>
{/if}

<div class="uk-margin">
<div class="uk-form-controls">
Expand Down
44 changes: 28 additions & 16 deletions smarty/templates/admin_users.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@


<div class="uk-container uk-container-expand uk-container-center uk-text-center">
{if $signup_key_error}
<div class="uk-alert-danger uk-text-center uk-margin-medium" uk-alert>
<p>Error creating signup key: {$signup_key_error}</p>
</div>
{elseif $signup_key_created}
<div class="uk-alert-success uk-text-center uk-margin-medium" uk-alert>
<p>New link created successfully. It expires on {$signup_key_expires}</p>
</div>

Give this URL to users to sign up:
<div class="uk-margin">
<input class="uk-input uk-form-width-large" type="text" value="{$signup_url}" readonly>
</div>
<div class="uk-margin">
<img src="qrcode.php?content={$signup_url|urlencode}" srcset="qrcode.php?content={$signup_url|urlencode}&size=5,qrcode.php?content={$signup_url|urlencode}&size=10 2x" />
</div>

{/if}

<h2 class="uk-heading-line uk-margin-small uk-margin-small-top uk-text-center"><span>Users CP</span></h2>

Expand Down Expand Up @@ -30,7 +48,7 @@
<td>{$users[u].created}</td>
<td>{$users[u].enabled}</td>
<td>{$users[u].groups_names}</td>
<td>{if !$users[u].last_command_time}NEVER{else}<a href="admin_queue.php?user_id={$users[u].id}" title="View action history for {$users[u].username|escape}">{$users[u].last_command_time}</a>{/if}</td>
<td>{if !$users[u].last_command_time}NEVER{else}{if $permissions.super_admin}<a href="admin_queue.php?user_id={$users[u].id}" title="View action history for {$users[u].username|escape}">{/if}{$users[u].last_command_time}{if $permissions.super_admin}</a>{/if}{/if}</td>
<td>{$users[u].apartment}</td>
<td>{$users[u].default_garage}</td>
<td>{$users[u].email}</td>
Expand All @@ -45,22 +63,16 @@

<h4 class="uk-heading-line uk-margin-small uk-margin-large-top uk-text-center" id="signup_url"><span>Signup URL</span></h4>

{if $signup_key_changed}
<div class="uk-alert-success uk-text-center uk-margin-medium" uk-alert>
<p>Key changed successfully. Old one will no longer work.</p>
</div>
{/if}

Give this URL to users to sign up:
<div class="uk-margin">
<input class="uk-input uk-form-width-large" type="text" value="{$signup_url}" readonly>
</div>
<div class="uk-margin">
<img src="qrcode.php?content={$signup_url|urlencode}" srcset="qrcode.php?content={$signup_url|urlencode}&size=5,qrcode.php?content={$signup_url|urlencode}&size=10 2x" />
</div>
<div class="uk-margin">
<a class="uk-button uk-button-default uk-button-medium" href="admin_users.php?change_signup_key=1">Change key</a>
</div>
<form action="admin_users.php" method="post">
<div class="uk-margin">
<label for="apartment_mask">Apartment mask</label>
<input type="text" class="uk-input uk-width-medium" name="apartment_mask" id="apartment_mask" placeholder="ZX.BY or ZX.BY.NNN" />
</div>
<div class="uk-margin">
<button type="submit" class="uk-button uk-button-default uk-button-medium" name="create_new_signup_key" value="1">Create new key</button>
</div>
</form>

</div>

Expand Down
19 changes: 10 additions & 9 deletions smarty/templates/footer.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@
<a href="settings.php">Settings</a> |
{if $user.can_create_guests}<a href="create_guest.php">Guest pass</a> |{/if}
<a href="logout.php">Log out</a><br/>
<strong>ADMIN - </strong>
{if $permissions.super_admin}<a href="admin_queue.php">Queue</a> |{/if}
{if $permissions.admin}<a href="admin_users.php">Users</a> |{/if}
{if $permissions.super_admin}<a href="admin_stats.php">Stats</a> |{/if}
{if $permissions.super_admin}<a href="admin_groups.php">Groups</a> |{/if}
{if $permissions.super_admin}<a href="admin_crons.php">CRONs</a> |{/if}
{if $permissions.super_admin}<a href="admin_monitor_nodes.php">Nodes</a>{/if}


{if $permissions.admin || $permissions.super_admin}

<strong>ADMIN - </strong>
{if $permissions.super_admin}<a href="admin_queue.php">Queue</a> |{/if}
{if $permissions.admin}<a href="admin_users.php">Users</a> |{/if}
{if $permissions.super_admin}<a href="admin_stats.php">Stats</a> |{/if}
{if $permissions.super_admin}<a href="admin_groups.php">Groups</a> |{/if}
{if $permissions.super_admin}<a href="admin_crons.php">CRONs</a> |{/if}
{if $permissions.super_admin}<a href="admin_monitor_nodes.php">Nodes</a>{/if}
{/if}
{/if}
</div>
</div>
Expand Down

0 comments on commit af0ff11

Please sign in to comment.