Quellcode durchsuchen

Add Portal API integration, add icon/style settings, add navbar and icon

 options to PAGES
master
Skylar Ittner vor 2 Jahren
Ursprung
Commit
3110011596
11 geänderte Dateien mit 545 neuen und 262 gelöschten Zeilen
  1. 57
    13
      app.php
  2. 2
    1
      composer.json
  3. 229
    1
      composer.lock
  4. 11
    4
      index.php
  5. 2
    18
      lang/en_us.php
  6. 148
    223
      lib/login.php
  7. 1
    1
      nbproject/project.xml
  8. 3
    1
      pages.php
  9. 14
    0
      settings.template.php
  10. BIN
      static/img/logo.png
  11. 78
    0
      static/img/logo.svg

+ 57
- 13
app.php Datei anzeigen

@@ -36,10 +36,18 @@ if (!is_empty($_GET['page'])) {
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-4 col-sm-offset-3 col-md-offset-4 col-lg-offset-4">
<img class="img-responsive banner-image" src="static/img/banner.png" />
<?php
if ((SHOW_ICON == "both" || SHOW_ICON == "app") && ICON_POSITION != "menu") {
if (MENU_BAR_STYLE != "fixed") {
?>
<img class="img-responsive banner-image" src="static/img/logo.png" />
<?php
}
}
?>
</div>
</div>
<nav class="navbar navbar-inverse">
<nav class="navbar navbar-inverse navbar-<?php echo MENU_BAR_STYLE; ?>-top">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse">
@@ -48,34 +56,70 @@ if (!is_empty($_GET['page'])) {
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="app.php?page=home">
<?php
if (SHOW_ICON == "both" || SHOW_ICON == "app") {
if (MENU_BAR_STYLE == "fixed" || ICON_POSITION == "menu") {
?>
<a class="navbar-brand" href="app.php">
<img style="height: 35px; padding-bottom: 12px; padding-left: 5px;" src="static/img/logo.png" />
</a>
<?php
}
}
?>
<a class="navbar-brand" href="app.php">
<?php
echo SITE_TITLE;
// add breadcrumb-y thing
//lang("home");
//echo " <i class=\"fa fa-caret-right\"></i> ";
lang(PAGES[$pageid]['title']);
//lang(PAGES[$pageid]['title']);
?>
</a>
</div>

<div class="collapse navbar-collapse" id="navbar-collapse">
<ul class="nav navbar-nav">
<?php
foreach (PAGES as $id => $pg) {
if ($pg['navbar'] === TRUE) {
if ($pageid == $id) {
?>
<li class="active">
<?php
} else {
?>
<li>
<?php } ?>
<a href="app.php?page=<?php echo $id; ?>">
<?php
if (isset($pg['icon'])) {
?>
<i class="fa fa-<?php echo $pg['icon']; ?> fa-fw"></i>
<?php } ?>
<?php lang($pg['title']) ?>
</a>
</li>
<?php
}
}
?>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><i class="fa fa-gears fa-fw"></i> <?php lang("options") ?> <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="app.php?page=security"><i class="fa fa-lock fa-fw"></i> <?php lang("account security") ?></a></li>
<li class="divider"></li>
<li><a href="action.php?action=signout"><i class="fa fa-sign-out fa-fw"></i> <?php lang("sign out") ?></a></li>
</ul>
</li>
<li><a href="action.php?action=signout"><i class="fa fa-sign-out fa-fw"></i> <?php lang("sign out") ?></a></li>
</ul>
</div>
</div>
</nav>
<?php
// Alert messages
if (MENU_BAR_STYLE == "fixed") {
?>
<div style="height: 75px;"></div>
<?php
}
?>
<?php
// Alert messages
if (!is_empty($_GET['msg']) && array_key_exists($_GET['msg'], MESSAGES)) {
// optional string generation argument
if (is_empty($_GET['arg'])) {

+ 2
- 1
composer.json Datei anzeigen

@@ -4,7 +4,8 @@
"type": "project",
"require": {
"catfan/medoo": "^1.2",
"spomky-labs/otphp": "^8.3"
"spomky-labs/otphp": "^8.3",
"guzzlehttp/guzzle": "^6.2"
},
"license": "MIT",
"authors": [

+ 229
- 1
composer.lock Datei anzeigen

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "51c1672b4dea32e60865b4c0cd9ff8e1",
"content-hash": "e0730a4c33d1a1cbf8738481ba9a1f1e",
"packages": [
{
"name": "beberlei/assert",
@@ -170,6 +170,184 @@
],
"time": "2016-05-05T11:49:03+00:00"
},
{
"name": "guzzlehttp/guzzle",
"version": "6.2.3",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "8d6c6cc55186db87b7dc5009827429ba4e9dc006"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/8d6c6cc55186db87b7dc5009827429ba4e9dc006",
"reference": "8d6c6cc55186db87b7dc5009827429ba4e9dc006",
"shasum": ""
},
"require": {
"guzzlehttp/promises": "^1.0",
"guzzlehttp/psr7": "^1.4",
"php": ">=5.5"
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "^4.0",
"psr/log": "^1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.2-dev"
}
},
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle is a PHP HTTP client library",
"homepage": "http://guzzlephp.org/",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"rest",
"web service"
],
"time": "2017-02-28T22:50:30+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "v1.3.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
"shasum": ""
},
"require": {
"php": ">=5.5.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle promises library",
"keywords": [
"promise"
],
"time": "2016-12-20T10:07:11+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "1.4.2",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
"reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
"shasum": ""
},
"require": {
"php": ">=5.4.0",
"psr/http-message": "~1.0"
},
"provide": {
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Tobias Schultze",
"homepage": "https://github.com/Tobion"
}
],
"description": "PSR-7 message implementation that also provides common utility methods",
"keywords": [
"http",
"message",
"request",
"response",
"stream",
"uri",
"url"
],
"time": "2017-03-20T17:10:46+00:00"
},
{
"name": "paragonie/random_compat",
"version": "v2.0.10",
@@ -218,6 +396,56 @@
],
"time": "2017-03-13T16:27:32+00:00"
},
{
"name": "psr/http-message",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"homepage": "https://github.com/php-fig/http-message",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
],
"time": "2016-08-06T14:39:51+00:00"
},
{
"name": "spomky-labs/otphp",
"version": "v8.3.0",

+ 11
- 4
index.php Datei anzeigen

@@ -39,9 +39,12 @@ if ($VARS['progress'] == "1") {
}
} else if ($VARS['progress'] == "2") {
if (verifyTOTP($VARS['username'], $VARS['authcode'])) {
doLoginUser($VARS['username'], $VARS['password']);
header('Location: app.php');
die("Logged in, go to app.php");
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);
}
@@ -64,7 +67,11 @@ if ($VARS['progress'] == "1") {
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-4 col-sm-offset-3 col-md-offset-4 col-lg-offset-4">
<div>
<img class="img-responsive banner-image" src="static/img/banner.png" />
<?php
if (SHOW_ICON == "both" || SHOW_ICON == "index") {
?>
<img class="img-responsive banner-image" src="static/img/logo.png" />
<?php } ?>
</div>
<div class="panel panel-primary">
<div class="panel-heading">

+ 2
- 18
lang/en_us.php Datei anzeigen

@@ -13,30 +13,14 @@ define("STRINGS", [
"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.",
"password on 500 list" => "The given password is ranked number {arg} out of the 500 most common passwords. Try a different one.",
"welcome user" => "Welcome, {user}!",
"change password" => "Change password",
"security options" => "Security options",
"account security" => "Account security",
"sign out" => "Sign out",
"settings" => "Settings",
"options" => "Options",
"404 error" => "404 Error",
"page not found" => "Page not found.",
"current password incorrect" => "The current password is incorrect. Try again.",
"new password mismatch" => "The new passwords did not match. Try again.",
"weak password" => "Password does not meet requirements.",
"password updated" => "Password updated successfully.",
"setup 2fa" => "Setup 2-factor authentication",
"2fa removed" => "2-factor authentication disabled.",
"2fa enabled" => "2-factor authentication activated.",
"remove 2fa" => "Disable 2-factor authentication",
"2fa explained" => "2-factor authentication adds more security to your account. You'll need an app such as Google Authenticator on your smartphone. When you have the app installed, you can enable 2-factor authentication by clicking the button below and scanning a QR code with the app. Whenever you sign in in the future, you'll need to input a six-digit code from your phone into the login page when prompted. You can disable 2-factor authentication from this page if you change your mind.",
"2fa active" => "2-factor authentication is active on your account. To remove 2fa, reset your authentication secret, or change to a new security device, click the button below.",
"enable 2fa" => "Enable 2-factor authentication",
"scan 2fa qrcode" => "Scan the QR Code with the authenticator app, or enter the secret key manually.",
"confirm 2fa" => "Finish setup",
"invalid parameters" => "Invalid request parameters.",
"ldap server error" => "The LDAP server returned an error: {arg}",
"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.",
"home" => "Home",
]);

+ 148
- 223
lib/login.php Datei anzeigen

@@ -1,147 +1,98 @@
<?php

/**
* Authentication and account functions
* Authentication and account functions. Connects to a Portal instance.
*/
use Base32\Base32;
use OTPHP\TOTP;
use LdapTools\LdapManager;
use LdapTools\Connection\ADResponseCodes;

////////////////////////////////////////////////////////////////////////////////
// Account handling //
////////////////////////////////////////////////////////////////////////////////

/**
* Add a user to the system. /!\ Assumes input is OK /!\
* @param string $username Username, saved in lowercase.
* @param string $password Password, will be hashed before saving.
* @param string $realname User's real legal name
* @param string $email User's email address.
* @return int The new user's ID number in the database.
*/
function adduser($username, $password, $realname, $email = null, $phone1 = "", $phone2 = "") {
global $database;
$database->debug()->insert('accounts', [
'username' => strtolower($username),
'password' => (is_null($password) ? null : encryptPassword($password)),
'realname' => $realname,
'email' => $email,
'phone1' => $phone1,
'phone2' => $phone2,
'acctstatus' => 1
]);

return $database->id();
}

/**
* Get where a user's account actually is.
* @param string $username
* @return string "LDAP", "LOCAL", "LDAP_ONLY", or "NONE".
*/
function account_location($username, $password) {
global $database;
$user_exists = user_exists($username);
if (!$user_exists && !LDAP_ENABLED) {
return false;
}
if ($user_exists) {
$userinfo = $database->select('accounts', ['password'], ['username' => $username])[0];
// if password empty, it's an LDAP user
if (is_empty($userinfo['password']) && LDAP_ENABLED) {
return "LDAP";
} else if (is_empty($userinfo['password']) && !LDAP_ENABLED) {
return "NONE";
} else {
return "LOCAL";
}
} else {
if (user_exists_ldap($username, $password)) {
return "LDAP_ONLY";
} else {
return "NONE";
}
}
}

/**
* Checks the given credentials against the database.
* 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) {
global $database;
global $ldap_config;
if (is_empty($username) || is_empty($password)) {
return false;
$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());
}
$loc = account_location($username, $password);
if ($loc == "NONE") {
return false;
} else if ($loc == "LOCAL") {
$hash = $database->select('accounts', ['password'], ['username' => $username, "LIMIT" => 1])[0]['password'];
return (comparePassword($password, $hash));
} else if ($loc == "LDAP") {
return authenticate_user_ldap($username, $password);
} else if ($loc == "LDAP_ONLY") {
if (authenticate_user_ldap($username, $password) === TRUE) {
try {
$user = (new LdapManager($ldap_config))->getRepository('user')->findOneByUsername($username);
var_dump($user);
adduser($user->getUsername(), null, $user->getName(), ($user->hasEmailAddress() ? $user->getEmailAddress() : null));
return true;
} catch (Exception $e) {
sendError("LDAP error: " . $e->getMessage());
}
} else {
return false;
}

$resp = json_decode($response->getBody(), TRUE);
if ($resp['status'] == "OK") {
return true;
} else {
return false;
}
}

/**
* Check if a username exists in the local database.
* Check if a username exists.
* @param String $username
*/
function user_exists($username) {
global $database;
return $database->has('accounts', ['username' => $username, "LIMIT" => QUERY_LIMIT]);
$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;
}
}

