forked from Business/ManagePanel
Merge ../BusinessAppTemplate
# Conflicts: # README.md # api.php # composer.lock # index.php # lang/en_us.php # lib/login.php # required.php # settings.template.php
This commit is contained in:
commit
47540e57d2
@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2018 Netsyms Technologies.
|
Copyright (c) 2018-2019 Netsyms Technologies.
|
||||||
|
|
||||||
If you modify and redistribute this project, you must replace the branding
|
If you modify and redistribute this project, you must replace the branding
|
||||||
assets with your own.
|
assets with your own.
|
||||||
|
@ -12,8 +12,7 @@ Installing
|
|||||||
0. Follow the installation directions for [AccountHub](https://source.netsyms.com/Business/AccountHub), then download this app somewhere.
|
0. Follow the installation directions for [AccountHub](https://source.netsyms.com/Business/AccountHub), then download this app somewhere.
|
||||||
1. Copy `settings.template.php` to `settings.php`
|
1. Copy `settings.template.php` to `settings.php`
|
||||||
2. Import `database.sql` into your database server
|
2. Import `database.sql` into your database server
|
||||||
3. Edit `settings.php` and fill in your DB info ("DB_*" for the AccountHub database, "DB2_*" for the ManagePanel one you just installed)
|
3. Edit `settings.php` and fill in your DB info ("database" for the AccountHub database, "database2" for the ManagePanel one you just installed)
|
||||||
4. Set the location of the AccountHub API in `settings.php` (see "PORTAL_API") and enter an API key ("PORTAL_KEY")
|
4. Set the location of the AccountHub API in `settings.php`, enter an API key, and set the home page
|
||||||
5. Set the location of the AccountHub home page ("PORTAL_URL")
|
6. Set the URL of this app
|
||||||
6. Set the URL of this app ("URL")
|
|
||||||
7. Run `composer install` (or `composer.phar install`) to install dependency libraries.
|
7. Run `composer install` (or `composer.phar install`) to install dependency libraries.
|
||||||
|
50
action.php
50
action.php
@ -8,14 +8,12 @@
|
|||||||
* Make things happen when buttons are pressed and forms submitted.
|
* Make things happen when buttons are pressed and forms submitted.
|
||||||
*/
|
*/
|
||||||
require_once __DIR__ . "/required.php";
|
require_once __DIR__ . "/required.php";
|
||||||
require_once __DIR__ . "/lib/login.php";
|
|
||||||
require_once __DIR__ . "/lib/authlog.php";
|
|
||||||
|
|
||||||
if ($VARS['action'] !== "signout") {
|
if ($VARS['action'] !== "signout") {
|
||||||
dieifnotloggedin();
|
dieifnotloggedin();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (account_has_permission($_SESSION['username'], "ADMIN") == FALSE) {
|
if ((new User($_SESSION['uid']))->hasPermission("ADMIN") == FALSE) {
|
||||||
die("You don't have permission to be here.");
|
die("You don't have permission to be here.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +42,7 @@ function returnToSender($msg, $arg = "", $additional = []) {
|
|||||||
|
|
||||||
switch ($VARS['action']) {
|
switch ($VARS['action']) {
|
||||||
case "edituser":
|
case "edituser":
|
||||||
if (is_empty($VARS['id'])) {
|
if (empty($VARS['id'])) {
|
||||||
$insert = true;
|
$insert = true;
|
||||||
} else {
|
} else {
|
||||||
if ($database->has('accounts', ['uid' => $VARS['id']])) {
|
if ($database->has('accounts', ['uid' => $VARS['id']])) {
|
||||||
@ -53,7 +51,7 @@ switch ($VARS['action']) {
|
|||||||
returnToSender("invalid_userid");
|
returnToSender("invalid_userid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_empty($VARS['name']) || is_empty($VARS['username']) || is_empty($VARS['status'])) {
|
if (empty($VARS['name']) || empty($VARS['username']) || empty($VARS['status'])) {
|
||||||
returnToSender('invalid_parameters');
|
returnToSender('invalid_parameters');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +67,7 @@ switch ($VARS['action']) {
|
|||||||
'deleted' => 0
|
'deleted' => 0
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!is_empty($VARS['pass'])) {
|
if (!empty($VARS['pass'])) {
|
||||||
$data['password'] = password_hash($VARS['pass'], PASSWORD_BCRYPT);
|
$data['password'] = password_hash($VARS['pass'], PASSWORD_BCRYPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,11 +76,11 @@ switch ($VARS['action']) {
|
|||||||
$data['phone2'] = "";
|
$data['phone2'] = "";
|
||||||
$data['accttype'] = 1;
|
$data['accttype'] = 1;
|
||||||
$database->insert('accounts', $data);
|
$database->insert('accounts', $data);
|
||||||
insertAuthLog(17, $_SESSION['uid'], $data['username'] . ", " . $data['realname'] . ", " . $data['email'] . ", " . $data['acctstatus']);
|
Log::insert(LogType::USER_ADDED, $_SESSION['uid'], $data['username'] . ", " . $data['realname'] . ", " . $data['email'] . ", " . $data['acctstatus']);
|
||||||
} else {
|
} else {
|
||||||
$olddata = $database->select('accounts', '*', ['uid' => $VARS['id']])[0];
|
$olddata = $database->select('accounts', '*', ['uid' => $VARS['id']])[0];
|
||||||
$database->update('accounts', $data, ['uid' => $VARS['id']]);
|
$database->update('accounts', $data, ['uid' => $VARS['id']]);
|
||||||
insertAuthLog(18, $_SESSION['uid'], "OLD: " . $olddata['username'] . ", " . $olddata['realname'] . ", " . $olddata['email'] . ", " . $olddata['acctstatus'] . "; NEW: " . $data['username'] . ", " . $data['realname'] . ", " . $data['email'] . ", " . $data['acctstatus']);
|
Log::insert(LogType::USER_EDITED, $_SESSION['uid'], "OLD: " . $olddata['username'] . ", " . $olddata['realname'] . ", " . $olddata['email'] . ", " . $olddata['acctstatus'] . "; NEW: " . $data['username'] . ", " . $data['realname'] . ", " . $data['email'] . ", " . $data['acctstatus']);
|
||||||
}
|
}
|
||||||
|
|
||||||
returnToSender("user_saved");
|
returnToSender("user_saved");
|
||||||
@ -97,7 +95,7 @@ switch ($VARS['action']) {
|
|||||||
// we will flag it as deleted and set the status to LOCKED_OR_DISABLED.
|
// we will flag it as deleted and set the status to LOCKED_OR_DISABLED.
|
||||||
$database->update('accounts', ['acctstatus' => 2, 'deleted' => 1], ['uid' => $VARS['id']]);
|
$database->update('accounts', ['acctstatus' => 2, 'deleted' => 1], ['uid' => $VARS['id']]);
|
||||||
}
|
}
|
||||||
insertAuthLog(16, $_SESSION['uid'], $olddata['username'] . ", " . $olddata['realname'] . ", " . $olddata['email'] . ", " . $olddata['acctstatus']);
|
Log::insert(LogType::USER_REMOVED, $_SESSION['uid'], $olddata['username'] . ", " . $olddata['realname'] . ", " . $olddata['email'] . ", " . $olddata['acctstatus']);
|
||||||
returnToSender("user_deleted");
|
returnToSender("user_deleted");
|
||||||
case "rmtotp":
|
case "rmtotp":
|
||||||
if ($database->has('accounts', ['uid' => $VARS['id']]) !== TRUE) {
|
if ($database->has('accounts', ['uid' => $VARS['id']]) !== TRUE) {
|
||||||
@ -105,28 +103,27 @@ switch ($VARS['action']) {
|
|||||||
}
|
}
|
||||||
$u = $database->get('accounts', 'username', ['uid' => $VARS['id']]);
|
$u = $database->get('accounts', 'username', ['uid' => $VARS['id']]);
|
||||||
$database->update('accounts', ["authsecret" => null], ['uid' => $VARS['id']]);
|
$database->update('accounts', ["authsecret" => null], ['uid' => $VARS['id']]);
|
||||||
insertAuthLog(10, $_SESSION['uid'], $u);
|
Log::insert(LogType::REMOVED_2FA, $_SESSION['uid'], $u);
|
||||||
returnToSender("2fa_removed");
|
returnToSender("2fa_removed");
|
||||||
case "clearlog":
|
case "clearlog":
|
||||||
$rows = $database->count('authlog');
|
$rows = $database->count('authlog');
|
||||||
$database->delete('authlog', []);
|
$database->delete('authlog', []);
|
||||||
insertAuthLog(15, $_SESSION['uid'], lang2("removed n entries", ['n' => $rows], false));
|
Log::insert(LogType::LOG_CLEARED, $_SESSION['uid'], $Strings->build("removed n entries", ['n' => $rows], false));
|
||||||
returnToSender("log_cleared");
|
returnToSender("log_cleared");
|
||||||
case "editmanager":
|
case "editmanager":
|
||||||
require_once __DIR__ . "/lib/userinfo.php";
|
|
||||||
if (!$database->has('accounts', ['username' => $VARS['manager']])) {
|
if (!$database->has('accounts', ['username' => $VARS['manager']])) {
|
||||||
returnToSender("invalid_manager");
|
returnToSender("invalid_manager");
|
||||||
}
|
}
|
||||||
$manager = getUserByUsername($VARS['manager'])['uid'];
|
$manager = User::byUsername($VARS['manager'])->getUID();
|
||||||
$already_assigned = $database->select('managers', 'employeeid', ['managerid' => $manager]);
|
$already_assigned = $database->select('managers', 'employeeid', ['managerid' => $manager]);
|
||||||
|
|
||||||
foreach ($VARS['employees'] as $u) {
|
foreach ($VARS['employees'] as $u) {
|
||||||
if (!user_exists($u)) {
|
$emp = User::byUsername($u);
|
||||||
returnToSender("user_not_exists", htmlentities($u));
|
if (!$emp->exists()) {
|
||||||
|
returnToSender("user_not_exists", htmlentities($emp->getUsername()));
|
||||||
}
|
}
|
||||||
$uid = getUserByUsername($u)['uid'];
|
$database->insert('managers', ['employeeid' => $emp->getUID(), 'managerid' => $manager]);
|
||||||
$database->insert('managers', ['employeeid' => $uid, 'managerid' => $manager]);
|
$already_assigned = array_diff($already_assigned, [$emp->getUID()]); // Remove user from old list
|
||||||
$already_assigned = array_diff($already_assigned, [$uid]); // Remove user from old list
|
|
||||||
}
|
}
|
||||||
foreach ($already_assigned as $uid) {
|
foreach ($already_assigned as $uid) {
|
||||||
$database->delete('managers', ["AND" => ['employeeid' => $uid, 'managerid' => $manager]]);
|
$database->delete('managers', ["AND" => ['employeeid' => $uid, 'managerid' => $manager]]);
|
||||||
@ -198,14 +195,14 @@ switch ($VARS['action']) {
|
|||||||
returnToSender("permission_deleted");
|
returnToSender("permission_deleted");
|
||||||
case "autocomplete_user":
|
case "autocomplete_user":
|
||||||
header("Content-Type: application/json");
|
header("Content-Type: application/json");
|
||||||
if (is_empty($VARS['q']) || strlen($VARS['q']) < 3) {
|
if (empty($VARS['q']) || strlen($VARS['q']) < 3) {
|
||||||
exit(json_encode([]));
|
exit(json_encode([]));
|
||||||
}
|
}
|
||||||
$data = $database->select('accounts', ['uid', 'username', 'realname (name)'], ["OR" => ['username[~]' => $VARS['q'], 'realname[~]' => $VARS['q']], "LIMIT" => 10]);
|
$data = $database->select('accounts', ['uid', 'username', 'realname (name)'], ["OR" => ['username[~]' => $VARS['q'], 'realname[~]' => $VARS['q']], "LIMIT" => 10]);
|
||||||
exit(json_encode($data));
|
exit(json_encode($data));
|
||||||
case "autocomplete_permission":
|
case "autocomplete_permission":
|
||||||
header("Content-Type: application/json");
|
header("Content-Type: application/json");
|
||||||
if (is_empty($VARS['q'])) {
|
if (empty($VARS['q'])) {
|
||||||
exit(json_encode([]));
|
exit(json_encode([]));
|
||||||
}
|
}
|
||||||
$data = $database->select('permissions', ['permcode (name)', 'perminfo (info)'], ["OR" => ['permcode[~]' => $VARS['q'], 'perminfo[~]' => $VARS['q']], "LIMIT" => 10]);
|
$data = $database->select('permissions', ['permcode (name)', 'perminfo (info)'], ["OR" => ['permcode[~]' => $VARS['q'], 'perminfo[~]' => $VARS['q']], "LIMIT" => 10]);
|
||||||
@ -217,14 +214,13 @@ switch ($VARS['action']) {
|
|||||||
$gid = $VARS['gid'];
|
$gid = $VARS['gid'];
|
||||||
$already_assigned = $database->select('assigned_groups', 'uid', ['groupid' => $gid]);
|
$already_assigned = $database->select('assigned_groups', 'uid', ['groupid' => $gid]);
|
||||||
|
|
||||||
require_once __DIR__ . "/lib/userinfo.php";
|
|
||||||
foreach ($VARS['users'] as $u) {
|
foreach ($VARS['users'] as $u) {
|
||||||
if (!user_exists($u)) {
|
$user = User::byUsername($u);
|
||||||
returnToSender("user_not_exists", htmlentities($u));
|
if (!$user->exists()) {
|
||||||
|
returnToSender("user_not_exists", htmlentities($user->getUsername()));
|
||||||
}
|
}
|
||||||
$uid = getUserByUsername($u)['uid'];
|
$database->insert('assigned_groups', ['groupid' => $gid, 'uid' => $user->getUID()]);
|
||||||
$database->insert('assigned_groups', ['groupid' => $gid, 'uid' => $uid]);
|
$already_assigned = array_diff($already_assigned, [$user->getUID()]); // Remove user from old list
|
||||||
$already_assigned = array_diff($already_assigned, [$uid]); // Remove user from old list
|
|
||||||
}
|
}
|
||||||
foreach ($already_assigned as $uid) {
|
foreach ($already_assigned as $uid) {
|
||||||
$database->delete('assigned_groups', ["AND" => ['uid' => $uid, 'groupid' => $gid]]);
|
$database->delete('assigned_groups', ["AND" => ['uid' => $uid, 'groupid' => $gid]]);
|
||||||
@ -251,7 +247,7 @@ switch ($VARS['action']) {
|
|||||||
break;
|
break;
|
||||||
case "signout":
|
case "signout":
|
||||||
session_destroy();
|
session_destroy();
|
||||||
header('Location: index.php');
|
header('Location: index.php?logout=1');
|
||||||
die("Logged out.");
|
die("Logged out.");
|
||||||
default:
|
default:
|
||||||
die("Invalid action");
|
die("Invalid action");
|
||||||
|
35
api.php
35
api.php
@ -4,37 +4,6 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple JSON API to allow other apps to access data from this app.
|
|
||||||
*
|
|
||||||
* Requests can be sent via either GET or POST requests. POST is recommended
|
|
||||||
* as it has a lower chance of being logged on the server, exposing unencrypted
|
|
||||||
* user passwords.
|
|
||||||
*/
|
|
||||||
require __DIR__ . '/required.php';
|
|
||||||
require_once __DIR__ . '/lib/login.php';
|
|
||||||
require_once __DIR__ . '/lib/userinfo.php';
|
|
||||||
header("Content-Type: application/json");
|
|
||||||
|
|
||||||
$username = $VARS['username'];
|
// Load in new API from legacy location (a.k.a. here)
|
||||||
$password = $VARS['password'];
|
require __DIR__ . "/api/index.php";
|
||||||
if (user_exists($username) !== true || authenticate_user($username, $password, $errmsg) !== true || account_has_permission($username, "ADMIN") !== true) {
|
|
||||||
header("HTTP/1.1 403 Unauthorized");
|
|
||||||
die("\"403 Unauthorized\"");
|
|
||||||
}
|
|
||||||
$userinfo = getUserByUsername($username);
|
|
||||||
|
|
||||||
// query max results
|
|
||||||
$max = 20;
|
|
||||||
if (preg_match("/^[0-9]+$/", $VARS['max']) === 1 && $VARS['max'] <= 1000) {
|
|
||||||
$max = (int) $VARS['max'];
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($VARS['action']) {
|
|
||||||
case "ping":
|
|
||||||
$out = ["status" => "OK", "maxresults" => $max, "pong" => true];
|
|
||||||
exit(json_encode($out));
|
|
||||||
default:
|
|
||||||
header("HTTP/1.1 400 Bad Request");
|
|
||||||
die("\"400 Bad Request\"");
|
|
||||||
}
|
|
||||||
|
5
api/.htaccess
Normal file
5
api/.htaccess
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Rewrite for Nextcloud Notes API
|
||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
RewriteEngine on
|
||||||
|
RewriteRule ([a-zA-Z0-9]+) index.php?action=$1 [PT]
|
||||||
|
</IfModule>
|
9
api/actions/ping.php
Normal file
9
api/actions/ping.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sendJsonResp();
|
15
api/apisettings.php
Normal file
15
api/apisettings.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$APIS = [
|
||||||
|
"ping" => [
|
||||||
|
"load" => "ping.php",
|
||||||
|
"vars" => [
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
144
api/functions.php
Normal file
144
api/functions.php
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build and send a simple JSON response.
|
||||||
|
* @param string $msg A message
|
||||||
|
* @param string $status "OK" or "ERROR"
|
||||||
|
* @param array $data More JSON data
|
||||||
|
*/
|
||||||
|
function sendJsonResp(string $msg = null, string $status = "OK", array $data = null) {
|
||||||
|
$resp = [];
|
||||||
|
if (!is_null($data)) {
|
||||||
|
$resp = $data;
|
||||||
|
}
|
||||||
|
if (!is_null($msg)) {
|
||||||
|
$resp["msg"] = $msg;
|
||||||
|
}
|
||||||
|
$resp["status"] = $status;
|
||||||
|
header("Content-Type: application/json");
|
||||||
|
exit(json_encode($resp));
|
||||||
|
}
|
||||||
|
|
||||||
|
function exitWithJson(array $json) {
|
||||||
|
header("Content-Type: application/json");
|
||||||
|
exit(json_encode($json));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the API key with most of the characters replaced with *s.
|
||||||
|
* @global string $key
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function getCensoredKey() {
|
||||||
|
global $key;
|
||||||
|
$resp = $key;
|
||||||
|
if (strlen($key) > 5) {
|
||||||
|
for ($i = 2; $i < strlen($key) - 2; $i++) {
|
||||||
|
$resp[$i] = "*";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the request is allowed
|
||||||
|
* @global array $VARS
|
||||||
|
* @return bool true if the request should continue, false if the request is bad
|
||||||
|
*/
|
||||||
|
function authenticate(): bool {
|
||||||
|
global $VARS;
|
||||||
|
// HTTP basic auth
|
||||||
|
if (!empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW'])) {
|
||||||
|
$user = User::byUsername($_SERVER['PHP_AUTH_USER']);
|
||||||
|
if (!$user->checkPassword($_SERVER['PHP_AUTH_PW'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Form auth
|
||||||
|
if (empty($VARS['username']) || empty($VARS['password'])) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
$username = $VARS['username'];
|
||||||
|
$password = $VARS['password'];
|
||||||
|
$user = User::byUsername($username);
|
||||||
|
if ($user->exists() !== true || Login::auth($username, $password) !== Login::LOGIN_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the User whose credentials were used to make the request.
|
||||||
|
*/
|
||||||
|
function getRequestUser(): User {
|
||||||
|
global $VARS;
|
||||||
|
if (!empty($_SERVER['PHP_AUTH_USER'])) {
|
||||||
|
return User::byUsername($_SERVER['PHP_AUTH_USER']);
|
||||||
|
} else {
|
||||||
|
return User::byUsername($VARS['username']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkVars($vars, $or = false) {
|
||||||
|
global $VARS;
|
||||||
|
$ok = [];
|
||||||
|
foreach ($vars as $key => $val) {
|
||||||
|
if (strpos($key, "OR") === 0) {
|
||||||
|
checkVars($vars[$key], true);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only check type of optional variables if they're set, and don't
|
||||||
|
// mark them as bad if they're not set
|
||||||
|
if (strpos($key, " (optional)") !== false) {
|
||||||
|
$key = str_replace(" (optional)", "", $key);
|
||||||
|
if (empty($VARS[$key])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (empty($VARS[$key])) {
|
||||||
|
$ok[$key] = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strpos($val, "/") === 0) {
|
||||||
|
// regex
|
||||||
|
$ok[$key] = preg_match($val, $VARS[$key]) === 1;
|
||||||
|
} else {
|
||||||
|
$checkmethod = "is_$val";
|
||||||
|
$ok[$key] = !($checkmethod($VARS[$key]) !== true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($or) {
|
||||||
|
$success = false;
|
||||||
|
$bad = "";
|
||||||
|
foreach ($ok as $k => $v) {
|
||||||
|
if ($v) {
|
||||||
|
$success = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
$bad = $k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$success) {
|
||||||
|
http_response_code(400);
|
||||||
|
die("400 Bad request: variable $bad is missing or invalid");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach ($ok as $key => $bool) {
|
||||||
|
if (!$bool) {
|
||||||
|
http_response_code(400);
|
||||||
|
die("400 Bad request: variable $key is missing or invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
79
api/index.php
Normal file
79
api/index.php
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
require __DIR__ . '/../required.php';
|
||||||
|
require __DIR__ . '/functions.php';
|
||||||
|
require __DIR__ . '/apisettings.php';
|
||||||
|
|
||||||
|
$VARS = $_GET;
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] != "GET") {
|
||||||
|
$VARS = array_merge($VARS, $_POST);
|
||||||
|
}
|
||||||
|
|
||||||
|
$requestbody = file_get_contents('php://input');
|
||||||
|
$requestjson = json_decode($requestbody, TRUE);
|
||||||
|
if (json_last_error() == JSON_ERROR_NONE) {
|
||||||
|
$VARS = array_merge($VARS, $requestjson);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're not using the old api.php file, allow more flexible requests
|
||||||
|
if (strpos($_SERVER['REQUEST_URI'], "/api.php") === FALSE) {
|
||||||
|
$route = explode("/", substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], "api/") + 4));
|
||||||
|
|
||||||
|
if (count($route) >= 1) {
|
||||||
|
$VARS["action"] = $route[0];
|
||||||
|
}
|
||||||
|
if (count($route) >= 2 && strpos($route[1], "?") !== 0) {
|
||||||
|
for ($i = 1; $i < count($route); $i++) {
|
||||||
|
if (empty($route[$i]) || strpos($route[$i], "=") === false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$key = explode("=", $route[$i], 2)[0];
|
||||||
|
$val = explode("=", $route[$i], 2)[1];
|
||||||
|
$VARS[$key] = $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strpos($route[count($route) - 1], "?") === 0) {
|
||||||
|
$morevars = explode("&", substr($route[count($route) - 1], 1));
|
||||||
|
foreach ($morevars as $var) {
|
||||||
|
$key = explode("=", $var, 2)[0];
|
||||||
|
$val = explode("=", $var, 2)[1];
|
||||||
|
$VARS[$key] = $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!authenticate()) {
|
||||||
|
header('WWW-Authenticate: Basic realm="' . $SETTINGS['site_title'] . '"');
|
||||||
|
header('HTTP/1.1 401 Unauthorized');
|
||||||
|
die("401 Unauthorized: you need to supply valid credentials.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($VARS['action'])) {
|
||||||
|
http_response_code(404);
|
||||||
|
die("404 No action specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($APIS[$VARS['action']])) {
|
||||||
|
http_response_code(404);
|
||||||
|
die("404 Action not defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
$APIACTION = $APIS[$VARS["action"]];
|
||||||
|
|
||||||
|
if (!file_exists(__DIR__ . "/actions/" . $APIACTION["load"])) {
|
||||||
|
http_response_code(404);
|
||||||
|
die("404 Action not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($APIACTION["vars"])) {
|
||||||
|
checkVars($APIACTION["vars"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once __DIR__ . "/actions/" . $APIACTION["load"];
|
40
app.php
40
app.php
@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
@ -14,7 +13,7 @@ if ($_SESSION['loggedin'] != true) {
|
|||||||
require_once __DIR__ . "/pages.php";
|
require_once __DIR__ . "/pages.php";
|
||||||
|
|
||||||
$pageid = "home";
|
$pageid = "home";
|
||||||
if (isset($_GET['page']) && !is_empty($_GET['page'])) {
|
if (!empty($_GET['page'])) {
|
||||||
$pg = strtolower($_GET['page']);
|
$pg = strtolower($_GET['page']);
|
||||||
$pg = preg_replace('/[^0-9a-z_]/', "", $pg);
|
$pg = preg_replace('/[^0-9a-z_]/', "", $pg);
|
||||||
if (array_key_exists($pg, PAGES) && file_exists(__DIR__ . "/pages/" . $pg . ".php")) {
|
if (array_key_exists($pg, PAGES) && file_exists(__DIR__ . "/pages/" . $pg . ".php")) {
|
||||||
@ -28,10 +27,10 @@ header("Link: <static/fonts/Roboto.css>; rel=preload; as=style", false);
|
|||||||
header("Link: <static/css/bootstrap.min.css>; rel=preload; as=style", false);
|
header("Link: <static/css/bootstrap.min.css>; rel=preload; as=style", false);
|
||||||
header("Link: <static/css/material-color/material-color.min.css>; rel=preload; as=style", false);
|
header("Link: <static/css/material-color/material-color.min.css>; rel=preload; as=style", false);
|
||||||
header("Link: <static/css/app.css>; rel=preload; as=style", false);
|
header("Link: <static/css/app.css>; rel=preload; as=style", false);
|
||||||
header("Link: <static/css/fa-svg-with-js.css>; rel=preload; as=style", false);
|
header("Link: <static/css/svg-with-js.min.css>; rel=preload; as=style", false);
|
||||||
header("Link: <static/js/fontawesome-all.min.js>; rel=preload; as=script", false);
|
header("Link: <static/js/fontawesome-all.min.js>; rel=preload; as=script", false);
|
||||||
header("Link: <static/js/jquery-3.3.1.min.js>; rel=preload; as=script", false);
|
header("Link: <static/js/jquery-3.3.1.min.js>; rel=preload; as=script", false);
|
||||||
header("Link: <static/js/bootstrap.min.js>; rel=preload; as=script", false);
|
header("Link: <static/js/bootstrap.bundle.min.js>; rel=preload; as=script", false);
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
@ -40,14 +39,14 @@ header("Link: <static/js/bootstrap.min.js>; rel=preload; as=script", false);
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
<title><?php echo SITE_TITLE; ?></title>
|
<title><?php echo $SETTINGS['site_title']; ?></title>
|
||||||
|
|
||||||
<link rel="icon" href="static/img/logo.svg">
|
<link rel="icon" href="static/img/logo.svg">
|
||||||
|
|
||||||
<link href="static/css/bootstrap.min.css" rel="stylesheet">
|
<link href="static/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link href="static/css/material-color/material-color.min.css" rel="stylesheet">
|
<link href="static/css/material-color/material-color.min.css" rel="stylesheet">
|
||||||
<link href="static/css/app.css" rel="stylesheet">
|
<link href="static/css/app.css" rel="stylesheet">
|
||||||
<link href="static/css/fa-svg-with-js.css" rel="stylesheet">
|
<link href="static/css/svg-with-js.min.css" rel="stylesheet">
|
||||||
<script nonce="<?php echo $SECURE_NONCE; ?>">
|
<script nonce="<?php echo $SECURE_NONCE; ?>">
|
||||||
FontAwesomeConfig = {autoAddCss: false}
|
FontAwesomeConfig = {autoAddCss: false}
|
||||||
</script>
|
</script>
|
||||||
@ -66,12 +65,13 @@ header("Link: <static/js/bootstrap.min.js>; rel=preload; as=script", false);
|
|||||||
|
|
||||||
<?php
|
<?php
|
||||||
// Alert messages
|
// Alert messages
|
||||||
if (isset($_GET['msg']) && !is_empty($_GET['msg']) && array_key_exists($_GET['msg'], MESSAGES)) {
|
if (!empty($_GET['msg'])) {
|
||||||
|
if (array_key_exists($_GET['msg'], MESSAGES)) {
|
||||||
// optional string generation argument
|
// optional string generation argument
|
||||||
if (!isset($_GET['arg']) || is_empty($_GET['arg'])) {
|
if (empty($_GET['arg'])) {
|
||||||
$alertmsg = lang(MESSAGES[$_GET['msg']]['string'], false);
|
$alertmsg = $Strings->get(MESSAGES[$_GET['msg']]['string'], false);
|
||||||
} else {
|
} else {
|
||||||
$alertmsg = lang2(MESSAGES[$_GET['msg']]['string'], ["arg" => strip_tags($_GET['arg'])], false);
|
$alertmsg = $Strings->build(MESSAGES[$_GET['msg']]['string'], ["arg" => strip_tags($_GET['arg'])], false);
|
||||||
}
|
}
|
||||||
$alerttype = MESSAGES[$_GET['msg']]['type'];
|
$alerttype = MESSAGES[$_GET['msg']]['type'];
|
||||||
$alerticon = "square-o";
|
$alerticon = "square-o";
|
||||||
@ -89,6 +89,12 @@ header("Link: <static/js/bootstrap.min.js>; rel=preload; as=script", false);
|
|||||||
$alerticon = "check";
|
$alerticon = "check";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// We don't have a message for this, so just assume an error and escape stuff.
|
||||||
|
$alertmsg = htmlentities($Strings->get($_GET['msg'], false));
|
||||||
|
$alerticon = "times";
|
||||||
|
$alerttype = "danger";
|
||||||
|
}
|
||||||
echo <<<END
|
echo <<<END
|
||||||
<div class="row justify-content-center" id="msg-alert-box">
|
<div class="row justify-content-center" id="msg-alert-box">
|
||||||
<div class="col-11 col-sm-6 col-md-5 col-lg-4 col-xl-4">
|
<div class="col-11 col-sm-6 col-md-5 col-lg-4 col-xl-4">
|
||||||
@ -121,7 +127,7 @@ END;
|
|||||||
</button>
|
</button>
|
||||||
<a class="navbar-brand py-0 mr-auto" href="app.php">
|
<a class="navbar-brand py-0 mr-auto" href="app.php">
|
||||||
<img src="static/img/logo.svg" alt="" class="d-none d-<?php echo $navbar_breakpoint; ?>-inline brand-img py-0" />
|
<img src="static/img/logo.svg" alt="" class="d-none d-<?php echo $navbar_breakpoint; ?>-inline brand-img py-0" />
|
||||||
<?php echo SITE_TITLE; ?>
|
<?php echo $SETTINGS['site_title']; ?>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="collapse navbar-collapse py-0" id="navbar-collapse">
|
<div class="collapse navbar-collapse py-0" id="navbar-collapse">
|
||||||
@ -146,7 +152,7 @@ END;
|
|||||||
if (isset($pg['icon'])) {
|
if (isset($pg['icon'])) {
|
||||||
?><i class="<?php echo $pg['icon']; ?> fa-fw"></i> <?php
|
?><i class="<?php echo $pg['icon']; ?> fa-fw"></i> <?php
|
||||||
}
|
}
|
||||||
lang($pg['title']);
|
$Strings->get($pg['title']);
|
||||||
?>
|
?>
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
@ -157,13 +163,13 @@ END;
|
|||||||
</div>
|
</div>
|
||||||
<div class="navbar-nav ml-auto py-0" id="navbar-right">
|
<div class="navbar-nav ml-auto py-0" id="navbar-right">
|
||||||
<span class="nav-item py-<?php echo $navbar_breakpoint; ?>-0">
|
<span class="nav-item py-<?php echo $navbar_breakpoint; ?>-0">
|
||||||
<a class="nav-link py-<?php echo $navbar_breakpoint; ?>-0" href="<?php echo PORTAL_URL; ?>">
|
<a class="nav-link py-<?php echo $navbar_breakpoint; ?>-0" href="<?php echo $SETTINGS['accounthub']['home']; ?>">
|
||||||
<i class="fas fa-user fa-fw"></i><span> <?php echo $_SESSION['realname'] ?></span>
|
<i class="fas fa-user fa-fw"></i><span> <?php echo $_SESSION['realname'] ?></span>
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
<span class="nav-item mr-auto py-<?php echo $navbar_breakpoint; ?>-0">
|
<span class="nav-item mr-auto py-<?php echo $navbar_breakpoint; ?>-0">
|
||||||
<a class="nav-link py-<?php echo $navbar_breakpoint; ?>-0" href="action.php?action=signout">
|
<a class="nav-link py-<?php echo $navbar_breakpoint; ?>-0" href="action.php?action=signout">
|
||||||
<i class="fas fa-sign-out-alt fa-fw"></i><span> <?php lang("sign out") ?></span>
|
<i class="fas fa-sign-out-alt fa-fw"></i><span> <?php $Strings->get("sign out") ?></span>
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -177,12 +183,12 @@ END;
|
|||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<?php echo FOOTER_TEXT; ?><br />
|
<?php echo $SETTINGS['footer_text']; ?><br />
|
||||||
Copyright © <?php echo date('Y'); ?> <?php echo COPYRIGHT_NAME; ?>
|
Copyright © <?php echo date('Y'); ?> <?php echo $SETTINGS['copyright']; ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="static/js/jquery-3.3.1.min.js"></script>
|
<script src="static/js/jquery-3.3.1.min.js"></script>
|
||||||
<script src="static/js/bootstrap.min.js"></script>
|
<script src="static/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="static/js/app.js"></script>
|
<script src="static/js/app.js"></script>
|
||||||
<?php
|
<?php
|
||||||
// custom page scripts
|
// custom page scripts
|
||||||
|
24
composer.lock
generated
24
composer.lock
generated
@ -9,16 +9,16 @@
|
|||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "catfan/medoo",
|
"name": "catfan/medoo",
|
||||||
"version": "v1.5.3",
|
"version": "v1.5.7",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/catfan/Medoo.git",
|
"url": "https://github.com/catfan/Medoo.git",
|
||||||
"reference": "1aa25a4001e0cfb739ba2996f00f4a3d2a7fdf07"
|
"reference": "8d90cba0e8ff176028847527d0ea76fe41a06ecf"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/catfan/Medoo/zipball/1aa25a4001e0cfb739ba2996f00f4a3d2a7fdf07",
|
"url": "https://api.github.com/repos/catfan/Medoo/zipball/8d90cba0e8ff176028847527d0ea76fe41a06ecf",
|
||||||
"reference": "1aa25a4001e0cfb739ba2996f00f4a3d2a7fdf07",
|
"reference": "8d90cba0e8ff176028847527d0ea76fe41a06ecf",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -64,20 +64,20 @@
|
|||||||
"sql",
|
"sql",
|
||||||
"sqlite"
|
"sqlite"
|
||||||
],
|
],
|
||||||
"time": "2017-12-25 17:02:41"
|
"time": "2018-06-14 18:59:08"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/guzzle",
|
"name": "guzzlehttp/guzzle",
|
||||||
"version": "6.3.0",
|
"version": "6.3.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/guzzle/guzzle.git",
|
"url": "https://github.com/guzzle/guzzle.git",
|
||||||
"reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699"
|
"reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/f4db5a78a5ea468d4831de7f0bf9d9415e348699",
|
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba",
|
||||||
"reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699",
|
"reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -87,7 +87,7 @@
|
|||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
"phpunit/phpunit": "^4.0 || ^5.0",
|
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
|
||||||
"psr/log": "^1.0"
|
"psr/log": "^1.0"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
@ -96,7 +96,7 @@
|
|||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "6.2-dev"
|
"dev-master": "6.3-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@ -129,7 +129,7 @@
|
|||||||
"rest",
|
"rest",
|
||||||
"web service"
|
"web service"
|
||||||
],
|
],
|
||||||
"time": "2017-06-22 18:50:49"
|
"time": "2018-04-22 15:46:56"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/promises",
|
"name": "guzzlehttp/promises",
|
||||||
|
243
index.php
243
index.php
@ -1,164 +1,131 @@
|
|||||||
<?php
|
<?php
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
require_once __DIR__ . "/required.php";
|
require_once __DIR__ . "/required.php";
|
||||||
|
|
||||||
require_once __DIR__ . "/lib/login.php";
|
|
||||||
|
|
||||||
// if we're logged in, we don't need to be here.
|
// if we're logged in, we don't need to be here.
|
||||||
if (!empty($_SESSION['loggedin']) && $_SESSION['loggedin'] === true && !isset($_GET['permissionerror'])) {
|
if (!empty($_SESSION['loggedin']) && $_SESSION['loggedin'] === true && !isset($_GET['permissionerror'])) {
|
||||||
header('Location: app.php');
|
header('Location: app.php');
|
||||||
|
die();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_GET['permissionerror'])) {
|
/**
|
||||||
$alert = lang("no access permission", false);
|
* Show a simple HTML page with a line of text and a button. Matches the UI of
|
||||||
}
|
* the AccountHub login flow.
|
||||||
|
*
|
||||||
/* Authenticate user */
|
* @global type $SETTINGS
|
||||||
$userpass_ok = false;
|
* @global type $SECURE_NONCE
|
||||||
$multiauth = false;
|
* @global type $Strings
|
||||||
if (checkLoginServer()) {
|
* @param string $title Text to show, passed through i18n
|
||||||
if (!empty($VARS['progress']) && $VARS['progress'] == "1") {
|
* @param string $button Button text, passed through i18n
|
||||||
if (!CAPTCHA_ENABLED || (CAPTCHA_ENABLED && verifyCaptcheck($VARS['captcheck_session_code'], $VARS['captcheck_selected_answer'], CAPTCHA_SERVER . "/api.php"))) {
|
* @param string $url URL for the button
|
||||||
$errmsg = "";
|
*/
|
||||||
if (authenticate_user($VARS['username'], $VARS['password'], $errmsg)) {
|
function showHTML(string $title, string $button, string $url) {
|
||||||
switch (get_account_status($VARS['username'])) {
|
global $SETTINGS, $SECURE_NONCE, $Strings;
|
||||||
case "LOCKED_OR_DISABLED":
|
?>
|
||||||
$alert = lang("account locked", false);
|
<!DOCTYPE html>
|
||||||
break;
|
|
||||||
case "TERMINATED":
|
|
||||||
$alert = lang("account terminated", false);
|
|
||||||
break;
|
|
||||||
case "CHANGE_PASSWORD":
|
|
||||||
$alert = lang("password expired", false);
|
|
||||||
case "NORMAL":
|
|
||||||
$userpass_ok = true;
|
|
||||||
break;
|
|
||||||
case "ALERT_ON_ACCESS":
|
|
||||||
sendLoginAlertEmail($VARS['username']);
|
|
||||||
$userpass_ok = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ($userpass_ok) {
|
|
||||||
$_SESSION['passok'] = true; // stop logins using only username and authcode
|
|
||||||
if (userHasTOTP($VARS['username'])) {
|
|
||||||
$multiauth = true;
|
|
||||||
} else {
|
|
||||||
doLoginUser($VARS['username'], $VARS['password']);
|
|
||||||
header('Location: app.php');
|
|
||||||
die("Logged in, go to app.php");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!is_empty($errmsg)) {
|
|
||||||
$alert = lang2("login server error", ['arg' => $errmsg], false);
|
|
||||||
} else {
|
|
||||||
$alert = lang("login incorrect", false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$alert = lang("captcha error", false);
|
|
||||||
}
|
|
||||||
} else if (!empty($VARS['progress']) && $VARS['progress'] == "2") {
|
|
||||||
if ($_SESSION['passok'] !== true) {
|
|
||||||
// stop logins using only username and authcode
|
|
||||||
sendError("Password integrity check failed!");
|
|
||||||
}
|
|
||||||
if (verifyTOTP($VARS['username'], $VARS['authcode'])) {
|
|
||||||
if (doLoginUser($VARS['username'])) {
|
|
||||||
header('Location: app.php');
|
|
||||||
die("Logged in, go to app.php");
|
|
||||||
} else {
|
|
||||||
$alert = lang("login server user data error", false);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$alert = lang("2fa incorrect", false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$alert = lang("login server unavailable", false);
|
|
||||||
}
|
|
||||||
header("Link: <static/fonts/Roboto.css>; rel=preload; as=style", false);
|
|
||||||
header("Link: <static/css/bootstrap.min.css>; rel=preload; as=style", false);
|
|
||||||
header("Link: <static/css/material-color/material-color.min.css>; rel=preload; as=style", false);
|
|
||||||
header("Link: <static/css/index.css>; rel=preload; as=style", false);
|
|
||||||
header("Link: <static/js/jquery-3.3.1.min.js>; rel=preload; as=script", false);
|
|
||||||
header("Link: <static/js/bootstrap.min.js>; rel=preload; as=script", false);
|
|
||||||
?>
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
<title><?php echo SITE_TITLE; ?></title>
|
<title><?php echo $SETTINGS['site_title']; ?></title>
|
||||||
|
|
||||||
<link rel="icon" href="static/img/logo.svg">
|
<link rel="icon" href="static/img/logo.svg">
|
||||||
|
|
||||||
<link href="static/css/bootstrap.min.css" rel="stylesheet">
|
<link href="static/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link href="static/css/material-color/material-color.min.css" rel="stylesheet">
|
<style nonce="<?php echo $SECURE_NONCE; ?>">
|
||||||
<link href="static/css/index.css" rel="stylesheet">
|
.display-5 {
|
||||||
<?php if (CAPTCHA_ENABLED) { ?>
|
font-size: 2.5rem;
|
||||||
<script src="<?php echo CAPTCHA_SERVER ?>/captcheck.dist.js"></script>
|
font-weight: 300;
|
||||||
<?php } ?>
|
line-height: 1.2;
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="col-auto">
|
|
||||||
<img class="banner-image" src="static/img/logo.svg" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="card col-11 col-xs-11 col-sm-8 col-md-6 col-lg-4">
|
|
||||||
<div class="card-body">
|
|
||||||
<h5 class="card-title"><?php lang("sign in"); ?></h5>
|
|
||||||
<form action="" method="POST">
|
|
||||||
<?php
|
|
||||||
if (!empty($alert)) {
|
|
||||||
?>
|
|
||||||
<div class="alert alert-danger">
|
|
||||||
<i class="fa fa-fw fa-exclamation-triangle"></i> <?php echo $alert; ?>
|
|
||||||
</div>
|
|
||||||
<?php
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($multiauth != true) {
|
.banner-image {
|
||||||
?>
|
max-height: 100px;
|
||||||
<input type="text" class="form-control" name="username" placeholder="<?php lang("username"); ?>" required="required" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" autofocus /><br />
|
margin: 2em auto;
|
||||||
<input type="password" class="form-control" name="password" placeholder="<?php lang("password"); ?>" required="required" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" /><br />
|
border: 1px solid grey;
|
||||||
<?php if (CAPTCHA_ENABLED) { ?>
|
border-radius: 15%;
|
||||||
<div class="captcheck_container" data-stylenonce="<?php echo $SECURE_NONCE; ?>"></div>
|
|
||||||
<br />
|
|
||||||
<?php } ?>
|
|
||||||
<input type="hidden" name="progress" value="1" />
|
|
||||||
<?php
|
|
||||||
} else if ($multiauth) {
|
|
||||||
?>
|
|
||||||
<div class="alert alert-info">
|
|
||||||
<?php lang("2fa prompt"); ?>
|
|
||||||
</div>
|
|
||||||
<input type="text" class="form-control" name="authcode" placeholder="<?php lang("authcode"); ?>" required="required" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" autofocus /><br />
|
|
||||||
<input type="hidden" name="progress" value="2" />
|
|
||||||
<input type="hidden" name="username" value="<?php echo $VARS['username']; ?>" />
|
|
||||||
<?php
|
|
||||||
}
|
}
|
||||||
?>
|
</style>
|
||||||
<button type="submit" class="btn btn-primary">
|
|
||||||
<?php lang("continue"); ?>
|
<div class="container mt-4">
|
||||||
</button>
|
<div class="row justify-content-center">
|
||||||
</form>
|
<div class="col-12 text-center">
|
||||||
|
<img class="banner-image" src="./static/img/logo.svg" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 text-center">
|
||||||
|
<h1 class="display-5 mb-4"><?php $Strings->get($title); ?></h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-sm-8 col-lg-6">
|
||||||
|
<div class="card mt-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<a href="<?php echo $url; ?>" class="btn btn-primary btn-block"><?php $Strings->get($button); ?></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
|
||||||
<?php echo FOOTER_TEXT; ?><br />
|
|
||||||
Copyright © <?php echo date('Y'); ?> <?php echo COPYRIGHT_NAME; ?>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="static/js/jquery-3.3.1.min.js"></script>
|
<?php
|
||||||
<script src="static/js/bootstrap.min.js"></script>
|
}
|
||||||
</body>
|
|
||||||
</html>
|
if (!empty($_GET['logout'])) {
|
||||||
|
showHTML("You have been logged out.", "Log in again", "./index.php");
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
if (empty($_SESSION["login_code"])) {
|
||||||
|
$redirecttologin = true;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
$uidinfo = AccountHubApi::get("checkloginkey", ["code" => $_SESSION["login_code"]]);
|
||||||
|
if ($uidinfo["status"] == "ERROR") {
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
if (is_numeric($uidinfo['uid'])) {
|
||||||
|
$user = new User($uidinfo['uid'] * 1);
|
||||||
|
foreach ($SETTINGS['permissions'] as $perm) {
|
||||||
|
if (!$user->hasPermission($perm)) {
|
||||||
|
showHTML("no access permission", "sign out", "./action.php?action=signout");
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Session::start($user);
|
||||||
|
$_SESSION["login_code"] = null;
|
||||||
|
header('Location: app.php');
|
||||||
|
showHTML("Logged in", "Continue", "./app.php");
|
||||||
|
die();
|
||||||
|
} else {
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
$redirecttologin = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($redirecttologin) {
|
||||||
|
try {
|
||||||
|
$urlbase = (isset($_SERVER['HTTPS']) ? "https" : "http") . "://" . $_SERVER['HTTP_HOST'] . (($_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) ? ":" . $_SERVER['SERVER_PORT'] : "");
|
||||||
|
$iconurl = $urlbase . str_replace("index.php", "", $_SERVER["REQUEST_URI"]) . "static/img/logo.svg";
|
||||||
|
$codedata = AccountHubApi::get("getloginkey", ["appname" => $SETTINGS["site_title"], "appicon" => $iconurl]);
|
||||||
|
|
||||||
|
if ($codedata['status'] != "OK") {
|
||||||
|
throw new Exception($Strings->get("login server unavailable", false));
|
||||||
|
}
|
||||||
|
|
||||||
|
$redirecturl = $urlbase . $_SERVER['REQUEST_URI'];
|
||||||
|
|
||||||
|
$_SESSION["login_code"] = $codedata["code"];
|
||||||
|
|
||||||
|
$locationurl = $codedata["loginurl"] . "?code=" . htmlentities($codedata["code"]) . "&redirect=" . htmlentities($redirecturl);
|
||||||
|
header("Location: $locationurl");
|
||||||
|
showHTML("Continue", "Continue", $locationurl);
|
||||||
|
die();
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
sendError($ex->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
140
lang/en_us.php
140
lang/en_us.php
@ -1,140 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
define("STRINGS", [
|
|
||||||
"sign in" => "Sign In",
|
|
||||||
"username" => "Username",
|
|
||||||
"password" => "Password",
|
|
||||||
"continue" => "Continue",
|
|
||||||
"authcode" => "Authentication code",
|
|
||||||
"2fa prompt" => "Enter the six-digit code from your mobile authenticator app.",
|
|
||||||
"2fa incorrect" => "Authentication code incorrect.",
|
|
||||||
"login incorrect" => "Login incorrect.",
|
|
||||||
"no admin permission" => "You do not have permission to access this system.",
|
|
||||||
"login server unavailable" => "Login server unavailable. Try again later or contact technical support.",
|
|
||||||
"account locked" => "This account has been disabled. Contact technical support.",
|
|
||||||
"password expired" => "You must change your password before continuing.",
|
|
||||||
"account terminated" => "Account terminated. Access denied.",
|
|
||||||
"account state error" => "Your account state is not stable. Log out, restart your browser, and try again.",
|
|
||||||
"welcome user" => "Welcome, {user}!",
|
|
||||||
"sign out" => "Sign out",
|
|
||||||
"settings" => "Settings",
|
|
||||||
"options" => "Options",
|
|
||||||
"404 error" => "404 Error",
|
|
||||||
"page not found" => "Page not found.",
|
|
||||||
"invalid parameters" => "Invalid request parameters.",
|
|
||||||
"login server error" => "The login server returned an error: {arg}",
|
|
||||||
"login server user data error" => "The login server refused to provide account information. Try again or contact technical support.",
|
|
||||||
"captcha error" => "There was a problem with the CAPTCHA (robot test). Try again.",
|
|
||||||
"no access permission" => "You do not have permission to access this system.",
|
|
||||||
"home" => "Home",
|
|
||||||
"users" => "Users",
|
|
||||||
"more" => "More",
|
|
||||||
"actions" => "Actions",
|
|
||||||
"name" => "Name",
|
|
||||||
"email" => "Email",
|
|
||||||
"status" => "Status",
|
|
||||||
"type" => "Type",
|
|
||||||
"new user" => "New User",
|
|
||||||
"total users" => "Total Users",
|
|
||||||
"view users" => "View Users",
|
|
||||||
"normal accounts" => "Normal Accounts",
|
|
||||||
"locked accounts" => "Locked Accounts",
|
|
||||||
"editing user" => "Editing {user}",
|
|
||||||
"invalid userid" => "Invalid user ID.",
|
|
||||||
"user saved" => "User saved.",
|
|
||||||
"adding user" => "Adding new user",
|
|
||||||
"placeholder name" => "John Doe",
|
|
||||||
"placeholder username" => "jdoe",
|
|
||||||
"placeholder email address" => "jdoe@example.com",
|
|
||||||
"placeholder password" => "swordfish",
|
|
||||||
"new password" => "New Password",
|
|
||||||
"non-local account warning" => "This account is not locally managed. Changes made here will not synchronize to the directory server and some attributes cannot be edited.",
|
|
||||||
"delete user" => "Delete User",
|
|
||||||
"really delete user" => "Are you sure you want to delete this user? This action cannot be reversed.",
|
|
||||||
"user deleted" => "User account deleted.",
|
|
||||||
"user does not exist" => "User does not exist.",
|
|
||||||
"logtime" => "Date/Time",
|
|
||||||
"logtype" => "Event Type",
|
|
||||||
"ip address" => "IP Address",
|
|
||||||
"other data" => "Other",
|
|
||||||
"security log" => "Security Log",
|
|
||||||
"event type reference" => "Event Type Reference",
|
|
||||||
"clear log" => "Clear Log",
|
|
||||||
"really clear log" => "Are you sure you want to purge the security log? This action cannot be reversed.",
|
|
||||||
"log cleared" => "Security log cleared.",
|
|
||||||
"removed n entries" => "Removed {n} entries",
|
|
||||||
"security log entries" => "Security Log Entries",
|
|
||||||
"view security log" => "View Security Log",
|
|
||||||
"managers" => "Managers",
|
|
||||||
"manager" => "Manager",
|
|
||||||
"employee" => "Employee",
|
|
||||||
"delete relationship" => "Delete Relationship",
|
|
||||||
"really delete relationship" => "Are you sure you want to remove this manager-employee relationship? This action cannot be reversed.",
|
|
||||||
"relationship deleted" => "Relationship deleted.",
|
|
||||||
"edit relationship" => "Edit Relationship",
|
|
||||||
"adding relationship" => "Adding Relationship",
|
|
||||||
"relationship added" => "Relationship added.",
|
|
||||||
"permissions" => "Permissions",
|
|
||||||
"permission" => "Permission",
|
|
||||||
"new permission" => "New Permission",
|
|
||||||
"delete permission" => "Delete Permission",
|
|
||||||
"adding permission" => "Adding Permission",
|
|
||||||
"user" => "User",
|
|
||||||
"permission does not exist" => "Permission does not exist: {arg}",
|
|
||||||
"really delete permission" => "Are you sure you want to revoke this permission?",
|
|
||||||
"permission added" => "Permission assigned.",
|
|
||||||
"permission deleted" => "Permission deleted.",
|
|
||||||
"remove 2fa" => "Reset 2FA",
|
|
||||||
"action performed by" => "Action performed by {user}",
|
|
||||||
"2fa removed" => "2-factor authentication removed.",
|
|
||||||
"2fa" => "2FA",
|
|
||||||
"show deleted" => "Show deleted",
|
|
||||||
"editing deleted account" => "You are editing an account marked as deleted. The account will be undeleted if you press Save.",
|
|
||||||
"manager assigned" => "Manager relationships saved.",
|
|
||||||
"manager does not exist" => "The selected manager username does not exist.",
|
|
||||||
"type to add a person" => "Type to add a person",
|
|
||||||
"employees" => "Employees",
|
|
||||||
"type to select a manager" => "Type to select a manager",
|
|
||||||
"select a manager to view or edit employees" => "Select a manager to view or edit the assigned employees.",
|
|
||||||
"report export" => "Reports/Export",
|
|
||||||
"report type" => "Report type",
|
|
||||||
"format" => "Format",
|
|
||||||
"generate report" => "Generate report",
|
|
||||||
"choose an option" => "Choose an option",
|
|
||||||
"csv file" => "CSV text file",
|
|
||||||
"ods file" => "ODS spreadsheet",
|
|
||||||
"html file" => "HTML web page",
|
|
||||||
"uid" => "User ID",
|
|
||||||
"manager name" => "Manager",
|
|
||||||
"manager username" => "Mgr. Username",
|
|
||||||
"employee name" => "Employee",
|
|
||||||
"employee username" => "Emp. Username",
|
|
||||||
"permission id" => "Perm. ID",
|
|
||||||
"permissions assigned" => "Permissions assigned.",
|
|
||||||
"type to select a user" => "Type to select a user",
|
|
||||||
"type to add a permission" => "Type to add a permission",
|
|
||||||
"Choose a permission" => "Choose a permission",
|
|
||||||
"select a user to view or edit permissions" => "Select a user to view or edit the assigned permissions.",
|
|
||||||
"group" => "Group",
|
|
||||||
"groups" => "Groups",
|
|
||||||
"group does not exist" => "That group does not exist.",
|
|
||||||
"group members updated" => "Group members updated.",
|
|
||||||
"group added" => "Group added.",
|
|
||||||
"group deleted" => "Group deleted.",
|
|
||||||
"group already exists" => "A group with that name already exists.",
|
|
||||||
"save" => "Save",
|
|
||||||
"next" => "Next",
|
|
||||||
"add" => "Add",
|
|
||||||
"delete" => "Delete",
|
|
||||||
"new group" => "New group",
|
|
||||||
"delete group" => "Delete group",
|
|
||||||
"enter group name" => "Group name",
|
|
||||||
"group management" => "Group Management",
|
|
||||||
"group assignments" => "Group Assignments",
|
|
||||||
"group id" => "Group ID",
|
|
||||||
"group name" => "Group Name"
|
|
||||||
]);
|
|
7
langs/en/core.json
Normal file
7
langs/en/core.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"sign out": "Sign out",
|
||||||
|
"404 error": "404 Error",
|
||||||
|
"page not found": "Page not found.",
|
||||||
|
"invalid parameters": "Invalid request parameters.",
|
||||||
|
"login server error": "The login server returned an error: {arg}"
|
||||||
|
}
|
8
langs/en/index.json
Normal file
8
langs/en/index.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"You have been logged out.": "You have been logged out.",
|
||||||
|
"Log in again": "Log in again",
|
||||||
|
"login server unavailable": "Login server unavailable. Try again later or contact technical support.",
|
||||||
|
"no access permission": "You do not have permission to access this system.",
|
||||||
|
"Logged in": "Logged in",
|
||||||
|
"Continue": "Continue"
|
||||||
|
}
|
9
langs/en/titles.json
Normal file
9
langs/en/titles.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"Home": "Home",
|
||||||
|
"Users": "Users",
|
||||||
|
"Groups": "Groups",
|
||||||
|
"Security": "Security",
|
||||||
|
"Security Log": "Security Log",
|
||||||
|
"Managers": "Managers",
|
||||||
|
"Permissions": "Permissions"
|
||||||
|
}
|
56
lib/AccountHubApi.lib.php
Normal file
56
lib/AccountHubApi.lib.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AccountHubApi {
|
||||||
|
|
||||||
|
public static function get(string $action, array $data = null, bool $throwex = false) {
|
||||||
|
global $SETTINGS;
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
"action" => $action,
|
||||||
|
"key" => $SETTINGS['accounthub']['key']
|
||||||
|
];
|
||||||
|
if (!is_null($data)) {
|
||||||
|
$content = array_merge($content, $data);
|
||||||
|
}
|
||||||
|
$options = [
|
||||||
|
'http' => [
|
||||||
|
'method' => 'POST',
|
||||||
|
'content' => json_encode($content),
|
||||||
|
'header' => "Content-Type: application/json\r\n" .
|
||||||
|
"Accept: application/json\r\n",
|
||||||
|
"ignore_errors" => true
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$context = stream_context_create($options);
|
||||||
|
$result = file_get_contents($SETTINGS['accounthub']['api'], false, $context);
|
||||||
|
$response = json_decode($result, true);
|
||||||
|
if ($result === false || !AccountHubApi::checkHttpRespCode($http_response_header) || json_last_error() != JSON_ERROR_NONE) {
|
||||||
|
if ($throwex) {
|
||||||
|
throw new Exception($result);
|
||||||
|
} else {
|
||||||
|
sendError($result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function checkHttpRespCode(array $headers): bool {
|
||||||
|
foreach ($headers as $header) {
|
||||||
|
if (preg_match("/HTTP\/[0-9]\.[0-9] [0-9]{3}.*/", $header)) {
|
||||||
|
$respcode = explode(" ", $header)[1] * 1;
|
||||||
|
if ($respcode >= 200 && $respcode < 300) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
13
lib/Exceptions.lib.php
Normal file
13
lib/Exceptions.lib.php
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class IncorrectPasswordException extends Exception {
|
||||||
|
public function __construct(string $message = "Incorrect password.", int $code = 0, \Throwable $previous = null) {
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
}
|
||||||
|
}
|
275
lib/FormBuilder.lib.php
Normal file
275
lib/FormBuilder.lib.php
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class FormBuilder {
|
||||||
|
|
||||||
|
private $items = [];
|
||||||
|
private $hiddenitems = [];
|
||||||
|
private $title = "";
|
||||||
|
private $icon = "";
|
||||||
|
private $buttons = [];
|
||||||
|
private $action = "action.php";
|
||||||
|
private $method = "POST";
|
||||||
|
private $id = "editform";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a form with autogenerated HTML.
|
||||||
|
*
|
||||||
|
* @param string $title Form title/heading
|
||||||
|
* @param string $icon FontAwesone icon next to the title.
|
||||||
|
* @param string $action URL to submit the form to.
|
||||||
|
* @param string $method Form submission method (POST, GET, etc.)
|
||||||
|
*/
|
||||||
|
public function __construct(string $title = "Untitled Form", string $icon = "fas fa-file-alt", string $action = "action.php", string $method = "POST") {
|
||||||
|
$this->title = $title;
|
||||||
|
$this->icon = $icon;
|
||||||
|
$this->action = $action;
|
||||||
|
$this->method = $method;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the title of the form.
|
||||||
|
* @param string $title
|
||||||
|
*/
|
||||||
|
public function setTitle(string $title) {
|
||||||
|
$this->title = $title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the icon for the form.
|
||||||
|
* @param string $icon FontAwesome icon (example: "fas fa-toilet-paper")
|
||||||
|
*/
|
||||||
|
public function setIcon(string $icon) {
|
||||||
|
$this->icon = $icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the URL the form will submit to.
|
||||||
|
* @param string $action
|
||||||
|
*/
|
||||||
|
public function setAction(string $action) {
|
||||||
|
$this->action = $action;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the form submission method (GET, POST, etc)
|
||||||
|
* @param string $method
|
||||||
|
*/
|
||||||
|
public function setMethod(string $method = "POST") {
|
||||||
|
$this->method = $method;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the form ID.
|
||||||
|
* @param string $id
|
||||||
|
*/
|
||||||
|
public function setID(string $id = "editform") {
|
||||||
|
$this->id = $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an input to the form.
|
||||||
|
*
|
||||||
|
* @param string $name Element name
|
||||||
|
* @param string $value Element value
|
||||||
|
* @param string $type Input type (text, number, date, select, tel...)
|
||||||
|
* @param bool $required If the element is required for form submission.
|
||||||
|
* @param string $id Element ID
|
||||||
|
* @param array $options Array of [value => text] pairs for a select element
|
||||||
|
* @param string $label Text label to display near the input
|
||||||
|
* @param string $icon FontAwesome icon (example: "fas fa-toilet-paper")
|
||||||
|
* @param int $width Bootstrap column width for the input, out of 12.
|
||||||
|
* @param int $minlength Minimum number of characters for the input.
|
||||||
|
* @param int $maxlength Maximum number of characters for the input.
|
||||||
|
* @param string $pattern Regex pattern for custom client-side validation.
|
||||||
|
* @param string $error Message to show if the input doesn't validate.
|
||||||
|
*/
|
||||||
|
public function addInput(string $name, string $value = "", string $type = "text", bool $required = true, string $id = null, array $options = null, string $label = "", string $icon = "", int $width = 4, int $minlength = 1, int $maxlength = 100, string $pattern = "", string $error = "") {
|
||||||
|
$item = [
|
||||||
|
"name" => $name,
|
||||||
|
"value" => $value,
|
||||||
|
"type" => $type,
|
||||||
|
"required" => $required,
|
||||||
|
"label" => $label,
|
||||||
|
"icon" => $icon,
|
||||||
|
"width" => $width,
|
||||||
|
"minlength" => $minlength,
|
||||||
|
"maxlength" => $maxlength
|
||||||
|
];
|
||||||
|
if (!empty($id)) {
|
||||||
|
$item["id"] = $id;
|
||||||
|
}
|
||||||
|
if (!empty($options) && $type == "select") {
|
||||||
|
$item["options"] = $options;
|
||||||
|
}
|
||||||
|
if (!empty($pattern)) {
|
||||||
|
$item["pattern"] = $pattern;
|
||||||
|
}
|
||||||
|
if (!empty($error)) {
|
||||||
|
$item["error"] = $error;
|
||||||
|
}
|
||||||
|
$this->items[] = $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a button to the form.
|
||||||
|
*
|
||||||
|
* @param string $text Text string to show on the button.
|
||||||
|
* @param string $icon FontAwesome icon to show next to the text.
|
||||||
|
* @param string $href If not null, the button will actually be a hyperlink.
|
||||||
|
* @param string $type Usually "button" or "submit". Ignored if $href is set.
|
||||||
|
* @param string $id The element ID.
|
||||||
|
* @param string $name The element name for the button.
|
||||||
|
* @param string $value The form value for the button. Ignored if $name is null.
|
||||||
|
* @param string $class The CSS classes for the button, if a standard success-colored one isn't right.
|
||||||
|
*/
|
||||||
|
public function addButton(string $text, string $icon = "", string $href = null, string $type = "button", string $id = null, string $name = null, string $value = "", string $class = "btn btn-success") {
|
||||||
|
$button = [
|
||||||
|
"text" => $text,
|
||||||
|
"icon" => $icon,
|
||||||
|
"class" => $class,
|
||||||
|
"type" => $type,
|
||||||
|
"id" => $id,
|
||||||
|
"href" => $href,
|
||||||
|
"name" => $name,
|
||||||
|
"value" => $value
|
||||||
|
];
|
||||||
|
$this->buttons[] = $button;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a hidden input.
|
||||||
|
* @param string $name
|
||||||
|
* @param string $value
|
||||||
|
*/
|
||||||
|
public function addHiddenInput(string $name, string $value) {
|
||||||
|
$this->hiddenitems[$name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the form HTML.
|
||||||
|
* @param bool $echo If false, returns HTML string instead of outputting it.
|
||||||
|
*/
|
||||||
|
public function generate(bool $echo = true) {
|
||||||
|
$html = <<<HTMLTOP
|
||||||
|
<form action="$this->action" method="$this->method" id="$this->id">
|
||||||
|
<div class="card">
|
||||||
|
<h3 class="card-header d-flex">
|
||||||
|
<div>
|
||||||
|
<i class="$this->icon"></i> $this->title
|
||||||
|
</div>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row">
|
||||||
|
HTMLTOP;
|
||||||
|
|
||||||
|
foreach ($this->items as $item) {
|
||||||
|
$required = $item["required"] ? "required" : "";
|
||||||
|
$id = empty($item["id"]) ? "" : "id=\"$item[id]\"";
|
||||||
|
$pattern = empty($item["pattern"]) ? "" : "pattern=\"$item[pattern]\"";
|
||||||
|
if (empty($item['type'])) {
|
||||||
|
$item['type'] = "text";
|
||||||
|
}
|
||||||
|
$itemhtml = "";
|
||||||
|
$itemlabel = "";
|
||||||
|
if ($item['type'] != "checkbox") {
|
||||||
|
$itemlabel = "<label class=\"mb-0\">$item[label]:</label>";
|
||||||
|
}
|
||||||
|
$strippedlabel = strip_tags($item['label']);
|
||||||
|
$itemhtml .= <<<ITEMTOP
|
||||||
|
\n\n <div class="col-12 col-md-$item[width]">
|
||||||
|
<div class="form-group mb-3">
|
||||||
|
$itemlabel
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text"><i class="$item[icon]"></i></span>
|
||||||
|
</div>
|
||||||
|
ITEMTOP;
|
||||||
|
switch ($item['type']) {
|
||||||
|
case "select":
|
||||||
|
$itemhtml .= <<<SELECT
|
||||||
|
\n <select class="form-control" name="$item[name]" aria-label="$strippedlabel" $required>
|
||||||
|
SELECT;
|
||||||
|
foreach ($item['options'] as $value => $label) {
|
||||||
|
$selected = "";
|
||||||
|
if (!empty($item['value']) && $value == $item['value']) {
|
||||||
|
$selected = " selected";
|
||||||
|
}
|
||||||
|
$itemhtml .= "\n <option value=\"$value\"$selected>$label</option>";
|
||||||
|
}
|
||||||
|
$itemhtml .= "\n </select>";
|
||||||
|
break;
|
||||||
|
case "checkbox":
|
||||||
|
$itemhtml .= <<<CHECKBOX
|
||||||
|
\n <div class="form-group form-check">
|
||||||
|
<input type="checkbox" name="$item[name]" $id class="form-check-input" value="$item[value]" $required aria-label="$strippedlabel">
|
||||||
|
<label class="form-check-label">$item[label]</label>
|
||||||
|
</div>
|
||||||
|
CHECKBOX;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$itemhtml .= <<<INPUT
|
||||||
|
\n <input type="$item[type]" name="$item[name]" $id class="form-control" aria-label="$strippedlabel" minlength="$item[minlength]" maxlength="$item[maxlength]" $pattern value="$item[value]" $required />
|
||||||
|
INPUT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($item["error"])) {
|
||||||
|
$itemhtml .= <<<ERROR
|
||||||
|
\n <div class="invalid-feedback">
|
||||||
|
$item[error]
|
||||||
|
</div>
|
||||||
|
ERROR;
|
||||||
|
}
|
||||||
|
$itemhtml .= <<<ITEMBOTTOM
|
||||||
|
\n </div>
|
||||||
|
</div>
|
||||||
|
</div>\n
|
||||||
|
ITEMBOTTOM;
|
||||||
|
$html .= $itemhtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
$html .= <<<HTMLBOTTOM
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
HTMLBOTTOM;
|
||||||
|
|
||||||
|
if (!empty($this->buttons)) {
|
||||||
|
$html .= "\n <div class=\"card-footer\">";
|
||||||
|
foreach ($this->buttons as $btn) {
|
||||||
|
$btnhtml = "";
|
||||||
|
$inner = "<i class=\"$btn[icon]\"></i> $btn[text]";
|
||||||
|
$id = empty($btn['id']) ? "" : "id=\"$btn[id]\"";
|
||||||
|
if (!empty($btn['href'])) {
|
||||||
|
$btnhtml = "<a href=\"$btn[href]\" class=\"$btn[class]\" $id>$inner</a>";
|
||||||
|
} else {
|
||||||
|
$name = empty($btn['name']) ? "" : "name=\"$btn[name]\"";
|
||||||
|
$value = (!empty($btn['name']) && !empty($btn['value'])) ? "value=\"$btn[value]\"" : "";
|
||||||
|
$btnhtml = "<button type=\"$btn[type]\" class=\"$btn[class]\" $id $name $value>$inner</button>";
|
||||||
|
}
|
||||||
|
$html .= "\n $btnhtml";
|
||||||
|
}
|
||||||
|
$html .= "\n </div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
$html .= "\n </div>";
|
||||||
|
foreach ($this->hiddenitems as $name => $value) {
|
||||||
|
$value = htmlentities($value);
|
||||||
|
$html .= "\n <input type=\"hidden\" name=\"$name\" value=\"$value\" />";
|
||||||
|
}
|
||||||
|
$html .= "\n</form>\n";
|
||||||
|
|
||||||
|
if ($echo) {
|
||||||
|
echo $html;
|
||||||
|
}
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
135
lib/IPUtils.lib.php
Normal file
135
lib/IPUtils.lib.php
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
class IPUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given ipv4 address is in a given cidr
|
||||||
|
* @param string $ip IP to check in IPV4 format eg. 127.0.0.1
|
||||||
|
* @param string $range IP/CIDR netmask eg. 127.0.0.0/24, also 127.0.0.1 is accepted and /32 assumed
|
||||||
|
* @return boolean true if the ip is in this range / false if not.
|
||||||
|
* @author Thorsten Ott <https://gist.github.com/tott/7684443>
|
||||||
|
*/
|
||||||
|
public static function ip4_in_cidr($ip, $cidr) {
|
||||||
|
if (strpos($cidr, '/') == false) {
|
||||||
|
$cidr .= '/32';
|
||||||
|
}
|
||||||
|
// $range is in IP/CIDR format eg 127.0.0.1/24
|
||||||
|
list( $cidr, $netmask ) = explode('/', $cidr, 2);
|
||||||
|
$range_decimal = ip2long($cidr);
|
||||||
|
$ip_decimal = ip2long($ip);
|
||||||
|
$wildcard_decimal = pow(2, ( 32 - $netmask)) - 1;
|
||||||
|
$netmask_decimal = ~ $wildcard_decimal;
|
||||||
|
return ( ( $ip_decimal & $netmask_decimal ) == ( $range_decimal & $netmask_decimal ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given ipv6 address is in a given cidr
|
||||||
|
* @param string $ip IP to check in IPV6 format
|
||||||
|
* @param string $cidr CIDR netmask
|
||||||
|
* @return boolean true if the IP is in this range, false otherwise.
|
||||||
|
* @author MW. <https://stackoverflow.com/a/7952169>
|
||||||
|
*/
|
||||||
|
public static function ip6_in_cidr($ip, $cidr) {
|
||||||
|
$address = inet_pton($ip);
|
||||||
|
$subnetAddress = inet_pton(explode("/", $cidr)[0]);
|
||||||
|
$subnetMask = explode("/", $cidr)[1];
|
||||||
|
|
||||||
|
$addr = str_repeat("f", $subnetMask / 4);
|
||||||
|
switch ($subnetMask % 4) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
$addr .= "8";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
$addr .= "c";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
$addr .= "e";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$addr = str_pad($addr, 32, '0');
|
||||||
|
$addr = pack("H*", $addr);
|
||||||
|
|
||||||
|
$binMask = $addr;
|
||||||
|
return ($address & $binMask) == $subnetAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the REMOTE_ADDR is on Cloudflare's network.
|
||||||
|
* @return boolean true if it is, otherwise false
|
||||||
|
*/
|
||||||
|
public static function validateCloudflare() {
|
||||||
|
if (filter_var($_SERVER["REMOTE_ADDR"], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
||||||
|
// Using IPv6
|
||||||
|
$cloudflare_ips_v6 = [
|
||||||
|
"2400:cb00::/32",
|
||||||
|
"2405:8100::/32",
|
||||||
|
"2405:b500::/32",
|
||||||
|
"2606:4700::/32",
|
||||||
|
"2803:f800::/32",
|
||||||
|
"2c0f:f248::/32",
|
||||||
|
"2a06:98c0::/29"
|
||||||
|
];
|
||||||
|
$valid = false;
|
||||||
|
foreach ($cloudflare_ips_v6 as $cidr) {
|
||||||
|
if (ip6_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) {
|
||||||
|
$valid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Using IPv4
|
||||||
|
$cloudflare_ips_v4 = [
|
||||||
|
"103.21.244.0/22",
|
||||||
|
"103.22.200.0/22",
|
||||||
|
"103.31.4.0/22",
|
||||||
|
"104.16.0.0/12",
|
||||||
|
"108.162.192.0/18",
|
||||||
|
"131.0.72.0/22",
|
||||||
|
"141.101.64.0/18",
|
||||||
|
"162.158.0.0/15",
|
||||||
|
"172.64.0.0/13",
|
||||||
|
"173.245.48.0/20",
|
||||||
|
"188.114.96.0/20",
|
||||||
|
"190.93.240.0/20",
|
||||||
|
"197.234.240.0/22",
|
||||||
|
"198.41.128.0/17"
|
||||||
|
];
|
||||||
|
$valid = false;
|
||||||
|
foreach ($cloudflare_ips_v4 as $cidr) {
|
||||||
|
if (ip4_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) {
|
||||||
|
$valid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a good guess at the client's real IP address.
|
||||||
|
*
|
||||||
|
* @return string Client IP or `0.0.0.0` if we can't find anything
|
||||||
|
*/
|
||||||
|
public static function getClientIP() {
|
||||||
|
// If CloudFlare is in the mix, we should use it.
|
||||||
|
// Check if the request is actually from CloudFlare before trusting it.
|
||||||
|
if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
|
||||||
|
if (validateCloudflare()) {
|
||||||
|
return $_SERVER["HTTP_CF_CONNECTING_IP"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_SERVER["REMOTE_ADDR"])) {
|
||||||
|
return $_SERVER["REMOTE_ADDR"];
|
||||||
|
}
|
||||||
|
|
||||||
|
return "0.0.0.0"; // This will not happen unless we aren't a web server
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
80
lib/Login.lib.php
Normal file
80
lib/Login.lib.php
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Login {
|
||||||
|
|
||||||
|
const BAD_USERPASS = 1;
|
||||||
|
const BAD_2FA = 2;
|
||||||
|
const ACCOUNT_DISABLED = 3;
|
||||||
|
const LOGIN_OK = 4;
|
||||||
|
|
||||||
|
public static function auth(string $username, string $password, string $twofa = ""): int {
|
||||||
|
global $database;
|
||||||
|
$username = strtolower($username);
|
||||||
|
|
||||||
|
$user = User::byUsername($username);
|
||||||
|
|
||||||
|
if (!$user->exists()) {
|
||||||
|
return Login::BAD_USERPASS;
|
||||||
|
}
|
||||||
|
if (!$user->checkPassword($password)) {
|
||||||
|
return Login::BAD_USERPASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->has2fa()) {
|
||||||
|
if (!$user->check2fa($twofa)) {
|
||||||
|
return Login::BAD_2FA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($user->getStatus()->get()) {
|
||||||
|
case AccountStatus::TERMINATED:
|
||||||
|
return Login::BAD_USERPASS;
|
||||||
|
case AccountStatus::LOCKED_OR_DISABLED:
|
||||||
|
return Login::ACCOUNT_DISABLED;
|
||||||
|
case AccountStatus::NORMAL:
|
||||||
|
default:
|
||||||
|
return Login::LOGIN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Login::LOGIN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the login server API for sanity
|
||||||
|
* @return boolean true if OK, else false
|
||||||
|
*/
|
||||||
|
public static function checkLoginServer() {
|
||||||
|
try {
|
||||||
|
$resp = AccountHubApi::get("ping");
|
||||||
|
if ($resp['status'] == "OK") {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given AccountHub API key is valid by attempting to
|
||||||
|
* access the API with it.
|
||||||
|
* @param String $key The API key to check
|
||||||
|
* @return boolean TRUE if the key is valid, FALSE if invalid or something went wrong
|
||||||
|
*/
|
||||||
|
function checkAPIKey($key) {
|
||||||
|
try {
|
||||||
|
$resp = AccountHubApi::get("ping", null, true);
|
||||||
|
return false;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
53
lib/Notifications.lib.php
Normal file
53
lib/Notifications.lib.php
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Notifications {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new notification.
|
||||||
|
* @global $database
|
||||||
|
* @param User $user
|
||||||
|
* @param string $title
|
||||||
|
* @param string $content
|
||||||
|
* @param string $timestamp If left empty, the current date and time will be used.
|
||||||
|
* @param string $url
|
||||||
|
* @param bool $sensitive If true, the notification is marked as containing sensitive content, and the $content might be hidden on lockscreens and other non-secure places.
|
||||||
|
* @return int The newly-created notification ID.
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function add(User $user, string $title, string $content, string $timestamp = "", string $url = "", bool $sensitive = false): int {
|
||||||
|
global $Strings;
|
||||||
|
if ($user->exists()) {
|
||||||
|
if (empty($title) || empty($content)) {
|
||||||
|
throw new Exception($Strings->get("invalid parameters", false));
|
||||||
|
}
|
||||||
|
|
||||||
|
$timestamp = date("Y-m-d H:i:s");
|
||||||
|
if (!empty($timestamp)) {
|
||||||
|
$timestamp = date("Y-m-d H:i:s", strtotime($timestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
$resp = AccountHubApi::get("addnotification", [
|
||||||
|
'uid' => $user->getUID(),
|
||||||
|
'title' => $title,
|
||||||
|
'content' => $content,
|
||||||
|
'timestamp' => $timestamp,
|
||||||
|
'url' => $url,
|
||||||
|
'sensitive' => $sensitive
|
||||||
|
]
|
||||||
|
);
|
||||||
|
if ($resp['status'] == "OK") {
|
||||||
|
return $resp['id'] * 1;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception($Strings->get("user does not exist", false));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
19
lib/Session.lib.php
Normal file
19
lib/Session.lib.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Session {
|
||||||
|
|
||||||
|
public static function start(User $user) {
|
||||||
|
$_SESSION['username'] = $user->getUsername();
|
||||||
|
$_SESSION['uid'] = $user->getUID();
|
||||||
|
$_SESSION['email'] = $user->getEmail();
|
||||||
|
$_SESSION['realname'] = $user->getName();
|
||||||
|
$_SESSION['loggedin'] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
122
lib/Strings.lib.php
Normal file
122
lib/Strings.lib.php
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides translated language strings.
|
||||||
|
*/
|
||||||
|
class Strings {
|
||||||
|
|
||||||
|
private $language = "en";
|
||||||
|
private $strings = [];
|
||||||
|
|
||||||
|
public function __construct($language = "en") {
|
||||||
|
if (!preg_match("/[a-zA-Z\_\-]+/", $language)) {
|
||||||
|
throw new Exception("Invalid language code $language");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->load("en");
|
||||||
|
|
||||||
|
if ($language == "en") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists(__DIR__ . "/../langs/$language/")) {
|
||||||
|
$this->language = $language;
|
||||||
|
$this->load($language);
|
||||||
|
} else {
|
||||||
|
trigger_error("Language $language could not be found.", E_USER_WARNING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load all JSON files for the specified language.
|
||||||
|
* @param string $language
|
||||||
|
*/
|
||||||
|
private function load(string $language) {
|
||||||
|
$files = glob(__DIR__ . "/../langs/$language/*.json");
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$strings = json_decode(file_get_contents($file), true);
|
||||||
|
foreach ($strings as $key => $val) {
|
||||||
|
if (array_key_exists($key, $this->strings)) {
|
||||||
|
trigger_error("Language key \"$key\" is defined more than once.", E_USER_WARNING);
|
||||||
|
}
|
||||||
|
$this->strings[$key] = $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add language strings dynamically.
|
||||||
|
* @param array $strings ["key" => "value", ...]
|
||||||
|
*/
|
||||||
|
public function addStrings(array $strings) {
|
||||||
|
foreach ($strings as $key => $val) {
|
||||||
|
$this->strings[$key] = $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I18N string getter. If the key isn't found, it outputs the key itself.
|
||||||
|
* @param string $key
|
||||||
|
* @param bool $echo True to echo the result, false to return it. Default is true.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get(string $key, bool $echo = true): string {
|
||||||
|
$str = $key;
|
||||||
|
if (array_key_exists($key, $this->strings)) {
|
||||||
|
$str = $this->strings[$key];
|
||||||
|
} else {
|
||||||
|
trigger_error("Language key \"$key\" does not exist in " . $this->language, E_USER_WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($echo) {
|
||||||
|
echo $str;
|
||||||
|
}
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I18N string getter (with builder). If the key doesn't exist, outputs the key itself.
|
||||||
|
* @param string $key
|
||||||
|
* @param array $replace key-value array of replacements.
|
||||||
|
* If the string value is "hello {abc}" and you give ["abc" => "123"], the
|
||||||
|
* result will be "hello 123".
|
||||||
|
* @param bool $echo True to echo the result, false to return it. Default is true.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function build(string $key, array $replace, bool $echo = true): string {
|
||||||
|
$str = $key;
|
||||||
|
if (array_key_exists($key, $this->strings)) {
|
||||||
|
$str = $this->strings[$key];
|
||||||
|
} else {
|
||||||
|
trigger_error("Language key \"$key\" does not exist in " . $this->language, E_USER_WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($replace as $find => $repl) {
|
||||||
|
$str = str_replace("{" . $find . "}", $repl, $str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($echo) {
|
||||||
|
echo $str;
|
||||||
|
}
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds and returns a JSON key:value string for the supplied array of keys.
|
||||||
|
* @param array $keys ["key1", "key2", ...]
|
||||||
|
*/
|
||||||
|
public function getJSON(array $keys): string {
|
||||||
|
$strings = [];
|
||||||
|
foreach ($keys as $k) {
|
||||||
|
$strings[$k] = $this->get($k, false);
|
||||||
|
}
|
||||||
|
return json_encode($strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,18 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
|
|
||||||
require_once __DIR__ . "/../required.php";
|
|
||||||
require_once __DIR__ . "/iputils.php";
|
|
||||||
|
|
||||||
dieifnotloggedin();
|
|
||||||
|
|
||||||
function insertAuthLog($type, $uid = null, $data = "") {
|
|
||||||
global $database;
|
|
||||||
// find IP address
|
|
||||||
$ip = getClientIP();
|
|
||||||
$database->insert("authlog", ['logtime' => date("Y-m-d H:i:s"), 'logtype' => $type, 'uid' => $uid, 'ip' => $ip, 'otherdata' => $data]);
|
|
||||||
}
|
|
@ -43,7 +43,7 @@ switch ($VARS['order'][0]['column']) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// search
|
// search
|
||||||
if (!is_empty($VARS['search']['value'])) {
|
if (!empty($VARS['search']['value'])) {
|
||||||
$filter = true;
|
$filter = true;
|
||||||
$wherenolimit = [
|
$wherenolimit = [
|
||||||
"OR" => [
|
"OR" => [
|
||||||
|
@ -34,7 +34,7 @@ switch ($VARS['order'][0]['column']) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// search
|
// search
|
||||||
if (!is_empty($VARS['search']['value'])) {
|
if (!empty($VARS['search']['value'])) {
|
||||||
$filter = true;
|
$filter = true;
|
||||||
$wherenolimit = [
|
$wherenolimit = [
|
||||||
"OR" => [
|
"OR" => [
|
||||||
@ -78,7 +78,7 @@ if ($filter) {
|
|||||||
}
|
}
|
||||||
$out['recordsFiltered'] = $recordsFiltered;
|
$out['recordsFiltered'] = $recordsFiltered;
|
||||||
for ($i = 0; $i < count($managers); $i++) {
|
for ($i = 0; $i < count($managers); $i++) {
|
||||||
$managers[$i]["delbtn"] = '<a class="btn btn-danger btn-xs" href="app.php?page=delmanager&mid=' . $managers[$i]['managerid'] . '&eid=' . $managers[$i]['employeeid'] . '"><i class="fa fa-trash"></i> ' . lang("delete", false) . '</a>';
|
$managers[$i]["delbtn"] = '<a class="btn btn-danger btn-xs" href="app.php?page=delmanager&mid=' . $managers[$i]['managerid'] . '&eid=' . $managers[$i]['employeeid'] . '"><i class="fa fa-trash"></i> ' . $Strings->get("delete", false) . '</a>';
|
||||||
}
|
}
|
||||||
$out['managers'] = $managers;
|
$out['managers'] = $managers;
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ switch ($VARS['order'][0]['column']) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// search
|
// search
|
||||||
if (!is_empty($VARS['search']['value'])) {
|
if (!empty($VARS['search']['value'])) {
|
||||||
$filter = true;
|
$filter = true;
|
||||||
$wherenolimit = [
|
$wherenolimit = [
|
||||||
"OR" => [
|
"OR" => [
|
||||||
@ -76,7 +76,7 @@ if ($filter) {
|
|||||||
}
|
}
|
||||||
$out['recordsFiltered'] = $recordsFiltered;
|
$out['recordsFiltered'] = $recordsFiltered;
|
||||||
for ($i = 0; $i < count($data); $i++) {
|
for ($i = 0; $i < count($data); $i++) {
|
||||||
$data[$i]["delbtn"] = '<a class="btn btn-danger btn-xs" href="app.php?page=delpermission&uid=' . $data[$i]['uid'] . '&pid=' . $data[$i]['permid'] . '"><i class="fa fa-trash"></i> ' . lang("delete", false) . '</a>';
|
$data[$i]["delbtn"] = '<a class="btn btn-danger btn-xs" href="app.php?page=delpermission&uid=' . $data[$i]['uid'] . '&pid=' . $data[$i]['permid'] . '"><i class="fa fa-trash"></i> ' . $Strings->get("delete", false) . '</a>';
|
||||||
}
|
}
|
||||||
$out['perms'] = $data;
|
$out['perms'] = $data;
|
||||||
|
|
||||||
|
@ -1,130 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
|
|
||||||
require __DIR__ . '/../required.php';
|
|
||||||
|
|
||||||
dieifnotloggedin();
|
|
||||||
|
|
||||||
header("Content-Type: application/json");
|
|
||||||
|
|
||||||
$show_deleted = false;
|
|
||||||
if ($VARS['show_deleted'] == 1) {
|
|
||||||
$show_deleted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$out = [];
|
|
||||||
|
|
||||||
$out['draw'] = intval($VARS['draw']);
|
|
||||||
|
|
||||||
if ($show_deleted) {
|
|
||||||
$out['recordsTotal'] = $database->count('accounts');
|
|
||||||
} else {
|
|
||||||
$out['recordsTotal'] = $database->count('accounts', ['deleted' => 0]);
|
|
||||||
}
|
|
||||||
$filter = false;
|
|
||||||
|
|
||||||
// sort
|
|
||||||
$order = null;
|
|
||||||
$sortby = "DESC";
|
|
||||||
if ($VARS['order'][0]['dir'] == 'asc') {
|
|
||||||
$sortby = "ASC";
|
|
||||||
}
|
|
||||||
switch ($VARS['order'][0]['column']) {
|
|
||||||
case 2:
|
|
||||||
$order = ["realname" => $sortby];
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
$order = ["username" => $sortby];
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
$order = ["email" => $sortby];
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
$order = ["authsecret" => $sortby];
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
$order = ["statuscode" => $sortby];
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
$order = ["typecode" => $sortby];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// search
|
|
||||||
if (!is_empty($VARS['search']['value'])) {
|
|
||||||
$filter = true;
|
|
||||||
if ($show_deleted) {
|
|
||||||
$wherenolimit = [
|
|
||||||
"OR" => [
|
|
||||||
"username[~]" => $VARS['search']['value'],
|
|
||||||
"realname[~]" => $VARS['search']['value'],
|
|
||||||
"email[~]" => $VARS['search']['value'],
|
|
||||||
"statuscode[~]" => $VARS['search']['value'],
|
|
||||||
"typecode[~]" => $VARS['search']['value']
|
|
||||||
]
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
$wherenolimit = [
|
|
||||||
"AND" => [
|
|
||||||
"OR" => [
|
|
||||||
"username[~]" => $VARS['search']['value'],
|
|
||||||
"realname[~]" => $VARS['search']['value'],
|
|
||||||
"email[~]" => $VARS['search']['value'],
|
|
||||||
"statuscode[~]" => $VARS['search']['value'],
|
|
||||||
"typecode[~]" => $VARS['search']['value']
|
|
||||||
],
|
|
||||||
"deleted" => 0
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
$where = $wherenolimit;
|
|
||||||
$where["LIMIT"] = [$VARS['start'], $VARS['length']];
|
|
||||||
} else {
|
|
||||||
$where = ["LIMIT" => [$VARS['start'], $VARS['length']]];
|
|
||||||
if (!$show_deleted) {
|
|
||||||
$where["deleted"] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!is_null($order)) {
|
|
||||||
$where["ORDER"] = $order;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$users = $database->select('accounts', [
|
|
||||||
"[>]acctstatus" => ['acctstatus' => 'statusid'],
|
|
||||||
"[>]accttypes" => ['accttype' => 'typeid']
|
|
||||||
], [
|
|
||||||
'uid',
|
|
||||||
'username',
|
|
||||||
'realname',
|
|
||||||
'email',
|
|
||||||
'authsecret (2fa)',
|
|
||||||
'acctstatus',
|
|
||||||
'statuscode',
|
|
||||||
'accttype',
|
|
||||||
'typecode',
|
|
||||||
'deleted'
|
|
||||||
], $where);
|
|
||||||
|
|
||||||
|
|
||||||
$out['status'] = "OK";
|
|
||||||
if ($filter) {
|
|
||||||
$recordsFiltered = $database->count('accounts', [
|
|
||||||
"[>]acctstatus" => ['acctstatus' => 'statusid'],
|
|
||||||
"[>]accttypes" => ['accttype' => 'typecode']
|
|
||||||
], 'uid', $wherenolimit);
|
|
||||||
} else {
|
|
||||||
$recordsFiltered = $out['recordsTotal'];
|
|
||||||
}
|
|
||||||
$out['recordsFiltered'] = $recordsFiltered;
|
|
||||||
for ($i = 0; $i < count($users); $i++) {
|
|
||||||
$users[$i]["2fa"] = (is_empty($users[$i]["2fa"]) ? false : true);
|
|
||||||
$users[$i]["editbtn"] = '<a class="btn btn-blue btn-sm" href="app.php?page=edituser&id=' . $users[$i]['uid'] . '"><i class="far fa-edit"></i> ' . lang("edit", false) . '</a>';
|
|
||||||
}
|
|
||||||
$out['users'] = $users;
|
|
||||||
|
|
||||||
echo json_encode($out);
|
|
131
lib/iputils.php
131
lib/iputils.php
@ -1,131 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a given ipv4 address is in a given cidr
|
|
||||||
* @param string $ip IP to check in IPV4 format eg. 127.0.0.1
|
|
||||||
* @param string $range IP/CIDR netmask eg. 127.0.0.0/24, also 127.0.0.1 is accepted and /32 assumed
|
|
||||||
* @return boolean true if the ip is in this range / false if not.
|
|
||||||
* @author Thorsten Ott <https://gist.github.com/tott/7684443>
|
|
||||||
*/
|
|
||||||
function ip4_in_cidr($ip, $cidr) {
|
|
||||||
if (strpos($cidr, '/') == false) {
|
|
||||||
$cidr .= '/32';
|
|
||||||
}
|
|
||||||
// $range is in IP/CIDR format eg 127.0.0.1/24
|
|
||||||
list( $cidr, $netmask ) = explode('/', $cidr, 2);
|
|
||||||
$range_decimal = ip2long($cidr);
|
|
||||||
$ip_decimal = ip2long($ip);
|
|
||||||
$wildcard_decimal = pow(2, ( 32 - $netmask)) - 1;
|
|
||||||
$netmask_decimal = ~ $wildcard_decimal;
|
|
||||||
return ( ( $ip_decimal & $netmask_decimal ) == ( $range_decimal & $netmask_decimal ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a given ipv6 address is in a given cidr
|
|
||||||
* @param string $ip IP to check in IPV6 format
|
|
||||||
* @param string $cidr CIDR netmask
|
|
||||||
* @return boolean true if the IP is in this range, false otherwise.
|
|
||||||
* @author MW. <https://stackoverflow.com/a/7952169>
|
|
||||||
*/
|
|
||||||
function ip6_in_cidr($ip, $cidr) {
|
|
||||||
$address = inet_pton($ip);
|
|
||||||
$subnetAddress = inet_pton(explode("/", $cidr)[0]);
|
|
||||||
$subnetMask = explode("/", $cidr)[1];
|
|
||||||
|
|
||||||
$addr = str_repeat("f", $subnetMask / 4);
|
|
||||||
switch ($subnetMask % 4) {
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
$addr .= "8";
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
$addr .= "c";
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
$addr .= "e";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$addr = str_pad($addr, 32, '0');
|
|
||||||
$addr = pack("H*", $addr);
|
|
||||||
|
|
||||||
$binMask = $addr;
|
|
||||||
return ($address & $binMask) == $subnetAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the REMOTE_ADDR is on Cloudflare's network.
|
|
||||||
* @return boolean true if it is, otherwise false
|
|
||||||
*/
|
|
||||||
function validateCloudflare() {
|
|
||||||
if (filter_var($_SERVER["REMOTE_ADDR"], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
|
||||||
// Using IPv6
|
|
||||||
$cloudflare_ips_v6 = [
|
|
||||||
"2400:cb00::/32",
|
|
||||||
"2405:8100::/32",
|
|
||||||
"2405:b500::/32",
|
|
||||||
"2606:4700::/32",
|
|
||||||
"2803:f800::/32",
|
|
||||||
"2c0f:f248::/32",
|
|
||||||
"2a06:98c0::/29"
|
|
||||||
];
|
|
||||||
$valid = false;
|
|
||||||
foreach ($cloudflare_ips_v6 as $cidr) {
|
|
||||||
if (ip6_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) {
|
|
||||||
$valid = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Using IPv4
|
|
||||||
$cloudflare_ips_v4 = [
|
|
||||||
"103.21.244.0/22",
|
|
||||||
"103.22.200.0/22",
|
|
||||||
"103.31.4.0/22",
|
|
||||||
"104.16.0.0/12",
|
|
||||||
"108.162.192.0/18",
|
|
||||||
"131.0.72.0/22",
|
|
||||||
"141.101.64.0/18",
|
|
||||||
"162.158.0.0/15",
|
|
||||||
"172.64.0.0/13",
|
|
||||||
"173.245.48.0/20",
|
|
||||||
"188.114.96.0/20",
|
|
||||||
"190.93.240.0/20",
|
|
||||||
"197.234.240.0/22",
|
|
||||||
"198.41.128.0/17"
|
|
||||||
];
|
|
||||||
$valid = false;
|
|
||||||
foreach ($cloudflare_ips_v4 as $cidr) {
|
|
||||||
if (ip4_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) {
|
|
||||||
$valid = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes a good guess at the client's real IP address.
|
|
||||||
*
|
|
||||||
* @return string Client IP or `0.0.0.0` if we can't find anything
|
|
||||||
*/
|
|
||||||
function getClientIP() {
|
|
||||||
// If CloudFlare is in the mix, we should use it.
|
|
||||||
// Check if the request is actually from CloudFlare before trusting it.
|
|
||||||
if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
|
|
||||||
if (validateCloudflare()) {
|
|
||||||
return $_SERVER["HTTP_CF_CONNECTING_IP"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($_SERVER["REMOTE_ADDR"])) {
|
|
||||||
return $_SERVER["REMOTE_ADDR"];
|
|
||||||
}
|
|
||||||
|
|
||||||
return "0.0.0.0"; // This will not happen unless we aren't a web server
|
|
||||||
}
|
|
402
lib/login.php
402
lib/login.php
@ -1,402 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Authentication and account functions. Connects to a Portal instance.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check the login server API for sanity
|
|
||||||
* @return boolean true if OK, else false
|
|
||||||
*/
|
|
||||||
function checkLoginServer() {
|
|
||||||
try {
|
|
||||||
$client = new GuzzleHttp\Client();
|
|
||||||
|
|
||||||
$response = $client
|
|
||||||
->request('POST', PORTAL_API, [
|
|
||||||
'form_params' => [
|
|
||||||
'key' => PORTAL_KEY,
|
|
||||||
'action' => "ping"
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() != 200) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$resp = json_decode($response->getBody(), TRUE);
|
|
||||||
if ($resp['status'] == "OK") {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (Exception $e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the given AccountHub API key is valid by attempting to
|
|
||||||
* access the API with it.
|
|
||||||
* @param String $key The API key to check
|
|
||||||
* @return boolean TRUE if the key is valid, FALSE if invalid or something went wrong
|
|
||||||
*/
|
|
||||||
function checkAPIKey($key) {
|
|
||||||
try {
|
|
||||||
$client = new GuzzleHttp\Client();
|
|
||||||
|
|
||||||
$response = $client
|
|
||||||
->request('POST', PORTAL_API, [
|
|
||||||
'form_params' => [
|
|
||||||
'key' => $key,
|
|
||||||
'action' => "ping"
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() === 200) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} catch (Exception $e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Account handling //
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the given credentials against the API.
|
|
||||||
* @param string $username
|
|
||||||
* @param string $password
|
|
||||||
* @return boolean True if OK, else false
|
|
||||||
*/
|
|
||||||
function authenticate_user($username, $password, &$errmsg) {
|
|
||||||
$client = new GuzzleHttp\Client();
|
|
||||||
|
|
||||||
$response = $client
|
|
||||||
->request('POST', PORTAL_API, [
|
|
||||||
'form_params' => [
|
|
||||||
'key' => PORTAL_KEY,
|
|
||||||
'action' => "auth",
|
|
||||||
'username' => $username,
|
|
||||||
'password' => $password
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() > 299) {
|
|
||||||
sendError("Login server error: " . $response->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
$resp = json_decode($response->getBody(), TRUE);
|
|
||||||
if ($resp['status'] == "OK") {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
$errmsg = $resp['msg'];
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a username exists.
|
|
||||||
* @param String $username
|
|
||||||
*/
|
|
||||||
function user_exists($username) {
|
|
||||||
$client = new GuzzleHttp\Client();
|
|
||||||
|
|
||||||
$response = $client
|
|
||||||
->request('POST', PORTAL_API, [
|
|
||||||
'form_params' => [
|
|
||||||
'key' => PORTAL_KEY,
|
|
||||||
'action' => "userexists",
|
|
||||||
'username' => $username
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() > 299) {
|
|
||||||
sendError("Login server error: " . $response->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
$resp = json_decode($response->getBody(), TRUE);
|
|
||||||
if ($resp['status'] == "OK" && $resp['exists'] === true) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a UID exists.
|
|
||||||
* @param String $uid
|
|
||||||
*/
|
|
||||||
function uid_exists($uid) {
|
|
||||||
$client = new GuzzleHttp\Client();
|
|
||||||
|
|
||||||
$response = $client
|
|
||||||
->request('POST', PORTAL_API, [
|
|
||||||
'form_params' => [
|
|
||||||
'key' => PORTAL_KEY,
|
|
||||||
'action' => "userexists",
|
|
||||||
'uid' => $uid
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() > 299) {
|
|
||||||
sendError("Login server error: " . $response->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
$resp = json_decode($response->getBody(), TRUE);
|
|
||||||
if ($resp['status'] == "OK" && $resp['exists'] === true) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the account status: NORMAL, TERMINATED, LOCKED_OR_DISABLED,
|
|
||||||
* CHANGE_PASSWORD, or ALERT_ON_ACCESS
|
|
||||||
* @param string $username
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function get_account_status($username) {
|
|
||||||
$client = new GuzzleHttp\Client();
|
|
||||||
|
|
||||||
$response = $client
|
|
||||||
->request('POST', PORTAL_API, [
|
|
||||||
'form_params' => [
|
|
||||||
'key' => PORTAL_KEY,
|
|
||||||
'action' => "acctstatus",
|
|
||||||
'username' => $username
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() > 299) {
|
|
||||||
sendError("Login server error: " . $response->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
$resp = json_decode($response->getBody(), TRUE);
|
|
||||||
if ($resp['status'] == "OK") {
|
|
||||||
return $resp['account'];
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the given username has the given permission (or admin access)
|
|
||||||
* @param string $username
|
|
||||||
* @param string $permcode
|
|
||||||
* @return boolean TRUE if the user has the permission (or admin access), else FALSE
|
|
||||||
*/
|
|
||||||
function account_has_permission($username, $permcode) {
|
|
||||||
$client = new GuzzleHttp\Client();
|
|
||||||
|
|
||||||
$response = $client
|
|
||||||
->request('POST', PORTAL_API, [
|
|
||||||
'form_params' => [
|
|
||||||
'key' => PORTAL_KEY,
|
|
||||||
'action' => "permission",
|
|
||||||
'username' => $username,
|
|
||||||
'code' => $permcode
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() > 299) {
|
|
||||||
sendError("Login server error: " . $response->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
$resp = json_decode($response->getBody(), TRUE);
|
|
||||||
if ($resp['status'] == "OK") {
|
|
||||||
return $resp['has_permission'];
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Login handling //
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setup $_SESSION values with user data and set loggedin flag to true
|
|
||||||
* @param string $username
|
|
||||||
*/
|
|
||||||
function doLoginUser($username) {
|
|
||||||
$client = new GuzzleHttp\Client();
|
|
||||||
|
|
||||||
$response = $client
|
|
||||||
->request('POST', PORTAL_API, [
|
|
||||||
'form_params' => [
|
|
||||||
'key' => PORTAL_KEY,
|
|
||||||
'action' => "userinfo",
|
|
||||||
'username' => $username
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() > 299) {
|
|
||||||
sendError("Login server error: " . $response->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
$resp = json_decode($response->getBody(), TRUE);
|
|
||||||
|
|
||||||
if ($resp['status'] == "OK") {
|
|
||||||
$userinfo = $resp['data'];
|
|
||||||
session_regenerate_id(true);
|
|
||||||
$newSession = session_id();
|
|
||||||
session_write_close();
|
|
||||||
session_id($newSession);
|
|
||||||
session_start();
|
|
||||||
$_SESSION['username'] = $username;
|
|
||||||
$_SESSION['uid'] = $userinfo['uid'];
|
|
||||||
$_SESSION['email'] = $userinfo['email'];
|
|
||||||
$_SESSION['realname'] = $userinfo['name'];
|
|
||||||
$_SESSION['loggedin'] = true;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendLoginAlertEmail($username) {
|
|
||||||
$client = new GuzzleHttp\Client();
|
|
||||||
|
|
||||||
$response = $client
|
|
||||||
->request('POST', PORTAL_API, [
|
|
||||||
'form_params' => [
|
|
||||||
'key' => PORTAL_KEY,
|
|
||||||
'action' => "alertemail",
|
|
||||||
'username' => $username,
|
|
||||||
'appname' => SITE_TITLE
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() > 299) {
|
|
||||||
return "An unknown error occurred.";
|
|
||||||
}
|
|
||||||
|
|
||||||
$resp = json_decode($response->getBody(), TRUE);
|
|
||||||
if ($resp['status'] == "OK") {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return $resp['msg'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function simLogin($username, $password) {
|
|
||||||
$client = new GuzzleHttp\Client();
|
|
||||||
|
|
||||||
$response = $client
|
|
||||||
->request('POST', PORTAL_API, [
|
|
||||||
'form_params' => [
|
|
||||||
'key' => PORTAL_KEY,
|
|
||||||
'action' => "login",
|
|
||||||
'username' => $username,
|
|
||||||
'password' => $password
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() > 299) {
|
|
||||||
sendError("Login server error: " . $response->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
$resp = json_decode($response->getBody(), TRUE);
|
|
||||||
if ($resp['status'] == "OK") {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return $resp['msg'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function verifyCaptcheck($session, $answer, $url) {
|
|
||||||
$data = [
|
|
||||||
'session_id' => $session,
|
|
||||||
'answer_id' => $answer,
|
|
||||||
'action' => "verify"
|
|
||||||
];
|
|
||||||
$options = [
|
|
||||||
'http' => [
|
|
||||||
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
|
|
||||||
'method' => 'POST',
|
|
||||||
'content' => http_build_query($data)
|
|
||||||
]
|
|
||||||
];
|
|
||||||
$context = stream_context_create($options);
|
|
||||||
$result = file_get_contents($url, false, $context);
|
|
||||||
$resp = json_decode($result, TRUE);
|
|
||||||
if (!$resp['result']) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// 2-factor authentication //
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a user has TOTP setup
|
|
||||||
* @param string $username
|
|
||||||
* @return boolean true if TOTP secret exists, else false
|
|
||||||
*/
|
|
||||||
function userHasTOTP($username) {
|
|
||||||
$client = new GuzzleHttp\Client();
|
|
||||||
|
|
||||||
$response = $client
|
|
||||||
->request('POST', PORTAL_API, [
|
|
||||||
'form_params' => [
|
|
||||||
'key' => PORTAL_KEY,
|
|
||||||
'action' => "hastotp",
|
|
||||||
'username' => $username
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() > 299) {
|
|
||||||
sendError("Login server error: " . $response->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
$resp = json_decode($response->getBody(), TRUE);
|
|
||||||
if ($resp['status'] == "OK") {
|
|
||||||
return $resp['otp'];
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify a TOTP multiauth code
|
|
||||||
* @global $database
|
|
||||||
* @param string $username
|
|
||||||
* @param int $code
|
|
||||||
* @return boolean true if it's legit, else false
|
|
||||||
*/
|
|
||||||
function verifyTOTP($username, $code) {
|
|
||||||
$client = new GuzzleHttp\Client();
|
|
||||||
|
|
||||||
$response = $client
|
|
||||||
->request('POST', PORTAL_API, [
|
|
||||||
'form_params' => [
|
|
||||||
'key' => PORTAL_KEY,
|
|
||||||
'action' => "verifytotp",
|
|
||||||
'username' => $username,
|
|
||||||
'code' => $code
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() > 299) {
|
|
||||||
sendError("Login server error: " . $response->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
$resp = json_decode($response->getBody(), TRUE);
|
|
||||||
if ($resp['status'] == "OK") {
|
|
||||||
return $resp['valid'];
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
180
lib/reports.php
180
lib/reports.php
@ -14,41 +14,20 @@ if (count(get_included_files()) == 1) {
|
|||||||
|
|
||||||
require_once __DIR__ . "/../required.php";
|
require_once __DIR__ . "/../required.php";
|
||||||
|
|
||||||
use League\Csv\Writer;
|
dieifnotloggedin();
|
||||||
use League\Csv\HTMLConverter;
|
|
||||||
use odsPhpGenerator\ods;
|
|
||||||
use odsPhpGenerator\odsTable;
|
|
||||||
use odsPhpGenerator\odsTableRow;
|
|
||||||
use odsPhpGenerator\odsTableColumn;
|
|
||||||
use odsPhpGenerator\odsTableCellString;
|
|
||||||
use odsPhpGenerator\odsStyleTableColumn;
|
|
||||||
use odsPhpGenerator\odsStyleTableCell;
|
|
||||||
|
|
||||||
// Allow access with a download code, for mobile app and stuff
|
|
||||||
$date = date("Y-m-d H:i:s");
|
|
||||||
if (isset($VARS['code']) && LOADED) {
|
|
||||||
if (!$database2->has('report_access_codes', ["AND" => ['code' => $VARS['code'], 'expires[>]' => $date]])) {
|
|
||||||
dieifnotloggedin();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dieifnotloggedin();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete old DB entries
|
|
||||||
$database2->delete('report_access_codes', ['expires[<=]' => $date]);
|
|
||||||
|
|
||||||
if (LOADED) {
|
if (LOADED) {
|
||||||
if (isset($VARS['type']) && isset($VARS['format'])) {
|
if (isset($VARS['type']) && isset($VARS['format'])) {
|
||||||
generateReport($VARS['type'], $VARS['format']);
|
generateReport($VARS['type'], $VARS['format']);
|
||||||
die();
|
die();
|
||||||
} else {
|
} else {
|
||||||
lang("invalid parameters");
|
$Strings->get("invalid parameters");
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUserReport() {
|
function getUserReport(): Report {
|
||||||
global $database;
|
global $database, $Strings;
|
||||||
$users = $database->select(
|
$users = $database->select(
|
||||||
"accounts", [
|
"accounts", [
|
||||||
"[>]acctstatus" => ["acctstatus" => "statusid"],
|
"[>]acctstatus" => ["acctstatus" => "statusid"],
|
||||||
@ -57,10 +36,21 @@ function getUserReport() {
|
|||||||
"uid", "username", "realname", "email", "statuscode", "typecode", "authsecret"
|
"uid", "username", "realname", "email", "statuscode", "typecode", "authsecret"
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
$header = [lang("uid", false), lang("username", false), lang("name", false), lang("email", false), lang("status", false), lang("type", false), lang("2fa", false)];
|
|
||||||
$out = [$header];
|
$report = new Report($Strings->get("Users", false));
|
||||||
|
|
||||||
|
$report->setHeader([
|
||||||
|
$Strings->get("uid", false),
|
||||||
|
$Strings->get("username", false),
|
||||||
|
$Strings->get("name", false),
|
||||||
|
$Strings->get("email", false),
|
||||||
|
$Strings->get("status", false),
|
||||||
|
$Strings->get("type", false),
|
||||||
|
$Strings->get("2fa", false)
|
||||||
|
]);
|
||||||
|
|
||||||
for ($i = 0; $i < count($users); $i++) {
|
for ($i = 0; $i < count($users); $i++) {
|
||||||
$out[] = [
|
$report->addDataRow([
|
||||||
$users[$i]["uid"],
|
$users[$i]["uid"],
|
||||||
$users[$i]["username"],
|
$users[$i]["username"],
|
||||||
$users[$i]["realname"],
|
$users[$i]["realname"],
|
||||||
@ -68,13 +58,13 @@ function getUserReport() {
|
|||||||
$users[$i]["statuscode"],
|
$users[$i]["statuscode"],
|
||||||
$users[$i]["typecode"],
|
$users[$i]["typecode"],
|
||||||
is_null($users[$i]["authsecret"]) ? "0" : "1"
|
is_null($users[$i]["authsecret"]) ? "0" : "1"
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
return $out;
|
return $report;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGroupReport() {
|
function getGroupReport() {
|
||||||
global $database;
|
global $database, $Strings;
|
||||||
$groups = $database->select('assigned_groups', [
|
$groups = $database->select('assigned_groups', [
|
||||||
"[>]groups" => ['groupid'],
|
"[>]groups" => ['groupid'],
|
||||||
"[>]accounts" => ['uid']
|
"[>]accounts" => ['uid']
|
||||||
@ -85,10 +75,10 @@ function getGroupReport() {
|
|||||||
'groupname',
|
'groupname',
|
||||||
'groupid'
|
'groupid'
|
||||||
]);
|
]);
|
||||||
$header = [lang("group id", false), lang("group name", false), lang("uid", false), lang("username", false), lang("name", false)];
|
$header = [$Strings->get("group id", false), $Strings->get("group name", false), $Strings->get("uid", false), $Strings->get("username", false), $Strings->get("name", false)];
|
||||||
$out = [$header];
|
$data = [];
|
||||||
for ($i = 0; $i < count($groups); $i++) {
|
for ($i = 0; $i < count($groups); $i++) {
|
||||||
$out[] = [
|
$data[] = [
|
||||||
$groups[$i]["groupid"],
|
$groups[$i]["groupid"],
|
||||||
$groups[$i]["groupname"],
|
$groups[$i]["groupname"],
|
||||||
$groups[$i]["uid"],
|
$groups[$i]["uid"],
|
||||||
@ -96,11 +86,11 @@ function getGroupReport() {
|
|||||||
$groups[$i]["realname"]
|
$groups[$i]["realname"]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
return $out;
|
return new Report($Strings->get("Groups", false), $header, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getManagerReport() {
|
function getManagerReport() {
|
||||||
global $database;
|
global $database, $Strings;
|
||||||
$managers = $database->select('managers', [
|
$managers = $database->select('managers', [
|
||||||
"[>]accounts (manager)" => ['managerid' => 'uid'],
|
"[>]accounts (manager)" => ['managerid' => 'uid'],
|
||||||
"[>]accounts (employee)" => ['employeeid' => 'uid']
|
"[>]accounts (employee)" => ['employeeid' => 'uid']
|
||||||
@ -112,21 +102,21 @@ function getManagerReport() {
|
|||||||
'manager.realname (managername)',
|
'manager.realname (managername)',
|
||||||
'employee.realname (employeename)',
|
'employee.realname (employeename)',
|
||||||
]);
|
]);
|
||||||
$header = [lang("manager name", false), lang("manager username", false), lang("employee name", false), lang("employee username", false)];
|
$header = [$Strings->get("manager name", false), $Strings->get("manager username", false), $Strings->get("employee name", false), $Strings->get("employee username", false)];
|
||||||
$out = [$header];
|
$data = [];
|
||||||
for ($i = 0; $i < count($managers); $i++) {
|
for ($i = 0; $i < count($managers); $i++) {
|
||||||
$out[] = [
|
$data[] = [
|
||||||
$managers[$i]["managername"],
|
$managers[$i]["managername"],
|
||||||
$managers[$i]["manageruser"],
|
$managers[$i]["manageruser"],
|
||||||
$managers[$i]["employeename"],
|
$managers[$i]["employeename"],
|
||||||
$managers[$i]["employeeuser"]
|
$managers[$i]["employeeuser"]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
return $out;
|
return new Report($Strings->get("Managers", false), $header, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPermissionReport() {
|
function getPermissionReport() {
|
||||||
global $database;
|
global $database, $Strings;
|
||||||
$permissions = $database->select('assigned_permissions', [
|
$permissions = $database->select('assigned_permissions', [
|
||||||
"[>]accounts" => ['uid' => 'uid'],
|
"[>]accounts" => ['uid' => 'uid'],
|
||||||
"[>]permissions" => ['permid' => 'permid']
|
"[>]permissions" => ['permid' => 'permid']
|
||||||
@ -137,10 +127,10 @@ function getPermissionReport() {
|
|||||||
'permissions.permid',
|
'permissions.permid',
|
||||||
'permcode'
|
'permcode'
|
||||||
]);
|
]);
|
||||||
$header = [lang("uid", false), lang("username", false), lang("name", false), lang("permission", false), lang("permission id", false)];
|
$header = [$Strings->get("uid", false), $Strings->get("username", false), $Strings->get("name", false), $Strings->get("permission", false), $Strings->get("permission id", false)];
|
||||||
$out = [$header];
|
$data = [];
|
||||||
for ($i = 0; $i < count($permissions); $i++) {
|
for ($i = 0; $i < count($permissions); $i++) {
|
||||||
$out[] = [
|
$data[] = [
|
||||||
$permissions[$i]["uid"],
|
$permissions[$i]["uid"],
|
||||||
$permissions[$i]["username"],
|
$permissions[$i]["username"],
|
||||||
$permissions[$i]["realname"],
|
$permissions[$i]["realname"],
|
||||||
@ -148,11 +138,11 @@ function getPermissionReport() {
|
|||||||
$permissions[$i]["permid"],
|
$permissions[$i]["permid"],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
return $out;
|
return new Report($Strings->get("Permissions", false), $header, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSecurityReport() {
|
function getSecurityReport() {
|
||||||
global $database;
|
global $database, $Strings;
|
||||||
$log = $database->select('authlog', [
|
$log = $database->select('authlog', [
|
||||||
"[>]logtypes" => ['logtype'],
|
"[>]logtypes" => ['logtype'],
|
||||||
"[>]accounts" => ['uid']
|
"[>]accounts" => ['uid']
|
||||||
@ -165,10 +155,10 @@ function getSecurityReport() {
|
|||||||
'ip',
|
'ip',
|
||||||
'otherdata'
|
'otherdata'
|
||||||
]);
|
]);
|
||||||
$header = [lang("logtime", false), lang("logtype", false), lang("ip address", false), lang("uid", false), lang("username", false), lang("name", false), lang("other data", false)];
|
$header = [$Strings->get("logtime", false), $Strings->get("logtype", false), $Strings->get("ip address", false), $Strings->get("uid", false), $Strings->get("username", false), $Strings->get("name", false), $Strings->get("other data", false)];
|
||||||
$out = [$header];
|
$data = [];
|
||||||
for ($i = 0; $i < count($log); $i++) {
|
for ($i = 0; $i < count($log); $i++) {
|
||||||
$out[] = [
|
$data[] = [
|
||||||
$log[$i]["logtime"],
|
$log[$i]["logtime"],
|
||||||
$log[$i]["typename"],
|
$log[$i]["typename"],
|
||||||
$log[$i]["ip"],
|
$log[$i]["ip"],
|
||||||
@ -178,10 +168,10 @@ function getSecurityReport() {
|
|||||||
$log[$i]["otherdata"]
|
$log[$i]["otherdata"]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
return $out;
|
return new Report($Strings->get("Security", false), $header, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getReportData($type) {
|
function getReport($type): Report {
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
case "users":
|
case "users":
|
||||||
return getUserReport();
|
return getUserReport();
|
||||||
@ -199,93 +189,11 @@ function getReportData($type) {
|
|||||||
return getSecurityReport();
|
return getSecurityReport();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return [["error"]];
|
return new Report("error", ["ERROR"], ["Invalid report type."]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function dataToCSV($data, $name = "report") {
|
|
||||||
$csv = Writer::createFromString('');
|
|
||||||
$csv->insertAll($data);
|
|
||||||
header('Content-type: text/csv');
|
|
||||||
header('Content-Disposition: attachment; filename="' . $name . "_" . date("Y-m-d_Hi") . ".csv" . '"');
|
|
||||||
echo $csv;
|
|
||||||
die();
|
|
||||||
}
|
|
||||||
|
|
||||||
function dataToODS($data, $name = "report") {
|
|
||||||
$ods = new ods();
|
|
||||||
$styleColumn = new odsStyleTableColumn();
|
|
||||||
$styleColumn->setUseOptimalColumnWidth(true);
|
|
||||||
$headerstyle = new odsStyleTableCell();
|
|
||||||
$headerstyle->setFontWeight("bold");
|
|
||||||
$table = new odsTable($name);
|
|
||||||
|
|
||||||
for ($i = 0; $i < count($data[0]); $i++) {
|
|
||||||
$table->addTableColumn(new odsTableColumn($styleColumn));
|
|
||||||
}
|
|
||||||
|
|
||||||
$rowid = 0;
|
|
||||||
foreach ($data as $datarow) {
|
|
||||||
$row = new odsTableRow();
|
|
||||||
foreach ($datarow as $cell) {
|
|
||||||
if ($rowid == 0) {
|
|
||||||
$row->addCell(new odsTableCellString($cell, $headerstyle));
|
|
||||||
} else {
|
|
||||||
$row->addCell(new odsTableCellString($cell));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$table->addRow($row);
|
|
||||||
$rowid++;
|
|
||||||
}
|
|
||||||
$ods->addTable($table);
|
|
||||||
$ods->downloadOdsFile($name . "_" . date("Y-m-d_Hi") . ".ods");
|
|
||||||
}
|
|
||||||
|
|
||||||
function dataToHTML($data, $name = "report") {
|
|
||||||
global $SECURE_NONCE;
|
|
||||||
// HTML exporter doesn't like null values
|
|
||||||
for ($i = 0; $i < count($data); $i++) {
|
|
||||||
for ($j = 0; $j < count($data[$i]); $j++) {
|
|
||||||
if (is_null($data[$i][$j])) {
|
|
||||||
$data[$i][$j] = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
header('Content-type: text/html');
|
|
||||||
$converter = new HTMLConverter();
|
|
||||||
$out = "<!DOCTYPE html>\n"
|
|
||||||
. "<meta charset=\"utf-8\">\n"
|
|
||||||
. "<meta name=\"viewport\" content=\"width=device-width\">\n"
|
|
||||||
. "<title>" . $name . "_" . date("Y-m-d_Hi") . "</title>\n"
|
|
||||||
. <<<STYLE
|
|
||||||
<style nonce="$SECURE_NONCE">
|
|
||||||
.table-csv-data {
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
.table-csv-data tr:first-child {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.table-csv-data tr td {
|
|
||||||
border: 1px solid black;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
STYLE
|
|
||||||
. $converter->convert($data);
|
|
||||||
echo $out;
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateReport($type, $format) {
|
function generateReport($type, $format) {
|
||||||
$data = getReportData($type);
|
$report = getReport($type);
|
||||||
switch ($format) {
|
$report->output($format);
|
||||||
case "ods":
|
|
||||||
dataToODS($data, $type);
|
|
||||||
break;
|
|
||||||
case "html":
|
|
||||||
dataToHTML($data, $type);
|
|
||||||
break;
|
|
||||||
case "csv":
|
|
||||||
default:
|
|
||||||
echo dataToCSV($data, $type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
127
lib/userinfo.php
127
lib/userinfo.php
@ -1,127 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get user info for the given username.
|
|
||||||
* @param int $u username
|
|
||||||
* @return [string] Array of [uid, username, name]
|
|
||||||
*/
|
|
||||||
function getUserByUsername($u) {
|
|
||||||
$client = new GuzzleHttp\Client();
|
|
||||||
|
|
||||||
$response = $client
|
|
||||||
->request('POST', PORTAL_API, [
|
|
||||||
'form_params' => [
|
|
||||||
'key' => PORTAL_KEY,
|
|
||||||
'action' => "userinfo",
|
|
||||||
'username' => $u
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() > 299) {
|
|
||||||
sendError("Login server error: " . $response->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
$resp = json_decode($response->getBody(), TRUE);
|
|
||||||
if ($resp['status'] == "OK") {
|
|
||||||
return $resp['data'];
|
|
||||||
} else {
|
|
||||||
// this shouldn't happen, but in case it does just fake it.
|
|
||||||
return ["name" => $u, "username" => $u, "uid" => $u];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get user info for the given UID.
|
|
||||||
* @param int $u user ID
|
|
||||||
* @return [string] Array of [uid, username, name]
|
|
||||||
*/
|
|
||||||
function getUserByID($u) {
|
|
||||||
$client = new GuzzleHttp\Client();
|
|
||||||
|
|
||||||
$response = $client
|
|
||||||
->request('POST', PORTAL_API, [
|
|
||||||
'form_params' => [
|
|
||||||
'key' => PORTAL_KEY,
|
|
||||||
'action' => "userinfo",
|
|
||||||
'uid' => $u
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() > 299) {
|
|
||||||
sendError("Login server error: " . $response->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
$resp = json_decode($response->getBody(), TRUE);
|
|
||||||
if ($resp['status'] == "OK") {
|
|
||||||
return $resp['data'];
|
|
||||||
} else {
|
|
||||||
// this shouldn't happen, but in case it does just fake it.
|
|
||||||
return ["name" => $u, "username" => $u, "uid" => $u];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the first UID is a manager of the second UID.
|
|
||||||
* @param int $m Manager UID
|
|
||||||
* @param int $e Employee UID
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
function isManagerOf($m, $e) {
|
|
||||||
$client = new GuzzleHttp\Client();
|
|
||||||
|
|
||||||
$response = $client
|
|
||||||
->request('POST', PORTAL_API, [
|
|
||||||
'form_params' => [
|
|
||||||
'key' => PORTAL_KEY,
|
|
||||||
'action' => "ismanagerof",
|
|
||||||
'manager' => $m,
|
|
||||||
'employee' => $e,
|
|
||||||
'uid' => 1
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() > 299) {
|
|
||||||
sendError("Login server error: " . $response->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
$resp = json_decode($response->getBody(), TRUE);
|
|
||||||
if ($resp['status'] == "OK") {
|
|
||||||
return $resp['managerof'] === true;
|
|
||||||
} else {
|
|
||||||
// this shouldn't happen, but in case it does just fake it.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an array of UIDs the given UID is a manager of.
|
|
||||||
* @param int $manageruid The UID of the manager to find employees for.
|
|
||||||
* @return [int]
|
|
||||||
*/
|
|
||||||
function getManagedUIDs($manageruid) {
|
|
||||||
$client = new GuzzleHttp\Client();
|
|
||||||
|
|
||||||
$response = $client
|
|
||||||
->request('POST', PORTAL_API, [
|
|
||||||
'form_params' => [
|
|
||||||
'key' => PORTAL_KEY,
|
|
||||||
'action' => "getmanaged",
|
|
||||||
'uid' => $manageruid
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() > 299) {
|
|
||||||
sendError("Login server error: " . $response->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
$resp = json_decode($response->getBody(), TRUE);
|
|
||||||
if ($resp['status'] == "OK") {
|
|
||||||
return $resp['employees'];
|
|
||||||
} else {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,8 +14,6 @@ $access_permission = "ADMIN";
|
|||||||
|
|
||||||
require __DIR__ . "/../required.php";
|
require __DIR__ . "/../required.php";
|
||||||
|
|
||||||
require __DIR__ . "/../lib/login.php";
|
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
header('Access-Control-Allow-Origin: *');
|
header('Access-Control-Allow-Origin: *');
|
||||||
|
|
||||||
@ -25,21 +23,7 @@ if ($VARS['action'] == "ping") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mobile_enabled() {
|
function mobile_enabled() {
|
||||||
$client = new GuzzleHttp\Client();
|
$resp = AccountHubApi::get("mobileenabled");
|
||||||
|
|
||||||
$response = $client
|
|
||||||
->request('POST', PORTAL_API, [
|
|
||||||
'form_params' => [
|
|
||||||
'key' => PORTAL_KEY,
|
|
||||||
'action' => "mobileenabled"
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() > 299) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$resp = json_decode($response->getBody(), TRUE);
|
|
||||||
if ($resp['status'] == "OK" && $resp['mobile'] === TRUE) {
|
if ($resp['status'] == "OK" && $resp['mobile'] === TRUE) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -48,36 +32,25 @@ function mobile_enabled() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mobile_valid($username, $code) {
|
function mobile_valid($username, $code) {
|
||||||
$client = new GuzzleHttp\Client();
|
try {
|
||||||
|
$resp = AccountHubApi::get("mobilevalid", ["code" => $code, "username" => $username], true);
|
||||||
|
|
||||||
$response = $client
|
|
||||||
->request('POST', PORTAL_API, [
|
|
||||||
'form_params' => [
|
|
||||||
'key' => PORTAL_KEY,
|
|
||||||
"code" => $code,
|
|
||||||
"username" => $username,
|
|
||||||
'action' => "mobilevalid"
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->getStatusCode() > 299) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$resp = json_decode($response->getBody(), TRUE);
|
|
||||||
if ($resp['status'] == "OK" && $resp['valid'] === TRUE) {
|
if ($resp['status'] == "OK" && $resp['valid'] === TRUE) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mobile_enabled() !== TRUE) {
|
if (mobile_enabled() !== TRUE) {
|
||||||
exit(json_encode(["status" => "ERROR", "msg" => lang("mobile login disabled", false)]));
|
exit(json_encode(["status" => "ERROR", "msg" => $Strings->get("mobile login disabled", false)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we have a username and access key
|
// Make sure we have a username and access key
|
||||||
if (is_empty($VARS['username']) || is_empty($VARS['key'])) {
|
if (empty($VARS['username']) || empty($VARS['key'])) {
|
||||||
http_response_code(401);
|
http_response_code(401);
|
||||||
die(json_encode(["status" => "ERROR", "msg" => "Missing username and/or access key."]));
|
die(json_encode(["status" => "ERROR", "msg" => "Missing username and/or access key."]));
|
||||||
}
|
}
|
||||||
@ -93,20 +66,21 @@ if (!mobile_valid($VARS['username'], $VARS['key'])) {
|
|||||||
switch ($VARS['action']) {
|
switch ($VARS['action']) {
|
||||||
case "start_session":
|
case "start_session":
|
||||||
// Do a web login.
|
// Do a web login.
|
||||||
if (user_exists($VARS['username'])) {
|
$user = User::byUsername($VARS['username']);
|
||||||
if (get_account_status($VARS['username']) == "NORMAL") {
|
if ($user->exists()) {
|
||||||
if (authenticate_user($VARS['username'], $VARS['password'], $autherror)) {
|
if ($user->getStatus()->getString() == "NORMAL") {
|
||||||
if (is_null($access_permission) || account_has_permission($VARS['username'], $access_permission)) {
|
if ($user->checkPassword($VARS['password'])) {
|
||||||
doLoginUser($VARS['username'], $VARS['password']);
|
if (is_null($access_permission) || $user->hasPermission($access_permission)) {
|
||||||
|
Session::start($user);
|
||||||
$_SESSION['mobile'] = true;
|
$_SESSION['mobile'] = true;
|
||||||
exit(json_encode(["status" => "OK"]));
|
exit(json_encode(["status" => "OK"]));
|
||||||
} else {
|
} else {
|
||||||
exit(json_encode(["status" => "ERROR", "msg" => lang("no admin permission", false)]));
|
exit(json_encode(["status" => "ERROR", "msg" => $Strings->get("no admin permission", false)]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exit(json_encode(["status" => "ERROR", "msg" => lang("login incorrect", false)]));
|
exit(json_encode(["status" => "ERROR", "msg" => $Strings->get("login incorrect", false)]));
|
||||||
default:
|
default:
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
die(json_encode(["status" => "ERROR", "msg" => "The requested action is not available."]));
|
die(json_encode(["status" => "ERROR", "msg" => "The requested action is not available."]));
|
||||||
|
12
pages.php
12
pages.php
@ -7,12 +7,12 @@
|
|||||||
// List of pages and metadata
|
// List of pages and metadata
|
||||||
define("PAGES", [
|
define("PAGES", [
|
||||||
"home" => [
|
"home" => [
|
||||||
"title" => "home",
|
"title" => "Home",
|
||||||
"navbar" => true,
|
"navbar" => true,
|
||||||
"icon" => "fas fa-home"
|
"icon" => "fas fa-home"
|
||||||
],
|
],
|
||||||
"users" => [
|
"users" => [
|
||||||
"title" => "users",
|
"title" => "Users",
|
||||||
"navbar" => true,
|
"navbar" => true,
|
||||||
"icon" => "fas fa-users",
|
"icon" => "fas fa-users",
|
||||||
"styles" => [
|
"styles" => [
|
||||||
@ -36,7 +36,7 @@ define("PAGES", [
|
|||||||
"navbar" => false
|
"navbar" => false
|
||||||
],
|
],
|
||||||
"groups" => [
|
"groups" => [
|
||||||
"title" => "groups",
|
"title" => "Groups",
|
||||||
"navbar" => true,
|
"navbar" => true,
|
||||||
"icon" => "fas fa-object-group",
|
"icon" => "fas fa-object-group",
|
||||||
"styles" => [
|
"styles" => [
|
||||||
@ -48,7 +48,7 @@ define("PAGES", [
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
"authlog" => [
|
"authlog" => [
|
||||||
"title" => "security log",
|
"title" => "Security Log",
|
||||||
"navbar" => true,
|
"navbar" => true,
|
||||||
"icon" => "fas fa-list",
|
"icon" => "fas fa-list",
|
||||||
"styles" => [
|
"styles" => [
|
||||||
@ -65,7 +65,7 @@ define("PAGES", [
|
|||||||
"navbar" => false
|
"navbar" => false
|
||||||
],
|
],
|
||||||
"managers" => [
|
"managers" => [
|
||||||
"title" => "managers",
|
"title" => "Managers",
|
||||||
"navbar" => true,
|
"navbar" => true,
|
||||||
"icon" => "fas fa-id-card",
|
"icon" => "fas fa-id-card",
|
||||||
"styles" => [
|
"styles" => [
|
||||||
@ -77,7 +77,7 @@ define("PAGES", [
|
|||||||
]
|
]
|
||||||
],
|
],
|
||||||
"permissions" => [
|
"permissions" => [
|
||||||
"title" => "permissions",
|
"title" => "Permissions",
|
||||||
"navbar" => true,
|
"navbar" => true,
|
||||||
"icon" => "fas fa-key",
|
"icon" => "fas fa-key",
|
||||||
"styles" => [
|
"styles" => [
|
||||||
|
@ -5,6 +5,6 @@
|
|||||||
?>
|
?>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-12 col-sm-10 col-md-8 col-lg-6">
|
<div class="col-12 col-sm-10 col-md-8 col-lg-6">
|
||||||
<div class="alert alert-warning"><b><?php lang("404 error");?></b><br /> <?php lang("page not found"); ?></div>
|
<div class="alert alert-warning"><b><?php $Strings->get("404 error");?></b><br /> <?php $Strings->get("page not found"); ?></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,17 +8,17 @@ require_once __DIR__ . '/../required.php';
|
|||||||
redirectifnotloggedin();
|
redirectifnotloggedin();
|
||||||
?>
|
?>
|
||||||
<div class="btn-group mgn-btm-10px">
|
<div class="btn-group mgn-btm-10px">
|
||||||
<a href="app.php?page=clearlog" class="btn btn-warning"><i class="fa fa-times"></i> <?php lang("clear log"); ?></a>
|
<a href="app.php?page=clearlog" class="btn btn-warning"><i class="fa fa-times"></i> <?php $Strings->get("clear log"); ?></a>
|
||||||
</div>
|
</div>
|
||||||
<table id="logtable" class="table table-bordered table-hover table-sm">
|
<table id="logtable" class="table table-bordered table-hover table-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th data-priority="0"></th>
|
<th data-priority="0"></th>
|
||||||
<th data-priority="1"><i class="fas fa-fw fa-calendar d-none d-md-inline"></i> <?php lang('logtime'); ?></th>
|
<th data-priority="1"><i class="fas fa-fw fa-calendar d-none d-md-inline"></i> <?php $Strings->get('logtime'); ?></th>
|
||||||
<th data-priority="1"><i class="fas fa-fw fa-server d-none d-md-inline"></i> <?php lang('logtype'); ?></th>
|
<th data-priority="1"><i class="fas fa-fw fa-server d-none d-md-inline"></i> <?php $Strings->get('logtype'); ?></th>
|
||||||
<th data-priority="2"><i class="fas fa-fw fa-id-badge d-none d-md-inline"></i> <?php lang('username'); ?></th>
|
<th data-priority="2"><i class="fas fa-fw fa-id-badge d-none d-md-inline"></i> <?php $Strings->get('username'); ?></th>
|
||||||
<th data-priority="3"><i class="fas fa-fw fa-globe d-none d-md-inline"></i> <?php lang('ip address'); ?></th>
|
<th data-priority="3"><i class="fas fa-fw fa-globe d-none d-md-inline"></i> <?php $Strings->get('ip address'); ?></th>
|
||||||
<th data-priority="3"><i class="fas fa-fw fa-info-circle d-none d-md-inline"></i> <?php lang('other data'); ?></th>
|
<th data-priority="3"><i class="fas fa-fw fa-info-circle d-none d-md-inline"></i> <?php $Strings->get('other data'); ?></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -27,11 +27,11 @@ redirectifnotloggedin();
|
|||||||
<tfoot>
|
<tfoot>
|
||||||
<tr>
|
<tr>
|
||||||
<th data-priority="0"></th>
|
<th data-priority="0"></th>
|
||||||
<th data-priority="1"><i class="fas fa-fw fa-calendar d-none d-md-inline"></i> <?php lang('logtime'); ?></th>
|
<th data-priority="1"><i class="fas fa-fw fa-calendar d-none d-md-inline"></i> <?php $Strings->get('logtime'); ?></th>
|
||||||
<th data-priority="1"><i class="fas fa-fw fa-server d-none d-md-inline"></i> <?php lang('logtype'); ?></th>
|
<th data-priority="1"><i class="fas fa-fw fa-server d-none d-md-inline"></i> <?php $Strings->get('logtype'); ?></th>
|
||||||
<th data-priority="2"><i class="fas fa-fw fa-id-badge d-none d-md-inline"></i> <?php lang('username'); ?></th>
|
<th data-priority="2"><i class="fas fa-fw fa-id-badge d-none d-md-inline"></i> <?php $Strings->get('username'); ?></th>
|
||||||
<th data-priority="3"><i class="fas fa-fw fa-globe d-none d-md-inline"></i> <?php lang('ip address'); ?></th>
|
<th data-priority="3"><i class="fas fa-fw fa-globe d-none d-md-inline"></i> <?php $Strings->get('ip address'); ?></th>
|
||||||
<th data-priority="3"><i class="fas fa-fw fa-info-circle d-none d-md-inline"></i> <?php lang('other data'); ?></th>
|
<th data-priority="3"><i class="fas fa-fw fa-info-circle d-none d-md-inline"></i> <?php $Strings->get('other data'); ?></th>
|
||||||
</tfoot>
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
<br />
|
<br />
|
||||||
@ -39,7 +39,7 @@ redirectifnotloggedin();
|
|||||||
<div class="col-12 col-sm-6 col-md-4">
|
<div class="col-12 col-sm-6 col-md-4">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h4 class="card-header">
|
<h4 class="card-header">
|
||||||
<?php lang('event type reference'); ?>
|
<?php $Strings->get('event type reference'); ?>
|
||||||
</h4>
|
</h4>
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
<?php
|
<?php
|
||||||
|
@ -11,15 +11,15 @@ redirectifnotloggedin();
|
|||||||
<div class="col-12 col-sm-6 col-sm-offset-3">
|
<div class="col-12 col-sm-6 col-sm-offset-3">
|
||||||
<div class="card border-red text-center">
|
<div class="card border-red text-center">
|
||||||
<h3 class="card-header text-red">
|
<h3 class="card-header text-red">
|
||||||
<?php lang("clear log") ?>
|
<?php $Strings->get("clear log") ?>
|
||||||
</h3>
|
</h3>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p><i class="fas fa-exclamation-triangle fa-10x"></i></p>
|
<p><i class="fas fa-exclamation-triangle fa-10x"></i></p>
|
||||||
<h4><?php lang("really clear log") ?></h4>
|
<h4><?php $Strings->get("really clear log") ?></h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer d-flex">
|
<div class="card-footer d-flex">
|
||||||
<a href="app.php?page=authlog" class="btn btn-primary mr-auto"><i class="fa fa-arrow-left"></i> <?php lang('cancel'); ?></a>
|
<a href="app.php?page=authlog" class="btn btn-primary mr-auto"><i class="fa fa-arrow-left"></i> <?php $Strings->get('cancel'); ?></a>
|
||||||
<a href="action.php?action=clearlog&source=authlog" class="btn btn-danger"><i class="fa fa-times"></i> <?php lang('delete'); ?></a>
|
<a href="action.php?action=clearlog&source=authlog" class="btn btn-danger"><i class="fa fa-times"></i> <?php $Strings->get('delete'); ?></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,17 +7,9 @@ require_once __DIR__ . "/../required.php";
|
|||||||
|
|
||||||
redirectifnotloggedin();
|
redirectifnotloggedin();
|
||||||
|
|
||||||
if (!is_empty($VARS['id'])) {
|
if (!empty($VARS['id']) && preg_match("/[0-9]+/", $VARS['id'])) {
|
||||||
if ($database->has('accounts', ['uid' => $VARS['id']])) {
|
$user = new User($VARS['id']);
|
||||||
$userdata = $database->select('accounts', ['[>]accttypes' => ['accttype' => 'typeid']], [
|
if (!$user->exists()) {
|
||||||
'uid',
|
|
||||||
'username',
|
|
||||||
'realname',
|
|
||||||
'email'
|
|
||||||
], [
|
|
||||||
'uid' => $VARS['id']
|
|
||||||
])[0];
|
|
||||||
} else {
|
|
||||||
// user id is invalid
|
// user id is invalid
|
||||||
header('Location: app.php?page=users&msg=user_not_exists');
|
header('Location: app.php?page=users&msg=user_not_exists');
|
||||||
die();
|
die();
|
||||||
@ -32,23 +24,23 @@ if (!is_empty($VARS['id'])) {
|
|||||||
<div class="col-12 col-sm-6 col-sm-offset-3">
|
<div class="col-12 col-sm-6 col-sm-offset-3">
|
||||||
<div class="card border-red text-center">
|
<div class="card border-red text-center">
|
||||||
<h3 class="card-header text-red">
|
<h3 class="card-header text-red">
|
||||||
<?php lang("delete user") ?>
|
<?php $Strings->get("delete user") ?>
|
||||||
</h3>
|
</h3>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p><i class="fas fa-exclamation-triangle fa-10x"></i></p>
|
<p><i class="fas fa-exclamation-triangle fa-10x"></i></p>
|
||||||
<h4><?php lang("really delete user") ?></h4>
|
<h4><?php $Strings->get("really delete user") ?></h4>
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
<div class="list-group-item">
|
<div class="list-group-item">
|
||||||
<i class="fas fa-fw fa-user"></i> <?php echo $userdata['realname']; ?>
|
<i class="fas fa-fw fa-user"></i> <?php echo $user->getName(); ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-group-item">
|
<div class="list-group-item">
|
||||||
<i class="fas fa-fw fa-id-badge"></i> <?php echo $userdata['username']; ?>
|
<i class="fas fa-fw fa-id-badge"></i> <?php echo $user->getUsername(); ?>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
if (!is_empty($userdata['email'])) {
|
if (!empty($user->getEmail())) {
|
||||||
?>
|
?>
|
||||||
<div class="list-group-item">
|
<div class="list-group-item">
|
||||||
<i class="fas fa-fw fa-envelope"></i> <?php echo $userdata['email']; ?>
|
<i class="fas fa-fw fa-envelope"></i> <?php echo $user->getEmail(); ?>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
@ -56,8 +48,8 @@ if (!is_empty($VARS['id'])) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer d-flex">
|
<div class="card-footer d-flex">
|
||||||
<a href="app.php?page=users" class="btn btn-primary mr-auto"><i class="fas fa-arrow-left"></i> <?php lang('cancel'); ?></a>
|
<a href="app.php?page=users" class="btn btn-primary mr-auto"><i class="fas fa-arrow-left"></i> <?php $Strings->get('cancel'); ?></a>
|
||||||
<a href="action.php?action=deleteuser&source=users&id=<?php echo htmlspecialchars($VARS['id']); ?>" class="btn btn-danger"><i class="fas fa-times"></i> <?php lang('delete'); ?></a>
|
<a href="action.php?action=deleteuser&source=users&id=<?php echo $user->getUID(); ?>" class="btn btn-danger"><i class="fas fa-times"></i> <?php $Strings->get('delete'); ?></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
require_once __DIR__ . '/../required.php';
|
require_once __DIR__ . '/../required.php';
|
||||||
require_once __DIR__ . "/../lib/login.php";
|
|
||||||
require_once __DIR__ . "/../lib/userinfo.php";
|
|
||||||
|
|
||||||
redirectifnotloggedin();
|
redirectifnotloggedin();
|
||||||
|
|
||||||
@ -21,134 +20,50 @@ $userdata = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
$editing = false;
|
$editing = false;
|
||||||
|
$user = new User(-1);
|
||||||
|
|
||||||
if (!is_empty($VARS['id'])) {
|
if (!empty($VARS['id']) && preg_match("/[0-9]+/", $VARS['id'])) {
|
||||||
if ($database->has('accounts', ['uid' => $VARS['id']])) {
|
$user = new User($VARS['id']);
|
||||||
|
if ($user->exists()) {
|
||||||
$editing = true;
|
$editing = true;
|
||||||
$userdata = $database->select('accounts', ['[>]accttypes' => ['accttype' => 'typeid']], [
|
|
||||||
'uid',
|
|
||||||
'username',
|
|
||||||
'realname',
|
|
||||||
'email',
|
|
||||||
'authsecret',
|
|
||||||
'acctstatus',
|
|
||||||
'typecode',
|
|
||||||
'deleted'
|
|
||||||
], [
|
|
||||||
'uid' => $VARS['id']
|
|
||||||
])[0];
|
|
||||||
} else {
|
} else {
|
||||||
// user id is invalid, redirect to a page that won't cause an error when pressing Save
|
// user id is invalid, redirect to a page that won't cause an error when pressing Save
|
||||||
header('Location: app.php?page=edituser');
|
header('Location: app.php?page=edituser');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($userdata['typecode'] != "LOCAL") {
|
$form = new FormBuilder("", "far fa-edit");
|
||||||
$localacct = false;
|
|
||||||
|
if ($editing) {
|
||||||
|
$form->setTitle($Strings->build("editing user", ['user' => "<span id=\"name_title\">" . htmlspecialchars($user->getName()) . "</span>"], false));
|
||||||
} else {
|
} else {
|
||||||
$localacct = true;
|
$form->setTitle($Strings->get("adding user", false));
|
||||||
}
|
}
|
||||||
?>
|
|
||||||
|
|
||||||
<form role="form" action="action.php" method="POST">
|
$form->addInput("name", (empty($user->getName()) ? "" : $user->getName()), "text", true, "name", null, $Strings->get("name", false), "fas fa-user");
|
||||||
<div class="card border-blue">
|
$form->addInput("username", (empty($user->getUsername()) ? "" : $user->getUsername()), "text", true, "username", null, $Strings->get("username", false), "fas fa-id-badge");
|
||||||
<h3 class="card-header text-blue">
|
$form->addInput("email", (empty($user->getEmail()) ? "" : $user->getEmail()), "email", false, "email", null, $Strings->get("email", false), "fas fa-envelope");
|
||||||
<?php
|
$form->addInput("pass", "", "text", false, "pass", null, $Strings->get("new password", false), "fas fa-lock");
|
||||||
if ($editing) {
|
$form->addInput("status", $user->getStatus()->get(), "select", true, "status", [
|
||||||
?>
|
AccountStatus::NORMAL => "NORMAL",
|
||||||
<i class="far fa-edit"></i> <?php lang2("editing user", ['user' => "<span id=\"name_title\">" . htmlspecialchars($userdata['realname']) . "</span>"]); ?>
|
AccountStatus::LOCKED_OR_DISABLED => "LOCKED_OR_DISABLED",
|
||||||
<?php
|
AccountStatus::CHANGE_PASSWORD => "CHANGE_PASSWORD",
|
||||||
} else {
|
AccountStatus::TERMINATED => "TERMINATED",
|
||||||
?>
|
AccountStatus::ALERT_ON_ACCESS => "ALERT_ON_ACCESS"
|
||||||
<i class="far fa-edit"></i> <?php lang("adding user"); ?>
|
], $Strings->get("status", false), "fas fa-check-circle");
|
||||||
<?php
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</h3>
|
|
||||||
<div class="card-body">
|
|
||||||
<?php
|
|
||||||
if (!$localacct) {
|
|
||||||
?>
|
|
||||||
<div class="alert alert-warning">
|
|
||||||
<?php lang("non-local account warning"); ?>
|
|
||||||
</div>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
if ($userdata['deleted'] == 1) {
|
|
||||||
?>
|
|
||||||
<div class="alert alert-info">
|
|
||||||
<?php lang("editing deleted account"); ?>
|
|
||||||
</div>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="name"><i class="fas fa-user"></i> <?php lang("name"); ?></label>
|
|
||||||
<input type="text" class="form-control" id="name" name="name" placeholder="<?php lang("placeholder name"); ?>" required="required" value="<?php echo htmlspecialchars($userdata['realname']); ?>" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
if ($editing) {
|
||||||
<div class="col-xs-12 col-md-6">
|
$form->addHiddenInput("id", $user->getUID());
|
||||||
<div class="form-group">
|
}
|
||||||
<label for="username"><i class="fas fa-id-badge"></i> <?php lang("username"); ?></label>
|
$form->addHiddenInput("action", "edituser");
|
||||||
<input type="text" <?php if (!$localacct) echo "readonly=\"readonly\""; ?> class="form-control" name="username" id="username" placeholder="<?php lang("placeholder username"); ?>" required="required" value="<?php echo htmlspecialchars($userdata['username']); ?>" />
|
$form->addHiddenInput("source", "users");
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-xs-12 col-md-6">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="email"><i class="fas fa-envelope"></i> <?php lang("email"); ?></label>
|
|
||||||
<input type="email" class="form-control" name="email" id="email" placeholder="<?php lang("placeholder email address"); ?>" value="<?php echo htmlspecialchars($userdata['email']); ?>" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
$form->addButton($Strings->get("save", false), "fas fa-save", null, "submit", null, null, "", "btn btn-success mr-auto");
|
||||||
<div class="col-xs-12 col-md-6">
|
if ($editing) {
|
||||||
<div class="form-group">
|
if (!empty($userdata['authsecret'])) {
|
||||||
<label for="pass"><i class="fas fa-lock"></i> <?php lang("new password"); ?></label>
|
$form->addButton($Strings->get("remove 2fa", false), "fas fa-unlock", "action.php?action=rmtotp&source=users&id=" . $user->getUID(), "", null, null, "", "btn btn-warning btn-sm");
|
||||||
<input type="text" <?php if (!$localacct) echo "readonly=\"readonly\""; ?> autocomplete="new-password" class="form-control" name="pass" id="pass" placeholder="<?php lang("placeholder password"); ?>" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-xs-12 col-md-6">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="status"><i class="fas fa-check-circle"></i> <?php lang("status"); ?></label>
|
|
||||||
<select class="form-control" name="status" id="status" required="required">
|
|
||||||
<?php
|
|
||||||
$statuses = $database->select('acctstatus', ['statusid (id)', 'statuscode (code)'], ["ORDER" => "statusid"]);
|
|
||||||
foreach ($statuses as $s) {
|
|
||||||
echo "<option";
|
|
||||||
if ($s['id'] == $userdata['acctstatus']) {
|
|
||||||
echo " selected";
|
|
||||||
}
|
}
|
||||||
echo " value=\"" . $s['id'] . "\">" . $s['code'] . "</option>";
|
$form->addButton($Strings->get("delete", false), "fas fa-times", "app.php?page=deluser&id=" . $user->getUID(), "", null, null, "", "btn btn-danger");
|
||||||
}
|
}
|
||||||
?>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
$form->generate();
|
||||||
|
|
||||||
<input type="hidden" name="id" value="<?php echo htmlspecialchars($VARS['id']); ?>" />
|
|
||||||
<input type="hidden" name="action" value="edituser" />
|
|
||||||
<input type="hidden" name="source" value="users" />
|
|
||||||
|
|
||||||
<div class="card-footer d-flex">
|
|
||||||
<button type="submit" class="btn btn-success mr-auto"><i class="fas fa-save"></i> <?php lang("save"); ?></button>
|
|
||||||
<?php
|
|
||||||
if ($editing) {
|
|
||||||
if (!is_empty($userdata['authsecret'])) {
|
|
||||||
?>
|
|
||||||
<a href="action.php?action=rmtotp&source=users&id=<?php echo htmlspecialchars($VARS['id']); ?>" class="btn btn-warning btn-sm"><i class="fas fa-unlock"></i> <?php lang('remove 2fa'); ?></a>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<a href="app.php?page=deluser&id=<?php echo htmlspecialchars($VARS['id']); ?>" class="btn btn-danger"><i class="fas fa-times"></i> <?php lang('delete'); ?></a>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
@ -13,24 +13,24 @@ redirectifnotloggedin();
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-sm-6">
|
<div class="col-12 col-sm-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="type"><?php lang("report type"); ?></label>
|
<label for="type"><?php $Strings->get("report type"); ?></label>
|
||||||
<select name="type" class="form-control" required>
|
<select name="type" class="form-control" required>
|
||||||
<option value="users"><?php lang("users") ?></option>
|
<option value="users"><?php $Strings->get("users") ?></option>
|
||||||
<option value="groups"><?php lang("groups") ?></option>
|
<option value="groups"><?php $Strings->get("groups") ?></option>
|
||||||
<option value="managers"><?php lang("managers") ?></option>
|
<option value="managers"><?php $Strings->get("managers") ?></option>
|
||||||
<option value="permissions"><?php lang("permissions") ?></option>
|
<option value="permissions"><?php $Strings->get("permissions") ?></option>
|
||||||
<option value="security"><?php lang("security log") ?></option>
|
<option value="security"><?php $Strings->get("security log") ?></option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-12 col-sm-6">
|
<div class="col-12 col-sm-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="type"><?php lang("format"); ?></label>
|
<label for="type"><?php $Strings->get("format"); ?></label>
|
||||||
<select name="format" class="form-control" required>
|
<select name="format" class="form-control" required>
|
||||||
<option value="csv"><?php lang("csv file") ?></option>
|
<option value="csv"><?php $Strings->get("csv file") ?></option>
|
||||||
<option value="ods"><?php lang("ods file") ?></option>
|
<option value="ods"><?php $Strings->get("ods file") ?></option>
|
||||||
<option value="html"><?php lang("html file") ?></option>
|
<option value="html"><?php $Strings->get("html file") ?></option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -43,7 +43,7 @@ redirectifnotloggedin();
|
|||||||
<input type="hidden" name="code" value="<?php echo $code; ?>" />
|
<input type="hidden" name="code" value="<?php echo $code; ?>" />
|
||||||
|
|
||||||
<div class="card-footer d-flex">
|
<div class="card-footer d-flex">
|
||||||
<button type="submit" class="btn btn-success ml-auto" id="genrptbtn"><i class="fas fa-download"></i> <?php lang("generate report"); ?></button>
|
<button type="submit" class="btn btn-success ml-auto" id="genrptbtn"><i class="fas fa-download"></i> <?php $Strings->get("generate report"); ?></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
@ -11,26 +11,26 @@ redirectifnotloggedin();
|
|||||||
$groupselected = false;
|
$groupselected = false;
|
||||||
$user = "";
|
$user = "";
|
||||||
$users = [];
|
$users = [];
|
||||||
if ($VARS['gid'] && $database->has('groups', ['groupid' => $VARS['gid']])) {
|
if (!empty($VARS['gid']) && $database->has('groups', ['groupid' => $VARS['gid']])) {
|
||||||
$gid = $VARS['gid'];
|
$gid = $VARS['gid'];
|
||||||
$users = $database->select('assigned_groups', ["[>]accounts" => ["uid" => "uid"]], 'username', ['groupid' => $gid]);
|
$users = $database->select('assigned_groups', ["[>]accounts" => ["uid" => "uid"]], 'username', ['groupid' => $gid]);
|
||||||
$groupselected = true;
|
$groupselected = true;
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-xl-6">
|
<div class="col-12">
|
||||||
<div class="card border-brown">
|
<div class="card border-brown">
|
||||||
<h4 class="card-header text-brown">
|
<h4 class="card-header text-brown">
|
||||||
<i class="fas fa-object-group"></i> <?php lang("group management"); ?>
|
<i class="fas fa-object-group"></i> <?php $Strings->get("group management"); ?>
|
||||||
</h4>
|
</h4>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<form role="form" action="action.php" method="POST" class="col-12 col-sm-6">
|
<form role="form" action="action.php" method="POST" class="col-12 col-sm-6">
|
||||||
<label for="addgroupbox"><i class="fas fa-plus"></i> <?php lang("new group"); ?></label>
|
<label for="addgroupbox"><i class="fas fa-plus"></i> <?php $Strings->get("new group"); ?></label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" name="group" placeholder="<?php lang("enter group name"); ?>" class="form-control" />
|
<input type="text" name="group" placeholder="<?php $Strings->get("enter group name"); ?>" class="form-control" />
|
||||||
<div class="input-group-append">
|
<div class="input-group-append">
|
||||||
<button type="submit" class="btn btn-success"><i class="fas fa-plus"></i> <?php lang("add"); ?></button>
|
<button type="submit" class="btn btn-success"><i class="fas fa-plus"></i> <?php $Strings->get("add"); ?></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input type="hidden" name="action" value="addgroup" />
|
<input type="hidden" name="action" value="addgroup" />
|
||||||
@ -38,7 +38,7 @@ if ($VARS['gid'] && $database->has('groups', ['groupid' => $VARS['gid']])) {
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<form role="form" action="action.php" method="POST" class="col-12 col-sm-6">
|
<form role="form" action="action.php" method="POST" class="col-12 col-sm-6">
|
||||||
<label for="addgroupbox"><i class="fas fa-trash"></i> <?php lang("delete group"); ?></label>
|
<label for="addgroupbox"><i class="fas fa-trash"></i> <?php $Strings->get("delete group"); ?></label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<select name="gid" class="form-control">
|
<select name="gid" class="form-control">
|
||||||
<?php
|
<?php
|
||||||
@ -49,7 +49,7 @@ if ($VARS['gid'] && $database->has('groups', ['groupid' => $VARS['gid']])) {
|
|||||||
?>
|
?>
|
||||||
</select>
|
</select>
|
||||||
<div class="input-group-append">
|
<div class="input-group-append">
|
||||||
<button type="submit" class="btn btn-danger"><i class="fas fa-times"></i> <?php lang("delete"); ?></button>
|
<button type="submit" class="btn btn-danger"><i class="fas fa-times"></i> <?php $Strings->get("delete"); ?></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input type="hidden" name="action" value="rmgroup" />
|
<input type="hidden" name="action" value="rmgroup" />
|
||||||
@ -61,10 +61,10 @@ if ($VARS['gid'] && $database->has('groups', ['groupid' => $VARS['gid']])) {
|
|||||||
<br />
|
<br />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-12 col-xl-6">
|
<div class="col-12">
|
||||||
<div class="card border-brown">
|
<div class="card border-brown">
|
||||||
<h4 class="card-header text-brown">
|
<h4 class="card-header text-brown">
|
||||||
<i class="fas fa-users"></i> <?php lang("group assignments"); ?>
|
<i class="fas fa-users"></i> <?php $Strings->get("group assignments"); ?>
|
||||||
</h4>
|
</h4>
|
||||||
<?php if ($groupselected !== false) { ?>
|
<?php if ($groupselected !== false) { ?>
|
||||||
<form role="form" action="action.php" method="POST">
|
<form role="form" action="action.php" method="POST">
|
||||||
@ -73,7 +73,7 @@ if ($VARS['gid'] && $database->has('groups', ['groupid' => $VARS['gid']])) {
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="group-box"><i class="fas fa-object-group"></i> <?php lang("group"); ?></label>
|
<label for="group-box"><i class="fas fa-object-group"></i> <?php $Strings->get("group"); ?></label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<select <?php if ($groupselected === false) { ?>id="group-box"<?php } ?> class="form-control" value="<?php echo $gid ?>" name="gid" <?php echo ($groupselected !== false ? "readonly" : ""); ?>>
|
<select <?php if ($groupselected === false) { ?>id="group-box"<?php } ?> class="form-control" value="<?php echo $gid ?>" name="gid" <?php echo ($groupselected !== false ? "readonly" : ""); ?>>
|
||||||
<?php
|
<?php
|
||||||
@ -89,7 +89,7 @@ if ($VARS['gid'] && $database->has('groups', ['groupid' => $VARS['gid']])) {
|
|||||||
</select>
|
</select>
|
||||||
<div class="input-group-append">
|
<div class="input-group-append">
|
||||||
<?php if ($groupselected === false) { ?>
|
<?php if ($groupselected === false) { ?>
|
||||||
<button class="btn btn-default" type="button" id="selectgroupbtn"><i class="fas fa-chevron-right"></i> <?php lang("next") ?></button>
|
<button class="btn btn-default" type="button" id="selectgroupbtn"><i class="fas fa-chevron-right"></i> <?php $Strings->get("next") ?></button>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -100,11 +100,20 @@ if ($VARS['gid'] && $database->has('groups', ['groupid' => $VARS['gid']])) {
|
|||||||
?>
|
?>
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="people-box"><i class="fas fa-users"></i> <?php lang("users"); ?></label>
|
<label for="people-box"><i class="fas fa-users"></i> <?php $Strings->get("users"); ?></label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" class="form-control" id="people-box" placeholder="<?php lang("type to add a person") ?>" />
|
<select class="form-control" id="people-box">
|
||||||
|
<option></option>
|
||||||
|
<?php
|
||||||
|
$allusers = $database->select("accounts", "uid", ["deleted" => 0]);
|
||||||
|
foreach ($allusers as $user) {
|
||||||
|
$u = new User($user);
|
||||||
|
echo '<option value="' . htmlentities($u->getUsername()) . '">' . htmlentities($u->getName()) . ' (' . htmlentities($u->getUsername()) . ')</option>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</select>
|
||||||
<div class="input-group-append">
|
<div class="input-group-append">
|
||||||
<button class="btn btn-default" type="button" id="addpersonbtn"><i class="fas fa-plus"></i> <?php lang("add") ?></button>
|
<button class="btn btn-default" type="button" id="addpersonbtn"><i class="fas fa-plus"></i> <?php $Strings->get("add") ?></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -133,7 +142,7 @@ if ($VARS['gid'] && $database->has('groups', ['groupid' => $VARS['gid']])) {
|
|||||||
</div>
|
</div>
|
||||||
<?php if ($groupselected !== false) { ?>
|
<?php if ($groupselected !== false) { ?>
|
||||||
<div class="card-footer d-flex">
|
<div class="card-footer d-flex">
|
||||||
<button type="submit" class="btn btn-success ml-auto" id="save-btn"><i class="fas fa-save"></i> <?php lang("save"); ?></button>
|
<button type="submit" class="btn btn-success ml-auto" id="save-btn"><i class="fas fa-save"></i> <?php $Strings->get("save"); ?></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
|
@ -10,29 +10,29 @@ redirectifnotloggedin();
|
|||||||
<div class="card-deck">
|
<div class="card-deck">
|
||||||
<div class="card text-dark bg-light-blue">
|
<div class="card text-dark bg-light-blue">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h4 class="card-title"><?php lang("total users") ?></h4>
|
<h4 class="card-title"><?php $Strings->get("total users") ?></h4>
|
||||||
<h1><i class="fas fa-fw fa-users"></i> <?php echo $database->count('accounts'); ?></h1>
|
<h1><i class="fas fa-fw fa-users"></i> <?php echo $database->count('accounts'); ?></h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer">
|
<div class="card-footer">
|
||||||
<a href="app.php?page=users" class="text-dark"><i class="fa fa-arrow-right fa-fw"></i> <?php lang('view users'); ?></a>
|
<a href="app.php?page=users" class="text-dark"><i class="fa fa-arrow-right fa-fw"></i> <?php $Strings->get('view users'); ?></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card text-dark bg-amber">
|
<div class="card text-dark bg-amber">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h4 class="card-title"><?php lang("locked accounts") ?></h4>
|
<h4 class="card-title"><?php $Strings->get("locked accounts") ?></h4>
|
||||||
<h1><i class="fas fa-fw fa-user-times"></i> <?php echo $database->count('accounts', ['OR' => ['acctstatus #LOCKED_OR_DISABLED' => 2, 'acctstatus #CHANGE_PASSWORD' => 3]]); ?></h1>
|
<h1><i class="fas fa-fw fa-user-times"></i> <?php echo $database->count('accounts', ['OR' => ['acctstatus #LOCKED_OR_DISABLED' => 2, 'acctstatus #CHANGE_PASSWORD' => 3]]); ?></h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer">
|
<div class="card-footer">
|
||||||
<a href="app.php?page=users" class="text-dark"><i class="fa fa-arrow-right fa-fw"></i> <?php lang('view users'); ?></a>
|
<a href="app.php?page=users" class="text-dark"><i class="fa fa-arrow-right fa-fw"></i> <?php $Strings->get('view users'); ?></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card text-dark bg-light-green">
|
<div class="card text-dark bg-light-green">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h4 class="card-title"><?php lang("security log entries") ?></h4>
|
<h4 class="card-title"><?php $Strings->get("security log entries") ?></h4>
|
||||||
<h1><i class="fas fa-fw fa-list"></i> <?php echo $database->count('authlog'); ?></h1>
|
<h1><i class="fas fa-fw fa-list"></i> <?php echo $database->count('authlog'); ?></h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer">
|
<div class="card-footer">
|
||||||
<a href="app.php?page=authlog" class="text-dark"><i class="fa fa-arrow-right fa-fw"></i> <?php lang('view security log'); ?></a>
|
<a href="app.php?page=authlog" class="text-dark"><i class="fa fa-arrow-right fa-fw"></i> <?php $Strings->get('view security log'); ?></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,10 +11,10 @@ redirectifnotloggedin();
|
|||||||
$assigned = [];
|
$assigned = [];
|
||||||
$employees = false;
|
$employees = false;
|
||||||
$user = "";
|
$user = "";
|
||||||
if ($VARS['man'] && $database->has('accounts', ['username' => $VARS['man']])) {
|
if (!empty($VARS['man']) && $database->has('accounts', ['username' => $VARS['man']])) {
|
||||||
|
|
||||||
$user = $VARS['man'];
|
$user = $VARS['man'];
|
||||||
require_once __DIR__ . "/../lib/userinfo.php";
|
$uid = User::byUsername($user)->getUID();
|
||||||
$uid = getUserByUsername($user)['uid'];
|
|
||||||
$assigned = $database->select('managers', ["[>]accounts" => ["employeeid" => "uid"]], 'username', ['managerid' => $uid]);
|
$assigned = $database->select('managers', ["[>]accounts" => ["employeeid" => "uid"]], 'username', ['managerid' => $uid]);
|
||||||
$employees = true;
|
$employees = true;
|
||||||
}
|
}
|
||||||
@ -24,21 +24,37 @@ if ($VARS['man'] && $database->has('accounts', ['username' => $VARS['man']])) {
|
|||||||
<?php if ($employees !== false) { ?>
|
<?php if ($employees !== false) { ?>
|
||||||
<form role="form" action="action.php" method="POST">
|
<form role="form" action="action.php" method="POST">
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
<h4 class="card-header text-brown"><?php lang("select a manager to view or edit employees"); ?></h4>
|
<h4 class="card-header text-brown"><?php $Strings->get("select a manager to view or edit employees"); ?></h4>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12 col-md-6">
|
<div class="col-xs-12 col-md-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="manager-box"><i class="fas fa-id-card"></i> <?php lang("manager"); ?></label><br />
|
<label for="manager-box"><i class="fas fa-id-card"></i> <?php $Strings->get("manager"); ?></label><br />
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text"<?php if ($employees === false) { ?> id="manager-box"<?php } ?> class="form-control" value="<?php echo $user ?>" name="manager" placeholder="<?php lang("type to select a manager"); ?>" <?php
|
<?php
|
||||||
if ($employees !== false) {
|
if ($employees === false) {
|
||||||
echo "readonly";
|
?>
|
||||||
|
<select class="form-control" id="manager-box" name="manager">
|
||||||
|
<option></option>
|
||||||
|
<?php
|
||||||
|
$allusers = $database->select("accounts", "uid", ["deleted" => 0]);
|
||||||
|
foreach ($allusers as $user) {
|
||||||
|
$u = new User($user);
|
||||||
|
echo '<option value="' . htmlentities($u->getUsername()) . '">' . htmlentities($u->getName()) . ' (' . htmlentities($u->getUsername()) . ')</option>';
|
||||||
}
|
}
|
||||||
?>/>
|
?>
|
||||||
|
</select>
|
||||||
|
<?php
|
||||||
|
} else {
|
||||||
|
?>
|
||||||
|
<input type="text" class="form-control" name="manager" readonly="readonly" value="<?php echo htmlentities($user); ?>" />
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
<div class="input-group-append">
|
<div class="input-group-append">
|
||||||
<?php if ($employees === false) { ?>
|
<?php if ($employees === false) { ?>
|
||||||
<button class="btn btn-default" type="button" id="selectmanagerbtn"><i class="fa fa-chevron-right"></i> <?php lang("next") ?></button>
|
<button class="btn btn-default" type="button" id="selectmanagerbtn"><i class="fa fa-chevron-right"></i> <?php $Strings->get("next") ?></button>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -49,11 +65,20 @@ if ($VARS['man'] && $database->has('accounts', ['username' => $VARS['man']])) {
|
|||||||
?>
|
?>
|
||||||
<div class="col-xs-12 col-md-6">
|
<div class="col-xs-12 col-md-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="people-box"><i class="fa fa-user"></i> <?php lang("employees"); ?></label><br />
|
<label for="people-box"><i class="fa fa-user"></i> <?php $Strings->get("employees"); ?></label><br />
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" id="people-box" class="form-control" placeholder="<?php lang("type to add a person") ?>" />
|
<select class="form-control" id="people-box">
|
||||||
|
<option></option>
|
||||||
|
<?php
|
||||||
|
$allusers = $database->select("accounts", "uid", ["deleted" => 0]);
|
||||||
|
foreach ($allusers as $user) {
|
||||||
|
$u = new User($user);
|
||||||
|
echo '<option value="' . htmlentities($u->getUsername()) . '">' . htmlentities($u->getName()) . ' (' . htmlentities($u->getUsername()) . ')</option>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</select>
|
||||||
<div class="input-group-append">
|
<div class="input-group-append">
|
||||||
<button class="btn btn-default" type="button" id="addpersonbtn"><i class="fa fa-plus"></i> <?php lang("add") ?></button>
|
<button class="btn btn-default" type="button" id="addpersonbtn"><i class="fa fa-plus"></i> <?php $Strings->get("add") ?></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -83,7 +108,7 @@ if ($VARS['man'] && $database->has('accounts', ['username' => $VARS['man']])) {
|
|||||||
|
|
||||||
<?php if ($employees !== false) { ?>
|
<?php if ($employees !== false) { ?>
|
||||||
<div class="card-footer d-flex">
|
<div class="card-footer d-flex">
|
||||||
<button type="submit" class="btn btn-success ml-auto" id="save-btn"><i class="fas fa-save"></i> <?php lang("save"); ?></button>
|
<button type="submit" class="btn btn-success ml-auto" id="save-btn"><i class="fas fa-save"></i> <?php $Strings->get("save"); ?></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
|
@ -10,40 +10,31 @@ redirectifnotloggedin();
|
|||||||
|
|
||||||
$perms = [];
|
$perms = [];
|
||||||
$permissions = false;
|
$permissions = false;
|
||||||
$user = "";
|
$user = null;
|
||||||
if ($VARS['user'] && $database->has('accounts', ['username' => $VARS['user']])) {
|
if (!empty($VARS['user'])) {
|
||||||
$user = $VARS['user'];
|
$user = User::byUsername($VARS['user']);
|
||||||
require_once __DIR__ . "/../lib/userinfo.php";
|
if ($user->exists()) {
|
||||||
$uid = getUserByUsername($user)['uid'];
|
$perms = $database->select('assigned_permissions', ["[>]permissions" => ["permid" => "permid"]], ['permissions.permid', 'permcode', 'perminfo'], ['uid' => $user->getUID()]);
|
||||||
$perms = $database->select('assigned_permissions', ["[>]permissions" => ["permid" => "permid"]], ['permissions.permid', 'permcode', 'perminfo'], ['uid' => $uid]);
|
|
||||||
$permissions = true;
|
$permissions = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<div class="card border-brown">
|
<div class="card border-brown">
|
||||||
<?php if ($permissions !== false) { ?>
|
<?php if ($permissions !== false) { ?>
|
||||||
<form role="form" action="action.php" method="POST">
|
<form role="form" action="action.php" method="POST">
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
<h4 class="card-header text-brown"><?php lang("select a user to view or edit permissions"); ?></h4>
|
<h4 class="card-header text-brown"><?php $Strings->get("select a user to view or edit permissions"); ?></h4>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="user-box"><i class="fas fa-id-card"></i> <?php lang("user"); ?></label><br />
|
<label for="user-box"><i class="fas fa-id-card"></i> <?php $Strings->get("user"); ?></label><br />
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<?php
|
<?php
|
||||||
if ($database->count('accounts', ['deleted[!]' => 1]) > 30) {
|
|
||||||
?>
|
|
||||||
<input type="text"<?php if ($permissions === false) { ?>id="user-box"<?php } ?> class="form-control" value="<?php echo $user ?>" name="user" placeholder="<?php lang("type to select a user"); ?>" <?php
|
|
||||||
if ($permissions !== false) {
|
|
||||||
echo "readonly";
|
|
||||||
}
|
|
||||||
?>/>
|
|
||||||
<?php
|
|
||||||
} else {
|
|
||||||
if ($permissions === false) {
|
if ($permissions === false) {
|
||||||
?>
|
?>
|
||||||
<select id="user-box" class="form-control" name="user">
|
<select id="user-box" class="form-control" name="user">
|
||||||
<option value=""><?php lang("Choose a user") ?></option>
|
<option value=""><?php $Strings->get("Choose a user") ?></option>
|
||||||
<?php
|
<?php
|
||||||
$allusers = $database->select('accounts', ['username', 'realname'], ['deleted[!]' => 1, 'ORDER' => ['realname' => 'ASC']]);
|
$allusers = $database->select('accounts', ['username', 'realname'], ['deleted[!]' => 1, 'ORDER' => ['realname' => 'ASC']]);
|
||||||
foreach ($allusers as $u) {
|
foreach ($allusers as $u) {
|
||||||
@ -53,18 +44,16 @@ if ($VARS['user'] && $database->has('accounts', ['username' => $VARS['user']]))
|
|||||||
</select>
|
</select>
|
||||||
<?php
|
<?php
|
||||||
} else {
|
} else {
|
||||||
$realname = $database->get('accounts', 'realname', ['username' => $user]);
|
|
||||||
?>
|
?>
|
||||||
<input type="text" class="form-control" value="<?php echo "$realname ($user)" ?>" readonly disabled />
|
<input type="text" class="form-control" value="<?php echo $user->getName() . "(" . $user->getUsername() . ")" ?>" readonly disabled />
|
||||||
<input type="hidden" id="user-box" name="user" value="<?php echo $user ?>" />
|
<input type="hidden" id="user-box" name="user" value="<?php echo $user->getUsername() ?>" />
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
<div class = "input-group-append">
|
<div class = "input-group-append">
|
||||||
<?php if ($permissions === false) {
|
<?php if ($permissions === false) {
|
||||||
?>
|
?>
|
||||||
<button class="btn btn-default" type="button" id="selectuserbtn"><i class="fa fa-chevron-right"></i> <?php lang("next") ?></button>
|
<button class="btn btn-default" type="button" id="selectuserbtn"><i class="fa fa-chevron-right"></i> <?php $Strings->get("next") ?></button>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -75,10 +64,10 @@ if ($VARS['user'] && $database->has('accounts', ['username' => $VARS['user']]))
|
|||||||
?>
|
?>
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="perms-box"><i class="fas fa-key"></i> <?php lang("permissions"); ?></label><br />
|
<label for="perms-box"><i class="fas fa-key"></i> <?php $Strings->get("permissions"); ?></label><br />
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<select id="perms-box" class="form-control" data-ac="false">
|
<select id="perms-box" class="form-control" data-ac="false">
|
||||||
<option value="" selected><?php lang("Choose a permission") ?></option>
|
<option value="" selected><?php $Strings->get("Choose a permission") ?></option>
|
||||||
<?php
|
<?php
|
||||||
$allpermissions = $database->select('permissions', ['permid', 'permcode', 'perminfo']);
|
$allpermissions = $database->select('permissions', ['permid', 'permcode', 'perminfo']);
|
||||||
foreach ($allpermissions as $p) {
|
foreach ($allpermissions as $p) {
|
||||||
@ -89,7 +78,7 @@ if ($VARS['user'] && $database->has('accounts', ['username' => $VARS['user']]))
|
|||||||
?>
|
?>
|
||||||
</select>
|
</select>
|
||||||
<div class="input-group-append">
|
<div class="input-group-append">
|
||||||
<button class="btn btn-default" type="button" id="addpermbtn"><i class="fa fa-plus"></i> <?php lang("add") ?></button>
|
<button class="btn btn-default" type="button" id="addpermbtn"><i class="fa fa-plus"></i> <?php $Strings->get("add") ?></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -120,7 +109,7 @@ if ($VARS['user'] && $database->has('accounts', ['username' => $VARS['user']]))
|
|||||||
|
|
||||||
<?php if ($permissions !== false) { ?>
|
<?php if ($permissions !== false) { ?>
|
||||||
<div class="card-footer d-flex">
|
<div class="card-footer d-flex">
|
||||||
<button type="submit" class="btn btn-success ml-auto" id="save-btn"><i class="fas fa-save"></i> <?php lang("save"); ?></button>
|
<button type="submit" class="btn btn-success ml-auto" id="save-btn"><i class="fas fa-save"></i> <?php $Strings->get("save"); ?></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
@ -9,38 +8,75 @@ require_once __DIR__ . '/../required.php';
|
|||||||
redirectifnotloggedin();
|
redirectifnotloggedin();
|
||||||
?>
|
?>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<a href="app.php?page=edituser" class="btn btn-success"><i class="fa fa-user-plus"></i> <?php lang("new user"); ?></a>
|
<a href="app.php?page=edituser" class="btn btn-success"><i class="fa fa-user-plus"></i> <?php $Strings->get("new user"); ?></a>
|
||||||
</div>
|
</div>
|
||||||
<table id="usertable" class="table table-bordered table-hover table-sm">
|
<table id="usertable" class="table table-bordered table-hover table-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th data-priority="0"></th>
|
<th data-priority="0"></th>
|
||||||
<th data-priority="1"><?php lang('actions'); ?></th>
|
<th data-priority="1"><?php $Strings->get('actions'); ?></th>
|
||||||
<th data-priority="1"><i class="fas fa-fw fa-user d-none d-md-inline"></i> <?php lang('name'); ?></th>
|
<th data-priority="1"><i class="fas fa-fw fa-user d-none d-md-inline"></i> <?php $Strings->get('name'); ?></th>
|
||||||
<th data-priority="2"><i class="fas fa-fw fa-id-badge d-none d-md-inline"></i> <?php lang('username'); ?></th>
|
<th data-priority="2"><i class="fas fa-fw fa-id-badge d-none d-md-inline"></i> <?php $Strings->get('username'); ?></th>
|
||||||
<th data-priority="3"><i class="fas fa-fw fa-envelope d-none d-md-inline"></i> <?php lang('email'); ?></th>
|
<th data-priority="3"><i class="fas fa-fw fa-envelope d-none d-md-inline"></i> <?php $Strings->get('email'); ?></th>
|
||||||
<th data-priority="4"><i class="fas fa-fw fa-lock d-none d-md-inline"></i> <?php lang('2fa'); ?></th>
|
<th data-priority="4"><i class="fas fa-fw fa-lock d-none d-md-inline"></i> <?php $Strings->get('2fa'); ?></th>
|
||||||
<th data-priority="3"><i class="fas fa-fw fa-check-circle d-none d-md-inline"></i> <?php lang('status'); ?></th>
|
<th data-priority="3"><i class="fas fa-fw fa-check-circle d-none d-md-inline"></i> <?php $Strings->get('status'); ?></th>
|
||||||
<th data-priority="4"><i class="fas fa-fw fa-server d-none d-md-inline"></i> <?php lang('type'); ?></th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
<?php
|
||||||
|
$where = [];
|
||||||
|
if (empty($_GET['show_deleted'])) {
|
||||||
|
$where = [
|
||||||
|
'deleted' => 0
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$users = $database->select('accounts', [
|
||||||
|
"[>]acctstatus" => ['acctstatus' => 'statusid'],
|
||||||
|
"[>]accttypes" => ['accttype' => 'typeid']
|
||||||
|
], [
|
||||||
|
'uid',
|
||||||
|
'username',
|
||||||
|
'realname',
|
||||||
|
'email',
|
||||||
|
'authsecret (2fa)',
|
||||||
|
'acctstatus',
|
||||||
|
'statuscode',
|
||||||
|
'accttype',
|
||||||
|
'typecode',
|
||||||
|
'deleted'
|
||||||
|
], $where
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($users as $user) {
|
||||||
|
?>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-primary btn-sm" href="app.php?page=edituser&id=<?php echo $user['uid']; ?>"><i class="far fa-edit"></i> <?php $Strings->get("Edit"); ?></a>
|
||||||
|
</td>
|
||||||
|
<?php if ($user['deleted']) { ?>
|
||||||
|
<td class="text-danger font-italic"><?php echo $user['realname']; ?></td>
|
||||||
|
<td class="text-danger font-italic"><?php echo $user['username']; ?></td>
|
||||||
|
<?php } else { ?>
|
||||||
|
<td><?php echo $user['realname']; ?></td>
|
||||||
|
<td><?php echo $user['username']; ?></td>
|
||||||
|
<?php } ?>
|
||||||
|
<td><?php echo $user['email']; ?></td>
|
||||||
|
<td><?php echo $user['2fa'] == true ? "<i class='fas fa-check'></i>" : "<i class='fas fa-times'></i>"; ?></td>
|
||||||
|
<td><?php echo $user['statuscode']; ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
</tbody>
|
</tbody>
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr>
|
<tr>
|
||||||
<th data-priority="0"></th>
|
<th data-priority="0"></th>
|
||||||
<th data-priority="1"><?php lang('actions'); ?></th>
|
<th data-priority="1"><?php $Strings->get('actions'); ?></th>
|
||||||
<th data-priority="1"><i class="fas fa-fw fa-user d-none d-md-inline"></i> <?php lang('name'); ?></th>
|
<th data-priority="1"><i class="fas fa-fw fa-user d-none d-md-inline"></i> <?php $Strings->get('name'); ?></th>
|
||||||
<th data-priority="2"><i class="fas fa-fw fa-id-badge d-none d-md-inline"></i> <?php lang('username'); ?></th>
|
<th data-priority="2"><i class="fas fa-fw fa-id-badge d-none d-md-inline"></i> <?php $Strings->get('username'); ?></th>
|
||||||
<th data-priority="3"><i class="fas fa-fw fa-envelope d-none d-md-inline"></i> <?php lang('email'); ?></th>
|
<th data-priority="3"><i class="fas fa-fw fa-envelope d-none d-md-inline"></i> <?php $Strings->get('email'); ?></th>
|
||||||
<th data-priority="4"><i class="fas fa-fw fa-lock d-none d-md-inline"></i> <?php lang('2fa'); ?></th>
|
<th data-priority="4"><i class="fas fa-fw fa-lock d-none d-md-inline"></i> <?php $Strings->get('2fa'); ?></th>
|
||||||
<th data-priority="3"><i class="fas fa-fw fa-check-circle d-none d-md-inline"></i> <?php lang('status'); ?></th>
|
<th data-priority="3"><i class="fas fa-fw fa-check-circle d-none d-md-inline"></i> <?php $Strings->get('status'); ?></th>
|
||||||
<th data-priority="4"><i class="fas fa-fw fa-server d-none d-md-inline"></i> <?php lang('type'); ?></th>
|
|
||||||
</tfoot>
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
<script nonce="<?php echo $SECURE_NONCE; ?>">
|
|
||||||
/* Give JavaScript access to the lang string
|
|
||||||
* it needs to inject the show deleted checkbox
|
|
||||||
*/
|
|
||||||
var lang_show_deleted = "<?php lang("show deleted") ?>";
|
|
||||||
</script>
|
|
146
required.php
146
required.php
@ -32,7 +32,6 @@ session_start(); // stick some cookies in it
|
|||||||
// renew session cookie
|
// renew session cookie
|
||||||
setcookie(session_name(), session_id(), time() + $session_length, "/", false, false);
|
setcookie(session_name(), session_id(), time() + $session_length, "/", false, false);
|
||||||
|
|
||||||
$captcha_server = (CAPTCHA_ENABLED === true ? preg_replace("/http(s)?:\/\//", "", CAPTCHA_SERVER) : "");
|
|
||||||
if ($_SESSION['mobile'] === TRUE) {
|
if ($_SESSION['mobile'] === TRUE) {
|
||||||
header("Content-Security-Policy: "
|
header("Content-Security-Policy: "
|
||||||
. "default-src 'self';"
|
. "default-src 'self';"
|
||||||
@ -42,8 +41,8 @@ if ($_SESSION['mobile'] === TRUE) {
|
|||||||
. "frame-src 'none'; "
|
. "frame-src 'none'; "
|
||||||
. "font-src 'self'; "
|
. "font-src 'self'; "
|
||||||
. "connect-src *; "
|
. "connect-src *; "
|
||||||
. "style-src 'self' 'unsafe-inline' $captcha_server; "
|
. "style-src 'self' 'unsafe-inline'; "
|
||||||
. "script-src 'self' 'unsafe-inline' $captcha_server");
|
. "script-src 'self' 'unsafe-inline'");
|
||||||
} else {
|
} else {
|
||||||
header("Content-Security-Policy: "
|
header("Content-Security-Policy: "
|
||||||
. "default-src 'self';"
|
. "default-src 'self';"
|
||||||
@ -53,8 +52,8 @@ if ($_SESSION['mobile'] === TRUE) {
|
|||||||
. "frame-src 'none'; "
|
. "frame-src 'none'; "
|
||||||
. "font-src 'self'; "
|
. "font-src 'self'; "
|
||||||
. "connect-src *; "
|
. "connect-src *; "
|
||||||
. "style-src 'self' 'nonce-$SECURE_NONCE' $captcha_server; "
|
. "style-src 'self' 'nonce-$SECURE_NONCE'; "
|
||||||
. "script-src 'self' 'nonce-$SECURE_NONCE' $captcha_server");
|
. "script-src 'self' 'nonce-$SECURE_NONCE'");
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -62,9 +61,14 @@ if ($_SESSION['mobile'] === TRUE) {
|
|||||||
require __DIR__ . '/vendor/autoload.php';
|
require __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
// List of alert messages
|
// List of alert messages
|
||||||
require __DIR__ . '/lang/messages.php';
|
require __DIR__ . '/langs/messages.php';
|
||||||
// text strings (i18n)
|
|
||||||
require __DIR__ . '/lang/' . LANGUAGE . ".php";
|
$libs = glob(__DIR__ . "/lib/*.lib.php");
|
||||||
|
foreach ($libs as $lib) {
|
||||||
|
require_once $lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
$Strings = new Strings($SETTINGS['language']);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kill off the running process and spit out an error message
|
* Kill off the running process and spit out an error message
|
||||||
@ -88,7 +92,7 @@ function sendError($error) {
|
|||||||
. "<p>" . htmlspecialchars($error) . "</p>");
|
. "<p>" . htmlspecialchars($error) . "</p>");
|
||||||
}
|
}
|
||||||
|
|
||||||
date_default_timezone_set(TIMEZONE);
|
date_default_timezone_set($SETTINGS['timezone']);
|
||||||
|
|
||||||
// Database settings
|
// Database settings
|
||||||
// Also inits database and stuff
|
// Also inits database and stuff
|
||||||
@ -97,12 +101,12 @@ use Medoo\Medoo;
|
|||||||
$database;
|
$database;
|
||||||
try {
|
try {
|
||||||
$database = new Medoo([
|
$database = new Medoo([
|
||||||
'database_type' => DB_TYPE,
|
'database_type' => $SETTINGS['database']['type'],
|
||||||
'database_name' => DB_NAME,
|
'database_name' => $SETTINGS['database']['name'],
|
||||||
'server' => DB_SERVER,
|
'server' => $SETTINGS['database']['server'],
|
||||||
'username' => DB_USER,
|
'username' => $SETTINGS['database']['user'],
|
||||||
'password' => DB_PASS,
|
'password' => $SETTINGS['database']['password'],
|
||||||
'charset' => DB_CHARSET
|
'charset' => $SETTINGS['database']['charset']
|
||||||
]);
|
]);
|
||||||
} catch (Exception $ex) {
|
} catch (Exception $ex) {
|
||||||
//header('HTTP/1.1 500 Internal Server Error');
|
//header('HTTP/1.1 500 Internal Server Error');
|
||||||
@ -112,19 +116,19 @@ try {
|
|||||||
$database2;
|
$database2;
|
||||||
try {
|
try {
|
||||||
$database2 = new Medoo([
|
$database2 = new Medoo([
|
||||||
'database_type' => DB2_TYPE,
|
'database_type' => $SETTINGS['database2']['type'],
|
||||||
'database_name' => DB2_NAME,
|
'database_name' => $SETTINGS['database2']['name'],
|
||||||
'server' => DB2_SERVER,
|
'server' => $SETTINGS['database2']['server'],
|
||||||
'username' => DB2_USER,
|
'username' => $SETTINGS['database2']['user'],
|
||||||
'password' => DB2_PASS,
|
'password' => $SETTINGS['database2']['password'],
|
||||||
'charset' => DB2_CHARSET
|
'charset' => $SETTINGS['database2']['charset']
|
||||||
]);
|
]);
|
||||||
} catch (Exception $ex) {
|
} catch (Exception $ex) {
|
||||||
//header('HTTP/1.1 500 Internal Server Error');
|
//header('HTTP/1.1 500 Internal Server Error');
|
||||||
sendError("Database error 2. Try again later. $ex");
|
sendError("Database error 2. Try again later. $ex");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DEBUG) {
|
if (!$SETTINGS['debug']) {
|
||||||
error_reporting(0);
|
error_reporting(0);
|
||||||
} else {
|
} else {
|
||||||
error_reporting(E_ALL);
|
error_reporting(E_ALL);
|
||||||
@ -141,70 +145,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
define("GET", true);
|
define("GET", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a string or whatever is empty.
|
|
||||||
* @param $str The thingy to check
|
|
||||||
* @return boolean True if it's empty or whatever.
|
|
||||||
*/
|
|
||||||
function is_empty($str) {
|
|
||||||
return (is_null($str) || !isset($str) || $str == '');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* I18N string getter. If the key doesn't exist, outputs the key itself.
|
|
||||||
* @param string $key I18N string key
|
|
||||||
* @param boolean $echo whether to echo the result or return it (default echo)
|
|
||||||
*/
|
|
||||||
function lang($key, $echo = true) {
|
|
||||||
if (array_key_exists($key, STRINGS)) {
|
|
||||||
$str = STRINGS[$key];
|
|
||||||
} else {
|
|
||||||
trigger_error("Language key \"$key\" does not exist in " . LANGUAGE, E_USER_WARNING);
|
|
||||||
$str = $key;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($echo) {
|
|
||||||
echo $str;
|
|
||||||
} else {
|
|
||||||
return $str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* I18N string getter (with builder). If the key doesn't exist, outputs the key itself.
|
|
||||||
* @param string $key I18N string key
|
|
||||||
* @param array $replace key-value array of replacements.
|
|
||||||
* If the string value is "hello {abc}" and you give ["abc" => "123"], the
|
|
||||||
* result will be "hello 123".
|
|
||||||
* @param boolean $echo whether to echo the result or return it (default echo)
|
|
||||||
*/
|
|
||||||
function lang2($key, $replace, $echo = true) {
|
|
||||||
if (array_key_exists($key, STRINGS)) {
|
|
||||||
$str = STRINGS[$key];
|
|
||||||
} else {
|
|
||||||
trigger_error("Language key \"$key\" does not exist in " . LANGUAGE, E_USER_WARNING);
|
|
||||||
$str = $key;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($replace as $find => $repl) {
|
|
||||||
$str = str_replace("{" . $find . "}", $repl, $str);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($echo) {
|
|
||||||
echo $str;
|
|
||||||
} else {
|
|
||||||
return $str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function dieifnotloggedin() {
|
function dieifnotloggedin() {
|
||||||
if ($_SESSION['loggedin'] != true) {
|
if ($_SESSION['loggedin'] != true) {
|
||||||
die("You don't have permission to be here.");
|
die("You don't have permission to be here.");
|
||||||
}
|
}
|
||||||
require_once __DIR__ . "/lib/login.php";
|
|
||||||
if (account_has_permission($_SESSION['username'], "ADMIN") == FALSE) {
|
|
||||||
die("You don't have permission to be here.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -224,46 +169,9 @@ function checkDBError($specials = []) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* http://stackoverflow.com/a/20075147
|
|
||||||
*/
|
|
||||||
if (!function_exists('base_url')) {
|
|
||||||
|
|
||||||
function base_url($atRoot = FALSE, $atCore = FALSE, $parse = FALSE) {
|
|
||||||
if (isset($_SERVER['HTTP_HOST'])) {
|
|
||||||
$http = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off' ? 'https' : 'http';
|
|
||||||
$hostname = $_SERVER['HTTP_HOST'];
|
|
||||||
$dir = str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']);
|
|
||||||
|
|
||||||
$core = preg_split('@/@', str_replace($_SERVER['DOCUMENT_ROOT'], '', realpath(dirname(__FILE__))), NULL, PREG_SPLIT_NO_EMPTY);
|
|
||||||
$core = $core[0];
|
|
||||||
|
|
||||||
$tmplt = $atRoot ? ($atCore ? "%s://%s/%s/" : "%s://%s/") : ($atCore ? "%s://%s/%s/" : "%s://%s%s");
|
|
||||||
$end = $atRoot ? ($atCore ? $core : $hostname) : ($atCore ? $core : $dir);
|
|
||||||
$base_url = sprintf($tmplt, $http, $hostname, $end);
|
|
||||||
} else
|
|
||||||
$base_url = 'http://localhost/';
|
|
||||||
|
|
||||||
if ($parse) {
|
|
||||||
$base_url = parse_url($base_url);
|
|
||||||
if (isset($base_url['path']))
|
|
||||||
if ($base_url['path'] == '/')
|
|
||||||
$base_url['path'] = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $base_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function redirectIfNotLoggedIn() {
|
function redirectIfNotLoggedIn() {
|
||||||
if ($_SESSION['loggedin'] !== TRUE) {
|
if ($_SESSION['loggedin'] !== TRUE) {
|
||||||
header('Location: ./index.php');
|
header('Location: ' . $SETTINGS['url'] . '/index.php');
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
require_once __DIR__ . "/lib/login.php";
|
|
||||||
if (account_has_permission($_SESSION['username'], "ADMIN") == FALSE) {
|
|
||||||
header('Location: ./index.php');
|
|
||||||
die("You don't have permission to be here.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,55 +1,65 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
// Whether to show debugging data in output.
|
// Settings for the app.
|
||||||
// DO NOT SET TO TRUE IN PRODUCTION!!!
|
// Copy to settings.php and customize.
|
||||||
define("DEBUG", false);
|
|
||||||
|
|
||||||
// AccountHub database connection settings
|
$SETTINGS = [
|
||||||
// See http://medoo.in/api/new for info
|
// Whether to output debugging info like PHP notices, warnings,
|
||||||
define("DB_TYPE", "mysql");
|
// and stacktraces.
|
||||||
define("DB_NAME", "accounthub");
|
// Turning this on in production is a security risk and can sometimes break
|
||||||
define("DB_SERVER", "localhost");
|
// things, such as JSON output where extra content is not expected.
|
||||||
define("DB_USER", "accounthub");
|
"debug" => false,
|
||||||
define("DB_PASS", "");
|
// Database connection settings
|
||||||
define("DB_CHARSET", "utf8");
|
// See http://medoo.in/api/new for info
|
||||||
|
// AccountHub database
|
||||||
// ManagePanel DB connection
|
"database" => [
|
||||||
define("DB2_TYPE", "mysql");
|
"type" => "mysql",
|
||||||
define("DB2_NAME", "managepanel");
|
"name" => "accounthub",
|
||||||
define("DB2_SERVER", "localhost");
|
"server" => "localhost",
|
||||||
define("DB2_USER", "managepanel");
|
"user" => "app",
|
||||||
define("DB2_PASS", "");
|
"password" => "",
|
||||||
define("DB2_CHARSET", "utf8");
|
"charset" => "utf8"
|
||||||
|
],
|
||||||
// Name of the app.
|
// ManagePanel database
|
||||||
define("SITE_TITLE", "ManagePanel");
|
"database2" => [
|
||||||
|
"type" => "mysql",
|
||||||
|
"name" => "managepanel",
|
||||||
// URL of the AccountHub API endpoint
|
"server" => "localhost",
|
||||||
define("PORTAL_API", "http://localhost/accounthub/api.php");
|
"user" => "app",
|
||||||
// URL of the AccountHub home page
|
"password" => "",
|
||||||
define("PORTAL_URL", "http://localhost/accounthub/home.php");
|
"charset" => "utf8"
|
||||||
// AccountHub API Key
|
],
|
||||||
define("PORTAL_KEY", "123");
|
// Name of the app.
|
||||||
|
"site_title" => "ManagePanel",
|
||||||
// For supported values, see http://php.net/manual/en/timezones.php
|
// Settings for connecting to the AccountHub server.
|
||||||
define("TIMEZONE", "America/Denver");
|
"accounthub" => [
|
||||||
|
// URL for the API endpoint
|
||||||
// Base URL for site links.
|
"api" => "http://localhost/accounthub/api/",
|
||||||
define('URL', '.');
|
// URL of the home page
|
||||||
|
"home" => "http://localhost/accounthub/home.php",
|
||||||
// Use Captcheck on login screen
|
// API key
|
||||||
// https://captcheck.netsyms.com
|
"key" => "123"
|
||||||
define("CAPTCHA_ENABLED", FALSE);
|
],
|
||||||
define('CAPTCHA_SERVER', 'https://captcheck.netsyms.com');
|
// List of required user permissions to access this app.
|
||||||
|
"permissions" => [
|
||||||
// See lang folder for language options
|
"ADMIN"
|
||||||
define('LANGUAGE', "en_us");
|
],
|
||||||
|
// For supported values, see http://php.net/manual/en/timezones.php
|
||||||
|
"timezone" => "America/Denver",
|
||||||
define("FOOTER_TEXT", "");
|
// Language to use for localization. See langs folder to add a language.
|
||||||
define("COPYRIGHT_NAME", "Netsyms Technologies");
|
"language" => "en",
|
||||||
|
// Shown in the footer of all the pages.
|
||||||
|
"footer_text" => "",
|
||||||
|
// Also shown in the footer, but with "Copyright <current_year>" in front.
|
||||||
|
"copyright" => "Netsyms Technologies",
|
||||||
|
// Base URL for building links relative to the location of the app.
|
||||||
|
// Only used when there's no good context for the path.
|
||||||
|
// The default is almost definitely fine.
|
||||||
|
"url" => "."
|
||||||
|
];
|
||||||
|
6
static/css/bootstrap.min.css
vendored
6
static/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
@ -1,15 +0,0 @@
|
|||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
.banner-image {
|
|
||||||
max-height: 100px;
|
|
||||||
margin: 2em auto;
|
|
||||||
border: 1px solid grey;
|
|
||||||
border-radius: 15%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
margin-top: 10em;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
/*!
|
/*!
|
||||||
* Font Awesome Free 5.1.0 by @fontawesome - https://fontawesome.com
|
* Font Awesome Free 5.6.0 by @fontawesome - https://fontawesome.com
|
||||||
* License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
*/
|
*/
|
||||||
.svg-inline--fa,svg:not(:root).svg-inline--fa{overflow:visible}.svg-inline--fa{display:inline-block;font-size:inherit;height:1em;vertical-align:-.125em}.svg-inline--fa.fa-lg{vertical-align:-.225em}.svg-inline--fa.fa-w-1{width:.0625em}.svg-inline--fa.fa-w-2{width:.125em}.svg-inline--fa.fa-w-3{width:.1875em}.svg-inline--fa.fa-w-4{width:.25em}.svg-inline--fa.fa-w-5{width:.3125em}.svg-inline--fa.fa-w-6{width:.375em}.svg-inline--fa.fa-w-7{width:.4375em}.svg-inline--fa.fa-w-8{width:.5em}.svg-inline--fa.fa-w-9{width:.5625em}.svg-inline--fa.fa-w-10{width:.625em}.svg-inline--fa.fa-w-11{width:.6875em}.svg-inline--fa.fa-w-12{width:.75em}.svg-inline--fa.fa-w-13{width:.8125em}.svg-inline--fa.fa-w-14{width:.875em}.svg-inline--fa.fa-w-15{width:.9375em}.svg-inline--fa.fa-w-16{width:1em}.svg-inline--fa.fa-w-17{width:1.0625em}.svg-inline--fa.fa-w-18{width:1.125em}.svg-inline--fa.fa-w-19{width:1.1875em}.svg-inline--fa.fa-w-20{width:1.25em}.svg-inline--fa.fa-pull-left{margin-right:.3em;width:auto}.svg-inline--fa.fa-pull-right{margin-left:.3em;width:auto}.svg-inline--fa.fa-border{height:1.5em}.svg-inline--fa.fa-li{width:2em}.svg-inline--fa.fa-fw{width:1.25em}.fa-layers svg.svg-inline--fa{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.fa-layers{display:inline-block;height:1em;position:relative;text-align:center;vertical-align:-.125em;width:1em}.fa-layers svg.svg-inline--fa{transform-origin:center center}.fa-layers-counter,.fa-layers-text{display:inline-block;position:absolute;text-align:center}.fa-layers-text{left:50%;top:50%;transform:translate(-50%,-50%);transform-origin:center center}.fa-layers-counter{background-color:#ff253a;border-radius:1em;box-sizing:border-box;color:#fff;height:1.5em;line-height:1;max-width:5em;min-width:1.5em;overflow:hidden;padding:.25em;right:0;text-overflow:ellipsis;top:0;transform:scale(.25);transform-origin:top right}.fa-layers-bottom-right{bottom:0;right:0;top:auto;transform:scale(.25);transform-origin:bottom right}.fa-layers-bottom-left{bottom:0;left:0;right:auto;top:auto;transform:scale(.25);transform-origin:bottom left}.fa-layers-top-right{right:0;top:0;transform:scale(.25);transform-origin:top right}.fa-layers-top-left{left:0;right:auto;top:0;transform:scale(.25);transform-origin:top left}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{animation:a 2s infinite linear}.fa-pulse{animation:a 1s infinite steps(8)}@keyframes a{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;position:relative;width:2em}.fa-stack-1x,.fa-stack-2x{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.svg-inline--fa.fa-stack-1x{height:1em;width:1em}.svg-inline--fa.fa-stack-2x{height:2em;width:2em}.fa-inverse{color:#fff}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}
|
.svg-inline--fa,svg:not(:root).svg-inline--fa{overflow:visible}.svg-inline--fa{display:inline-block;font-size:inherit;height:1em;vertical-align:-.125em}.svg-inline--fa.fa-lg{vertical-align:-.225em}.svg-inline--fa.fa-w-1{width:.0625em}.svg-inline--fa.fa-w-2{width:.125em}.svg-inline--fa.fa-w-3{width:.1875em}.svg-inline--fa.fa-w-4{width:.25em}.svg-inline--fa.fa-w-5{width:.3125em}.svg-inline--fa.fa-w-6{width:.375em}.svg-inline--fa.fa-w-7{width:.4375em}.svg-inline--fa.fa-w-8{width:.5em}.svg-inline--fa.fa-w-9{width:.5625em}.svg-inline--fa.fa-w-10{width:.625em}.svg-inline--fa.fa-w-11{width:.6875em}.svg-inline--fa.fa-w-12{width:.75em}.svg-inline--fa.fa-w-13{width:.8125em}.svg-inline--fa.fa-w-14{width:.875em}.svg-inline--fa.fa-w-15{width:.9375em}.svg-inline--fa.fa-w-16{width:1em}.svg-inline--fa.fa-w-17{width:1.0625em}.svg-inline--fa.fa-w-18{width:1.125em}.svg-inline--fa.fa-w-19{width:1.1875em}.svg-inline--fa.fa-w-20{width:1.25em}.svg-inline--fa.fa-pull-left{margin-right:.3em;width:auto}.svg-inline--fa.fa-pull-right{margin-left:.3em;width:auto}.svg-inline--fa.fa-border{height:1.5em}.svg-inline--fa.fa-li{width:2em}.svg-inline--fa.fa-fw{width:1.25em}.fa-layers svg.svg-inline--fa{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.fa-layers{display:inline-block;height:1em;position:relative;text-align:center;vertical-align:-.125em;width:1em}.fa-layers svg.svg-inline--fa{transform-origin:center center}.fa-layers-counter,.fa-layers-text{display:inline-block;position:absolute;text-align:center}.fa-layers-text{left:50%;top:50%;transform:translate(-50%,-50%);transform-origin:center center}.fa-layers-counter{background-color:#ff253a;border-radius:1em;box-sizing:border-box;color:#fff;height:1.5em;line-height:1;max-width:5em;min-width:1.5em;overflow:hidden;padding:.25em;right:0;text-overflow:ellipsis;top:0;transform:scale(.25);transform-origin:top right}.fa-layers-bottom-right{bottom:0;right:0;top:auto;transform:scale(.25);transform-origin:bottom right}.fa-layers-bottom-left{bottom:0;left:0;right:auto;top:auto;transform:scale(.25);transform-origin:bottom left}.fa-layers-top-right{right:0;top:0;transform:scale(.25);transform-origin:top right}.fa-layers-top-left{left:0;right:auto;top:0;transform:scale(.25);transform-origin:top left}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{animation:fa-spin 2s infinite linear}.fa-pulse{animation:fa-spin 1s infinite steps(8)}@keyframes fa-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{display:inline-block;height:2em;position:relative;width:2.5em}.fa-stack-1x,.fa-stack-2x{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.svg-inline--fa.fa-stack-1x{height:1em;width:1.25em}.svg-inline--fa.fa-stack-2x{height:2em;width:2.5em}.fa-inverse{color:#fff}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}
|
7
static/js/bootstrap.bundle.min.js
vendored
Normal file
7
static/js/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
static/js/bootstrap.min.js
vendored
7
static/js/bootstrap.min.js
vendored
File diff suppressed because one or more lines are too long
6
static/js/fontawesome-all.min.js
vendored
6
static/js/fontawesome-all.min.js
vendored
File diff suppressed because one or more lines are too long
@ -25,57 +25,12 @@ function removePerson(p) {
|
|||||||
$("#peoplelist div[data-user=" + p + "]").remove();
|
$("#peoplelist div[data-user=" + p + "]").remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
var options = {
|
|
||||||
url: "action.php",
|
|
||||||
ajaxSettings: {
|
|
||||||
dataType: "json",
|
|
||||||
method: "GET",
|
|
||||||
data: {
|
|
||||||
action: "autocomplete_user"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
preparePostData: function (data) {
|
|
||||||
data.q = $("#people-box").val();
|
|
||||||
return data;
|
|
||||||
},
|
|
||||||
getValue: function (element) {
|
|
||||||
return element.username;
|
|
||||||
},
|
|
||||||
template: {
|
|
||||||
type: "custom",
|
|
||||||
method: function (value, item) {
|
|
||||||
return item.name + " <i class=\"small\">" + item.username + "</i>";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
list: {
|
|
||||||
onClickEvent: function () {
|
|
||||||
var value = $("#people-box").getSelectedItemData().username;
|
|
||||||
addPerson(value);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
requestDelay: 500,
|
|
||||||
cssClasses: "form-control form-control-sm"
|
|
||||||
};
|
|
||||||
|
|
||||||
$("#people-box").easyAutocomplete(options);
|
|
||||||
|
|
||||||
|
|
||||||
$("#selectgroupbtn").click(function () {
|
$("#selectgroupbtn").click(function () {
|
||||||
document.location.href = "app.php?page=groups&gid=" + $("#group-box").val();
|
document.location.href = "app.php?page=groups&gid=" + $("#group-box").val();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#people-box").keyup(function (event) {
|
$("#people-box").on("change", function (event) {
|
||||||
if (event.keyCode == 13) {
|
addPerson($("#people-box").val());
|
||||||
$("#addpersonbtn").click();
|
|
||||||
event.preventDefault();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$("#people-box").keydown(function (event) {
|
|
||||||
if (event.keyCode == 13) {
|
|
||||||
event.preventDefault();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#addpersonbtn").click(function () {
|
$("#addpersonbtn").click(function () {
|
||||||
|
@ -25,96 +25,12 @@ function removePerson(p) {
|
|||||||
$("#peoplelist div[data-user=" + p + "]").remove();
|
$("#peoplelist div[data-user=" + p + "]").remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
var empoptions = {
|
|
||||||
url: "action.php",
|
|
||||||
ajaxSettings: {
|
|
||||||
dataType: "json",
|
|
||||||
method: "GET",
|
|
||||||
data: {
|
|
||||||
action: "autocomplete_user"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
preparePostData: function (data) {
|
|
||||||
data.q = $("#people-box").val();
|
|
||||||
return data;
|
|
||||||
},
|
|
||||||
getValue: function (element) {
|
|
||||||
return element.username;
|
|
||||||
},
|
|
||||||
template: {
|
|
||||||
type: "custom",
|
|
||||||
method: function (value, item) {
|
|
||||||
return item.name + " <i class=\"small\">" + item.username + "</i>";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
list: {
|
|
||||||
onClickEvent: function () {
|
|
||||||
var value = $("#people-box").getSelectedItemData().username;
|
|
||||||
addPerson(value);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
requestDelay: 500,
|
|
||||||
cssClasses: "form-control form-control-sm"
|
|
||||||
};
|
|
||||||
|
|
||||||
$("#people-box").easyAutocomplete(empoptions);
|
|
||||||
|
|
||||||
var manoptions = {
|
|
||||||
url: "action.php",
|
|
||||||
ajaxSettings: {
|
|
||||||
dataType: "json",
|
|
||||||
method: "GET",
|
|
||||||
data: {
|
|
||||||
action: "autocomplete_user"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
preparePostData: function (data) {
|
|
||||||
data.q = $("#manager-box").val();
|
|
||||||
return data;
|
|
||||||
},
|
|
||||||
getValue: function (element) {
|
|
||||||
return element.username;
|
|
||||||
},
|
|
||||||
template: {
|
|
||||||
type: "custom",
|
|
||||||
method: function (value, item) {
|
|
||||||
return item.name + " <i class=\"small\">" + item.username + "</i>";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
list: {
|
|
||||||
onClickEvent: function () {
|
|
||||||
var value = $("#manager-box").getSelectedItemData().username;
|
|
||||||
document.location.href = "app.php?page=managers&man=" + value;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
requestDelay: 500,
|
|
||||||
cssClasses: "form-control form-control-sm"
|
|
||||||
};
|
|
||||||
|
|
||||||
$("#manager-box").easyAutocomplete(manoptions);
|
|
||||||
|
|
||||||
$("#manager-box").keyup(function (e) {
|
|
||||||
if (e.keyCode == 13) {
|
|
||||||
$("#selectmanagerbtn").click();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#selectmanagerbtn").click(function () {
|
$("#selectmanagerbtn").click(function () {
|
||||||
document.location.href = "app.php?page=managers&man=" + $("#manager-box").val();
|
document.location.href = "app.php?page=managers&man=" + $("#manager-box").val();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#people-box").keyup(function (event) {
|
$("#people-box").on("change", function (event) {
|
||||||
if (event.keyCode == 13) {
|
addPerson($("#people-box").val());
|
||||||
$("#addpersonbtn").click();
|
|
||||||
event.preventDefault();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$("#people-box").keydown(function (event) {
|
|
||||||
if (event.keyCode == 13) {
|
|
||||||
event.preventDefault();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#addpersonbtn").click(function () {
|
$("#addpersonbtn").click(function () {
|
||||||
|
@ -51,64 +51,16 @@ function removePermission(permcode) {
|
|||||||
$("#permslist div[data-permcode=" + permcode + "]").remove();
|
$("#permslist div[data-permcode=" + permcode + "]").remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
var options = {
|
$("#user-box").on("change", function (e) {
|
||||||
url: "action.php",
|
|
||||||
ajaxSettings: {
|
|
||||||
dataType: "json",
|
|
||||||
method: "GET",
|
|
||||||
data: {
|
|
||||||
action: "autocomplete_user"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
preparePostData: function (data) {
|
|
||||||
data.q = $("#user-box").val();
|
|
||||||
return data;
|
|
||||||
},
|
|
||||||
getValue: function (element) {
|
|
||||||
return element.username;
|
|
||||||
},
|
|
||||||
template: {
|
|
||||||
type: "custom",
|
|
||||||
method: function (value, item) {
|
|
||||||
return item.name + " <i class=\"small\">" + item.username + "</i>";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
list: {
|
|
||||||
onClickEvent: function () {
|
|
||||||
var value = $("#user-box").getSelectedItemData().username;
|
|
||||||
document.location.href = "app.php?page=permissions&user=" + value;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
requestDelay: 500,
|
|
||||||
cssClasses: "form-control form-control-sm"
|
|
||||||
};
|
|
||||||
|
|
||||||
if ($("#user-box").get(0).tagName != "SELECT") {
|
|
||||||
$("#user-box").easyAutocomplete(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#user-box").keyup(function (e) {
|
|
||||||
if (e.keyCode == 13) {
|
|
||||||
$("#selectuserbtn").click();
|
$("#selectuserbtn").click();
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#selectuserbtn").click(function () {
|
$("#selectuserbtn").click(function () {
|
||||||
document.location.href = "app.php?page=permissions&user=" + $("#user-box").val();
|
document.location.href = "app.php?page=permissions&user=" + $("#user-box").val();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#perms-box").keyup(function (event) {
|
$("#perms-box").on("click", function (event) {
|
||||||
if (event.keyCode == 13) {
|
|
||||||
$("#addpermbtn").click();
|
$("#addpermbtn").click();
|
||||||
event.preventDefault();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$("#perms-box").keydown(function (event) {
|
|
||||||
if (event.keyCode == 13) {
|
|
||||||
event.preventDefault();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#addpermbtn").click(function () {
|
$("#addpermbtn").click(function () {
|
||||||
|
@ -30,37 +30,5 @@ var usertable = $('#usertable').DataTable({
|
|||||||
],
|
],
|
||||||
order: [
|
order: [
|
||||||
[2, 'asc']
|
[2, 'asc']
|
||||||
],
|
]
|
||||||
serverSide: true,
|
|
||||||
ajax: {
|
|
||||||
url: "lib/getusertable.php",
|
|
||||||
data: function (d) {
|
|
||||||
if ($('#show_deleted_checkbox').is(':checked')) {
|
|
||||||
d.show_deleted = 1;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dataFilter: function (data) {
|
|
||||||
var json = jQuery.parseJSON(data);
|
|
||||||
json.data = [];
|
|
||||||
json.users.forEach(function (row) {
|
|
||||||
json.data.push([
|
|
||||||
"",
|
|
||||||
row.editbtn,
|
|
||||||
(row.deleted == 1 ? "<del style=\"color: red;\">" : "") + row.realname + (row.deleted == 1 ? "</del>" : ""),
|
|
||||||
(row.deleted == 1 ? "<span style=\"color: red;\">" : "") + row.username + (row.deleted == 1 ? "</span>" : ""),
|
|
||||||
row.email,
|
|
||||||
(row['2fa'] == true ? "<i class='fas fa-check'></i>" : "<i class='fa fa-times'></i>"),
|
|
||||||
row.statuscode,
|
|
||||||
row.typecode
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
return JSON.stringify(json);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#usertable_filter').append("<div class=\"checkbox inblock\"><label><input type=\"checkbox\" id=\"show_deleted_checkbox\"> " + lang_show_deleted + "</label></div>");
|
|
||||||
|
|
||||||
$('#show_deleted_checkbox').click(function () {
|
|
||||||
usertable.ajax.reload();
|
|
||||||
});
|
});
|
Loading…
x
Reference in New Issue
Block a user