/**
* Get the account status: NORMAL, TERMINATED, LOCKED_OR_DISABLED,
* CHANGE_PASSWORD, or ALERT_ON_ACCESS
* @global $database $database
* @param string $username
* @return string
*/
function get_account_status($username) {
global $database;
$loc = account_location($username);
if ($loc == "LOCAL") {
$statuscode = $database->select('accounts', [
'[>]acctstatus' => [
'acctstatus' => 'statusid'
]
], [
'accounts.acctstatus',
'acctstatus.statuscode'
], [
'username' => $username,
"LIMIT" => 1
]
)[0]['statuscode'];
return $statuscode;
} else if ($loc == "LDAP") {
// TODO: Read actual account status from AD servers
return "NORMAL";
$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 {
// account isn't setup properly
return "LOCKED_OR_DISABLED";
return false;
}
}

@@ -150,93 +101,64 @@ function get_account_status($username) {
////////////////////////////////////////////////////////////////////////////////

/**
* Setup $_SESSION values to log in a user
* Setup $_SESSION values with user data and set loggedin flag to true
* @param string $username
*/
function doLoginUser($username, $password) {
global $database;
$userinfo = $database->select('accounts', ['email', 'uid', 'realname'], ['username' => $username])[0];
$_SESSION['username'] = $username;
$_SESSION['uid'] = $userinfo['uid'];
$_SESSION['email'] = $userinfo['email'];
$_SESSION['realname'] = $userinfo['realname'];
$_SESSION['password'] = $password; // needed for things like EWS
$_SESSION['loggedin'] = true;
}

/**
* Send an alert email to the system admin
*
* Used when an account with the status ALERT_ON_ACCESS logs in
* @param String $username the account username
*/
function sendLoginAlertEmail($username) {
// TODO: add email code
}

////////////////////////////////////////////////////////////////////////////////
// LDAP handling //
////////////////////////////////////////////////////////////////////////////////
function doLoginUser($username) {
$client = new GuzzleHttp\Client();

$response = $client
->request('POST', PORTAL_API, [
'form_params' => [
'key' => PORTAL_KEY,
'action' => "userinfo",
'username' => $username
]
]);

/**
* Checks the given credentials against the LDAP server.
* @param string $username
* @param string $password
* @return mixed True if OK, else false or the error code from the server
*/
function authenticate_user_ldap($username, $password) {
global $ldap_config;
if (is_empty($username) || is_empty($password)) {
return false;
if ($response->getStatusCode() > 299) {
sendError("Login server error: " . $response->getBody());
}
$ldapManager = new LdapManager($ldap_config);
$msg = "";
$code = 0;
if ($ldapManager->authenticate($username, $password, $msg, $code)) {

$resp = json_decode($response->getBody(), TRUE);
var_dump($resp);
if ($resp['status'] == "OK") {
$userinfo = $resp['data'];
$_SESSION['username'] = $username;
$_SESSION['uid'] = $userinfo['uid'];
$_SESSION['email'] = $userinfo['email'];
$_SESSION['realname'] = $userinfo['name'];
$_SESSION['password'] = $password;
$_SESSION['loggedin'] = true;
return true;
} else {
return $code;
return false;
}
}

/**
* Check if a username exists on the LDAP server.
* @global type $ldap_config
* @param type $username
* @return boolean true if yes, else false
*/
function user_exists_ldap($username, $password) {
global $ldap_config;
$ldap = new LdapManager($ldap_config);
if (!$ldap->authenticate($username, $password, $message, $code)) {
switch ($code) {
case ADResponseCodes::ACCOUNT_INVALID:
return false;
case ADResponseCodes::ACCOUNT_CREDENTIALS_INVALID:
return true;
case ADResponseCodes::ACCOUNT_RESTRICTIONS:
return true;
case ADResponseCodes::ACCOUNT_RESTRICTIONS_TIME:
return true;
case ADResponseCodes::ACCOUNT_RESTRICTIONS_DEVICE:
return true;
case ADResponseCodes::ACCOUNT_PASSWORD_EXPIRED:
return true;
case ADResponseCodes::ACCOUNT_DISABLED:
return true;
case ADResponseCodes::ACCOUNT_CONTEXT_IDS:
return true;
case ADResponseCodes::ACCOUNT_EXPIRED:
return false;
case ADResponseCodes::ACCOUNT_PASSWORD_MUST_CHANGE:
return true;
case ADResponseCodes::ACCOUNT_LOCKED:
return true;
default:
return false;
}
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'];
}
return true;
}

////////////////////////////////////////////////////////////////////////////////
@@ -245,43 +167,31 @@ function user_exists_ldap($username, $password) {

/**
* Check if a user has TOTP setup
* @global $database $database
* @param string $username
* @return boolean true if TOTP secret exists, else false
*/
function userHasTOTP($username) {
global $database;
$secret = $database->select('accounts', 'authsecret', ['username' => $username])[0];
if (is_empty($secret)) {
return false;
}
return true;
}
$client = new GuzzleHttp\Client();

$response = $client
->request('POST', PORTAL_API, [
'form_params' => [
'key' => PORTAL_KEY,
'action' => "hastotp",
'username' => $username
]
]);

/**
* Generate a TOTP secret for the given user.
* @param string $username
* @return string OTP provisioning URI (for generating a QR code)
*/
function newTOTP($username) {
global $database;
$secret = random_bytes(20);
$encoded_secret = Base32::encode($secret);
$userdata = $database->select('accounts', ['email', 'authsecret', 'realname'], ['username' => $username])[0];
$totp = new TOTP((is_null($userdata['email']) ? $userdata['realname'] : $userdata['email']), $encoded_secret);
$totp->setIssuer(SYSTEM_NAME);
return $totp->getProvisioningUri();
}
if ($response->getStatusCode() > 299) {
sendError("Login server error: " . $response->getBody());
}

/**
* Save a TOTP secret for the user.
* @global $database $database
* @param string $username
* @param string $secret
*/
function saveTOTP($username, $secret) {
global $database;
$database->update('accounts', ['authsecret' => $secret], ['username' => $username]);
$resp = json_decode($response->getBody(), TRUE);
if ($resp['status'] == "OK") {
return $resp['otp'];
} else {
return false;
}
}

/**
@@ -292,11 +202,26 @@ function saveTOTP($username, $secret) {
* @return boolean true if it's legit, else false
*/
function verifyTOTP($username, $code) {
global $database;
$userdata = $database->select('accounts', ['email', 'authsecret'], ['username' => $username])[0];
if (is_empty($userdata['authsecret'])) {
$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;
}
$totp = new TOTP(null, $userdata['authsecret']);
return $totp->verify($code);
}

+ 1
- 1
nbproject/project.xml Datei anzeigen

@@ -3,7 +3,7 @@
<type>org.netbeans.modules.php.project</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/php-project/1">
<name>WebAppTemplate</name>
<name>BusinessAppTemplate</name>
</data>
</configuration>
</project>

+ 3
- 1
pages.php Datei anzeigen

@@ -3,7 +3,9 @@
// List of pages and metadata
define("PAGES", [
"home" => [
"title" => "home"
"title" => "home",
"navbar" => true,
"icon" => "home"
],
"404" => [
"title" => "404 error"

+ 14
- 0
settings.template.php Datei anzeigen

@@ -18,6 +18,20 @@ define("SITE_TITLE", "Web App Template");
// Used to identify the system in OTP and other places
define("SYSTEM_NAME", "Web App Template");

// Which pages to show the app icon on:
// index, app, both, none
define("SHOW_ICON", "both");
// Where to put the icon: top or menu
// Overridden to 'menu' if MENU_BAR_STYLE is 'fixed'.
define("ICON_POSITION", "menu");
// App menu bar style: fixed or static
define("MENU_BAR_STYLE", "fixed");

// URL of the Business Portal API endpoint
define("PORTAL_API", "http://localhost/api.php");
// Business Portal API Key
define("PORTAL_KEY", "123");

// For supported values, see http://php.net/manual/en/timezones.php
define("TIMEZONE", "America/Denver");


BIN
static/img/logo.png Datei anzeigen


+ 78
- 0
static/img/logo.svg Datei anzeigen

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="512"
height="512"
viewBox="0 0 512.00001 512.00001"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="logo.svg"
inkscape:export-filename="/home/skylar/Documents/Projects/Sources/WebAppTemplate/static/img/logo.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs4">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="-493.3276 : 245.89848 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="464.45088 : 245.89848 : 1"
inkscape:persp3d-origin="-14.438371 : 160.56515 : 1"
id="perspective4236" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.49497475"
inkscape:cx="-135.9681"
inkscape:cy="352.66131"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-540.36216)">
<rect
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.74509804"
id="rect4726"
width="512"
height="512"
x="0"
y="540.36218"
rx="50"
ry="50" />
<path
id="path4348"
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:9.87128067;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 132.93564,682.51771 213.96788,-43.14304 0,313.97496 -213.96788,-37.9643 z m 213.96788,-43.14304 0,313.97496 32.16084,-45.18373 0,-217.44396 z m -213.96788,43.14304 213.96788,-43.14304 32.16084,51.34727 -167.21823,22.47784 z m 78.91049,30.68207 167.21823,-22.47784 0,217.44396 -167.21823,-19.77968 z m -78.91049,-30.68207 0,232.86762 78.91049,-26.99911 0,-175.18644 z m 0,232.86762 213.96788,37.9643 32.16084,-45.18373 -167.21823,-19.77968 z"
inkscape:connector-curvature="0" />
</g>
</svg>

Laden…
Abbrechen
Speichern