mirror of https://github.com/itflow-org/itflow
Implemented 2FA TOTP with Google Authenticator
This commit is contained in:
parent
bc8091ae49
commit
e247ad4ee4
|
|
@ -8,65 +8,89 @@
|
|||
</button>
|
||||
</div>
|
||||
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
|
||||
<div class="modal-body bg-white">
|
||||
|
||||
<div class="form-group">
|
||||
<label>Assign a User to a Client</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
|
||||
<div class="modal-body bg-white">
|
||||
|
||||
<ul class="nav nav-pills nav-justified mb-3" id="pills-tab" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" id="pills-user-tab" data-toggle="pill" href="#pills-user">User</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="pills-assign-tab" data-toggle="pill" href="#pills-assign">Assign</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="tab-content" id="pills-tabContent">
|
||||
|
||||
<div class="tab-pane fade show active" id="pills-user">
|
||||
|
||||
<div class="form-group">
|
||||
<label>Name</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="name" placeholder="Full Name" required autofocus>
|
||||
</div>
|
||||
</div>
|
||||
<select class="form-control selectpicker show-tick" data-live-search="true" name="client">
|
||||
<option value="0">No Client Assignment</option>
|
||||
<?php
|
||||
|
||||
$sql = mysqli_query($mysqli,"SELECT * FROM clients");
|
||||
while($row = mysqli_fetch_array($sql)){
|
||||
$client_id = $row['client_id'];
|
||||
$client_name = $row['client_name'];
|
||||
?>
|
||||
<option value="<?php echo $client_id; ?>"><?php echo $client_name; ?></option>
|
||||
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Email</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-envelope"></i></span>
|
||||
</div>
|
||||
<input type="email" class="form-control" name="email" placeholder="Email Address" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Password</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-lock"></i></span>
|
||||
</div>
|
||||
<input type="password" class="form-control" name="password" placeholder="Enter a Password" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Avatar</label>
|
||||
<input type="file" class="form-control-file" accept="image/*;capture=camera" name="file">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="pills-assign">
|
||||
|
||||
<div class="form-group">
|
||||
<label>Assign a User to a Client</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
|
||||
</div>
|
||||
<select class="form-control selectpicker show-tick" data-live-search="true" name="client">
|
||||
<option value="0">No Client Assignment</option>
|
||||
<?php
|
||||
|
||||
$sql = mysqli_query($mysqli,"SELECT * FROM clients");
|
||||
while($row = mysqli_fetch_array($sql)){
|
||||
$client_id = $row['client_id'];
|
||||
$client_name = $row['client_name'];
|
||||
?>
|
||||
<option value="<?php echo $client_id; ?>"><?php echo $client_name; ?></option>
|
||||
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Name</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="name" placeholder="Full Name" required autofocus>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Email</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-envelope"></i></span>
|
||||
</div>
|
||||
<input type="email" class="form-control" name="email" placeholder="Email Address" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Password</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-lock"></i></span>
|
||||
</div>
|
||||
<input type="password" class="form-control" name="password" placeholder="Enter a Password" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Avatar</label>
|
||||
<input type="file" class="form-control-file" accept="image/*;capture=camera" name="file">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer bg-white">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
/**
|
||||
* Encode in Base32 based on RFC 4648.
|
||||
* Requires 20% more space than base64
|
||||
* Great for case-insensitive filesystems like Windows and URL's (except for = char which can be excluded using the pad option for urls)
|
||||
*
|
||||
* @package default
|
||||
* @author Bryan Ruiz
|
||||
**/
|
||||
class Base32Static {
|
||||
private static $map = array(
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 7
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 15
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 23
|
||||
'Y', 'Z', '2', '3', '4', '5', '6', '7', // 31
|
||||
'=' // padding character
|
||||
);
|
||||
|
||||
private static $flippedMap = array(
|
||||
'A'=>'0', 'B'=>'1', 'C'=>'2', 'D'=>'3', 'E'=>'4', 'F'=>'5', 'G'=>'6', 'H'=>'7',
|
||||
'I'=>'8', 'J'=>'9', 'K'=>'10', 'L'=>'11', 'M'=>'12', 'N'=>'13', 'O'=>'14', 'P'=>'15',
|
||||
'Q'=>'16', 'R'=>'17', 'S'=>'18', 'T'=>'19', 'U'=>'20', 'V'=>'21', 'W'=>'22', 'X'=>'23',
|
||||
'Y'=>'24', 'Z'=>'25', '2'=>'26', '3'=>'27', '4'=>'28', '5'=>'29', '6'=>'30', '7'=>'31'
|
||||
);
|
||||
|
||||
/**
|
||||
* Use padding false when encoding for urls
|
||||
*
|
||||
* @return base32 encoded string
|
||||
* @author Bryan Ruiz
|
||||
**/
|
||||
public static function encode($input, $padding = true) {
|
||||
if(empty($input)) return "";
|
||||
|
||||
$input = str_split($input);
|
||||
$binaryString = "";
|
||||
|
||||
for($i = 0; $i < count($input); $i++) {
|
||||
$binaryString .= str_pad(base_convert(ord($input[$i]), 10, 2), 8, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
$fiveBitBinaryArray = str_split($binaryString, 5);
|
||||
$base32 = "";
|
||||
$i=0;
|
||||
|
||||
while($i < count($fiveBitBinaryArray)) {
|
||||
$base32 .= self::$map[base_convert(str_pad($fiveBitBinaryArray[$i], 5,'0'), 2, 10)];
|
||||
$i++;
|
||||
}
|
||||
|
||||
if($padding && ($x = strlen($binaryString) % 40) != 0) {
|
||||
if($x == 8) $base32 .= str_repeat(self::$map[32], 6);
|
||||
else if($x == 16) $base32 .= str_repeat(self::$map[32], 4);
|
||||
else if($x == 24) $base32 .= str_repeat(self::$map[32], 3);
|
||||
else if($x == 32) $base32 .= self::$map[32];
|
||||
}
|
||||
|
||||
return $base32;
|
||||
}
|
||||
|
||||
public static function decode($input) {
|
||||
if(empty($input)) return;
|
||||
|
||||
$paddingCharCount = substr_count($input, self::$map[32]);
|
||||
$allowedValues = array(6,4,3,1,0);
|
||||
|
||||
if(!in_array($paddingCharCount, $allowedValues)) return false;
|
||||
|
||||
for($i=0; $i<4; $i++){
|
||||
if($paddingCharCount == $allowedValues[$i] &&
|
||||
substr($input, -($allowedValues[$i])) != str_repeat(self::$map[32], $allowedValues[$i])) return false;
|
||||
}
|
||||
|
||||
$input = str_replace('=','', $input);
|
||||
$input = str_split($input);
|
||||
$binaryString = "";
|
||||
|
||||
for($i=0; $i < count($input); $i = $i+8) {
|
||||
$x = "";
|
||||
|
||||
if(!in_array($input[$i], self::$map)) return false;
|
||||
|
||||
for($j=0; $j < 8; $j++) {
|
||||
$x .= str_pad(base_convert(@self::$flippedMap[@$input[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
$eightBits = str_split($x, 8);
|
||||
|
||||
for($z = 0; $z < count($eightBits); $z++) {
|
||||
$binaryString .= ( ($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48 ) ? $y:"";
|
||||
}
|
||||
}
|
||||
|
||||
return $binaryString;
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
$session_name = $row['name'];
|
||||
$session_avatar = $row['avatar'];
|
||||
$session_client_id = $row['client_id'];
|
||||
$session_token = $row['token'];
|
||||
|
||||
//Detects if using an apple device and uses apple maps instead of google
|
||||
$iPod = stripos($_SERVER['HTTP_USER_AGENT'],"iPod");
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ $url_query_strings_sb = http_build_query(array_merge($_GET,array('sb' => $sb, 'o
|
|||
|
||||
if(isset($_GET['p'])){
|
||||
$p = intval($_GET['p']);
|
||||
$record_from = (($p)-1)*10;
|
||||
$record_to = 10;
|
||||
$record_from = (($p)-1)*6;
|
||||
$record_to = 6;
|
||||
}else{
|
||||
$record_from = 0;
|
||||
$record_to = 10;
|
||||
$record_to = 6;
|
||||
$p = 1;
|
||||
}
|
||||
|
||||
|
|
@ -39,12 +39,9 @@ if(isset($_GET['o'])){
|
|||
$disp = "DESC";
|
||||
}
|
||||
|
||||
|
||||
$sql = mysqli_query($mysqli,"SELECT SQL_CALC_FOUND_ROWS * FROM contacts WHERE client_id = $client_id AND (contact_name LIKE '%$q%') ORDER BY $sb $o LIMIT $record_from, $record_to");
|
||||
$sql = mysqli_query($mysqli,"SELECT SQL_CALC_FOUND_ROWS * FROM contacts WHERE client_id = $client_id AND (contact_name LIKE '%$q%') ORDER BY $sb $o LIMIT $record_from, $record_to");
|
||||
|
||||
$num_rows = mysqli_fetch_row(mysqli_query($mysqli,"SELECT FOUND_ROWS()"));
|
||||
$total_found_rows = $num_rows[0];
|
||||
$total_pages = ceil($total_found_rows / 10);
|
||||
|
||||
?>
|
||||
|
||||
|
|
|
|||
16
clients.php
16
clients.php
|
|
@ -42,8 +42,6 @@ if(isset($_GET['o'])){
|
|||
$sql = mysqli_query($mysqli,"SELECT SQL_CALC_FOUND_ROWS * FROM clients WHERE client_name LIKE '%$q%' OR client_email LIKE '%$q%' ORDER BY $sb $o LIMIT $record_from, $record_to");
|
||||
|
||||
$num_rows = mysqli_fetch_row(mysqli_query($mysqli,"SELECT FOUND_ROWS()"));
|
||||
$total_found_rows = $num_rows[0];
|
||||
$total_pages = ceil($total_found_rows / 10);
|
||||
|
||||
?>
|
||||
|
||||
|
|
@ -51,7 +49,7 @@ $total_pages = ceil($total_found_rows / 10);
|
|||
<div class="card-header bg-dark text-white">
|
||||
|
||||
<h6 class="float-left mt-2"><i class="fa fa-users mr-2"></i>Clients</h6>
|
||||
<button type="button" class="btn btn-primary float-right" data-toggle="modal" data-target="#addClientModal"><i class="fas fa-fw fa-user-plus"></i> New</button>
|
||||
<button type="button" class="btn btn-primary btn-sm float-right" data-toggle="modal" data-target="#addClientModal"><i class="fas fa-fw fa-user-plus"></i> New</button>
|
||||
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
|
@ -68,12 +66,12 @@ $total_pages = ceil($total_found_rows / 10);
|
|||
<table class="table table-striped table-borderless table-hover">
|
||||
<thead class="text-dark">
|
||||
<tr>
|
||||
<th><a class="text-secondary" href="?<?php echo $url_query_strings_sb; ?>&sb=client_name&o=<?php echo $disp; ?>">Name <i class="fa fa-sort<?php if($disp=='ASC'){ echo "-up"; }else{ echo "-down"; }?>"></i></a></th>
|
||||
<th><a href="?<?php echo $url_query_strings_sb; ?>&sb=client_type&o=<?php echo $disp; ?>">Type <i class="fa fa-sort-up"></i></a></th>
|
||||
<th>Email</th>
|
||||
<th>Phone</th>
|
||||
<th class="text-right">Balance</th>
|
||||
<th class="text-center">Action</th>
|
||||
<th class="w-50"><a class="text-secondary" href="?<?php echo $url_query_strings_sb; ?>&sb=client_name&o=<?php echo $disp; ?>">Name <i class="fa fa-sort<?php if($disp=='ASC'){ echo "-up"; }else{ echo "-down"; }?>"></i></a></th>
|
||||
<th class="w-10"><a href="?<?php echo $url_query_strings_sb; ?>&sb=client_type&o=<?php echo $disp; ?>">Type <i class="fa fa-sort-up"></i></a></th>
|
||||
<th class="w-10">Email</th>
|
||||
<th class="w-10">Phone</th>
|
||||
<th class="w-10 text-right">Balance</th>
|
||||
<th class="w-10 text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,21 @@ function keygen()
|
|||
return $key;
|
||||
}
|
||||
|
||||
function key32gen()
|
||||
{
|
||||
$chars .= "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
$chars .= "234567";
|
||||
while (1) {
|
||||
$key = '';
|
||||
srand((double) microtime() * 1000000);
|
||||
for ($i = 0; $i < 32; $i++) {
|
||||
$key .= substr($chars, (rand() % (strlen($chars))), 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $key;
|
||||
}
|
||||
|
||||
function initials($str) {
|
||||
$ret = '';
|
||||
foreach (explode(' ', $str) as $word)
|
||||
|
|
|
|||
48
login.php
48
login.php
|
|
@ -8,22 +8,48 @@ if(isset($_POST['login'])){
|
|||
|
||||
$email = mysqli_real_escape_string($mysqli,$_POST['email']);
|
||||
$password = md5(mysqli_real_escape_string($mysqli,$_POST['password']));
|
||||
$current_code = $_POST['current_code'];
|
||||
|
||||
$sql = mysqli_query($mysqli,"SELECT * FROM users WHERE email = '$email' AND password = '$password'");
|
||||
|
||||
if(mysqli_num_rows($sql) == 1){
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$_SESSION['logged'] = TRUE;
|
||||
$_SESSION['user_id'] = $row['user_id'];
|
||||
$_SESSION['name'] = $row['name'];
|
||||
$_SESSION['client_id'] = $row['client_id'];
|
||||
$client_id = $row['client_id'];
|
||||
$token = $row['token'];
|
||||
|
||||
if(empty($token)){
|
||||
$_SESSION['logged'] = TRUE;
|
||||
$_SESSION['user_id'] = $row['user_id'];
|
||||
$_SESSION['name'] = $row['name'];
|
||||
$_SESSION['client_id'] = $row['client_id'];
|
||||
$client_id = $row['client_id'];
|
||||
|
||||
|
||||
if($client_id > 0){
|
||||
header("Location: client.php?client_id=$client_id");
|
||||
if($client_id > 0){
|
||||
header("Location: client.php?client_id=$client_id");
|
||||
}else{
|
||||
header("Location: $config_start_page");
|
||||
}
|
||||
|
||||
}else{
|
||||
header("Location: $config_start_page");
|
||||
require_once("rfc6238.php");
|
||||
|
||||
if(TokenAuth6238::verify($token,$current_code)){
|
||||
$_SESSION['logged'] = TRUE;
|
||||
$_SESSION['user_id'] = $row['user_id'];
|
||||
$_SESSION['name'] = $row['name'];
|
||||
$_SESSION['client_id'] = $row['client_id'];
|
||||
$client_id = $row['client_id'];
|
||||
header("Location: $config_start_page");
|
||||
}else{
|
||||
$response = "
|
||||
<div class='alert alert-danger'>
|
||||
Invalid Code.
|
||||
<button class='close' data-dismiss='alert'>×</button>
|
||||
</div>
|
||||
";
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
$response = "
|
||||
<div class='alert alert-danger'>
|
||||
|
|
@ -79,6 +105,12 @@ if(isset($_POST['login'])){
|
|||
<label for="inputPassword">Password</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-label-group">
|
||||
<input type="text" id="inputToken" name="current_code" class="form-control" placeholder="2FA Token if applicable">
|
||||
<label for="inputToken">Token</label>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-primary btn-block" type="submit" name="login">Login</button>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,59 +1,62 @@
|
|||
<?php
|
||||
<?php
|
||||
|
||||
$total_found_rows = $num_rows[0];
|
||||
$total_pages = ceil($total_found_rows / 10);
|
||||
|
||||
if ($total_found_rows > 10) {
|
||||
|
||||
?>
|
||||
|
||||
<ul class="pagination justify-content-end">
|
||||
<ul class="pagination justify-content-end">
|
||||
|
||||
<?php
|
||||
|
||||
if($total_pages <= 100){
|
||||
$pages_split = 10;
|
||||
}
|
||||
if(($total_pages <= 1000) AND ($total_pages > 100)){
|
||||
$pages_split = 100;
|
||||
}
|
||||
if(($total_pages <= 10000) AND ($total_pages > 1000)){
|
||||
$pages_split = 1000;
|
||||
}
|
||||
if($p > 1){
|
||||
$prev_class = "";
|
||||
}else{
|
||||
$prev_class = "disabled";
|
||||
}
|
||||
if($p <> $total_pages) {
|
||||
$next_class = "";
|
||||
}else{
|
||||
$next_class = "disabled";
|
||||
}
|
||||
$url_query_strings = http_build_query(array_merge($_GET,array('p' => $i)));
|
||||
$prev_page = $p - 1;
|
||||
$next_page = $p + 1;
|
||||
|
||||
if($p > 1){
|
||||
echo "<li class='page-item $prev_class'><a class='page-link' href='?$url_query_strings&p=$prev_page'>Prev</a></li>";
|
||||
}
|
||||
|
||||
while($i < $total_pages){
|
||||
$i++;
|
||||
if(($i == 1) OR (($p <= 3) AND ($i <= 6)) OR (($i > $total_pages - 6) AND ($p > $total_pages - 3 )) OR (is_int($i / $pages_split)) OR (($p > 3) AND ($i >= $p - 2) AND ($i <= $p + 3)) OR ($i == $total_pages)){
|
||||
if($p == $i ) {
|
||||
$page_class = "active";
|
||||
}else{
|
||||
$page_class = "";
|
||||
}
|
||||
echo "<li class='page-item $page_class'><a class='page-link' href='?$url_query_strings&p=$i'>$i</a></li>";
|
||||
<?php
|
||||
|
||||
if($total_pages <= 100){
|
||||
$pages_split = 10;
|
||||
}
|
||||
if(($total_pages <= 1000) AND ($total_pages > 100)){
|
||||
$pages_split = 100;
|
||||
}
|
||||
if(($total_pages <= 10000) AND ($total_pages > 1000)){
|
||||
$pages_split = 1000;
|
||||
}
|
||||
if($p > 1){
|
||||
$prev_class = "";
|
||||
}else{
|
||||
$prev_class = "disabled";
|
||||
}
|
||||
if($p <> $total_pages) {
|
||||
$next_class = "";
|
||||
}else{
|
||||
$next_class = "disabled";
|
||||
}
|
||||
$url_query_strings = http_build_query(array_merge($_GET,array('p' => $i)));
|
||||
$prev_page = $p - 1;
|
||||
$next_page = $p + 1;
|
||||
|
||||
if($p > 1){
|
||||
echo "<li class='page-item $prev_class'><a class='page-link' href='?$url_query_strings&p=$prev_page'>Prev</a></li>";
|
||||
}
|
||||
|
||||
while($i < $total_pages){
|
||||
$i++;
|
||||
if(($i == 1) OR (($p <= 3) AND ($i <= 6)) OR (($i > $total_pages - 6) AND ($p > $total_pages - 3 )) OR (is_int($i / $pages_split)) OR (($p > 3) AND ($i >= $p - 2) AND ($i <= $p + 3)) OR ($i == $total_pages)){
|
||||
if($p == $i ) {
|
||||
$page_class = "active";
|
||||
}else{
|
||||
$page_class = "";
|
||||
}
|
||||
echo "<li class='page-item $page_class'><a class='page-link' href='?$url_query_strings&p=$i'>$i</a></li>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($p <> $total_pages){
|
||||
echo "<li class='page_item $next_class'><a class='page-link' href='?$url_query_strings&p=$next_page'>Next</a></li>";
|
||||
}
|
||||
if($p <> $total_pages){
|
||||
echo "<li class='page_item $next_class'><a class='page-link' href='?$url_query_strings&p=$next_page'>Next</a></li>";
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
||||
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
<?php
|
||||
|
||||
|
|
|
|||
27
post.php
27
post.php
|
|
@ -15,6 +15,21 @@ use PHPMailer\PHPMailer\Exception;
|
|||
|
||||
$todays_date = date('Y-m-d');
|
||||
|
||||
if(isset($_POST['verify'])){
|
||||
|
||||
require_once("rfc6238.php");
|
||||
$currentcode = $_POST['code']; //code to validate, for example received from device
|
||||
|
||||
if(TokenAuth6238::verify($session_token,$currentcode)){
|
||||
$_SESSION['alert_message'] = "VALID!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
|
||||
}else{
|
||||
$_SESSION['alert_message'] = "INVALID";
|
||||
}
|
||||
|
||||
header("Location: " . $_SERVER["HTTP_REFERER"]);
|
||||
|
||||
}
|
||||
|
||||
if(isset($_POST['edit_general_settings'])){
|
||||
|
||||
$config_start_page = strip_tags(mysqli_real_escape_string($mysqli,$_POST['config_start_page']));
|
||||
|
|
@ -100,6 +115,18 @@ if(isset($_POST['edit_invoice_settings'])){
|
|||
|
||||
}
|
||||
|
||||
if(isset($_POST['settings_2fa'])){
|
||||
|
||||
$token = mysqli_real_escape_string($mysqli,$_POST['token']);
|
||||
|
||||
mysqli_query($mysqli,"UPDATE users SET token = '$token' WHERE user_id = $session_user_id");
|
||||
|
||||
$_SESSION['alert_message'] = "Updated User Token";
|
||||
|
||||
header("Location: " . $_SERVER["HTTP_REFERER"]);
|
||||
|
||||
}
|
||||
|
||||
if(isset($_GET['download_database'])){
|
||||
|
||||
// Get All Table Names From the Database
|
||||
|
|
|
|||
|
|
@ -0,0 +1,171 @@
|
|||
<?php
|
||||
// http://www.faqs.org/rfcs/rfc6238.html
|
||||
require_once(dirname(__FILE__).'/base32static.php');
|
||||
class TokenAuth6238 {
|
||||
|
||||
/**
|
||||
* verify
|
||||
*
|
||||
* @param string $secretkey Secret clue (base 32).
|
||||
* @return bool True if success, false if failure
|
||||
*/
|
||||
public static function verify($secretkey, $code, $rangein30s = 3) {
|
||||
$key = base32static::decode($secretkey);
|
||||
$unixtimestamp = time()/30;
|
||||
|
||||
for($i=-($rangein30s); $i<=$rangein30s; $i++) {
|
||||
$checktime = (int)($unixtimestamp+$i);
|
||||
$thiskey = self::oath_hotp($key, $checktime);
|
||||
|
||||
if ((int)$code == self::oath_truncate($thiskey,6)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public static function getTokenCode($secretkey,$rangein30s = 3) {
|
||||
$result = "";
|
||||
$key = base32static::decode($secretkey);
|
||||
$unixtimestamp = time()/30;
|
||||
|
||||
for($i=-($rangein30s); $i<=$rangein30s; $i++) {
|
||||
$checktime = (int)($unixtimestamp+$i);
|
||||
$thiskey = self::oath_hotp($key, $checktime);
|
||||
$result = $result." # ".self::oath_truncate($thiskey,6);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
public static function getTokenCodeDebug($secretkey,$rangein30s = 3) {
|
||||
$result = "";
|
||||
print "<br/>SecretKey: $secretkey <br/>";
|
||||
|
||||
$key = base32static::decode($secretkey);
|
||||
print "Key(base 32 decode): $key <br/>";
|
||||
|
||||
$unixtimestamp = time()/30;
|
||||
print "UnixTimeStamp (time()/30): $unixtimestamp <br/>";
|
||||
for($i=-($rangein30s); $i<=$rangein30s; $i++) {
|
||||
$checktime = (int)($unixtimestamp+$i);
|
||||
print "Calculating oath_hotp from (int)(unixtimestamp +- 30sec offset): $checktime basing on secret key<br/>";
|
||||
|
||||
$thiskey = self::oath_hotp($key, $checktime, true);
|
||||
print "======================================================<br/>";
|
||||
print "CheckTime: $checktime oath_hotp:".$thiskey."<br/>";
|
||||
$result = $result." # ".self::oath_truncate($thiskey,6,true);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function getBarCodeUrl($username, $domain, $secretkey, $issuer) {
|
||||
$url = "http://chart.apis.google.com/chart";
|
||||
$url = $url."?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/";
|
||||
$url = $url.$username . "@" . $domain . "%3Fsecret%3D" . $secretkey . '%26issuer%3D' . rawurlencode($issuer);
|
||||
|
||||
return $url;
|
||||
}
|
||||
public static function generateRandomClue($length = 16) {
|
||||
$b32 = "234567QWERTYUIOPASDFGHJKLZXCVBNM";
|
||||
$s = "";
|
||||
for ($i = 0; $i < $length; $i++)
|
||||
$s .= $b32[rand(0,31)];
|
||||
return $s;
|
||||
}
|
||||
|
||||
private static function hotp_tobytestream($key) {
|
||||
$result = array();
|
||||
$last = strlen($key);
|
||||
for ($i = 0; $i < $last; $i = $i + 2) {
|
||||
$x = $key[$i] + $key[$i + 1];
|
||||
$x = strtoupper($x);
|
||||
$x = hexdec($x);
|
||||
$result = $result.chr($x);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
private static function oath_hotp ($key, $counter, $debug=false) {
|
||||
$result = "";
|
||||
$orgcounter = $counter;
|
||||
$cur_counter = array(0,0,0,0,0,0,0,0);
|
||||
|
||||
if ($debug) {
|
||||
print "Packing counter $counter (".dechex($counter).")into binary string - pay attention to hex representation of key and binary representation<br/>";
|
||||
}
|
||||
|
||||
for($i=7;$i>=0;$i--) { // C for unsigned char, * for repeating to the end of the input data
|
||||
$cur_counter[$i] = pack ('C*', $counter);
|
||||
|
||||
if ($debug) {
|
||||
print $cur_counter[$i]."(".dechex(ord($cur_counter[$i])).")"." from $counter <br/>";
|
||||
}
|
||||
|
||||
$counter = $counter >> 8;
|
||||
}
|
||||
|
||||
if ($debug) {
|
||||
foreach ($cur_counter as $char) {
|
||||
print ord($char) . " ";
|
||||
}
|
||||
|
||||
print "<br/>";
|
||||
}
|
||||
|
||||
$binary = implode($cur_counter);
|
||||
// Pad to 8 characters
|
||||
str_pad($binary, 8, chr(0), STR_PAD_LEFT);
|
||||
|
||||
if ($debug) {
|
||||
print "Prior to HMAC calculation pad with zero on the left until 8 characters.<br/>";
|
||||
print "Calculate sha1 HMAC(Hash-based Message Authentication Code http://en.wikipedia.org/wiki/HMAC).<br/>";
|
||||
print "hash_hmac ('sha1', $binary, $key)<br/>";
|
||||
}
|
||||
$result = hash_hmac ('sha1', $binary, $key);
|
||||
|
||||
if ($debug) {
|
||||
print "Result: $result <br/>";
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
private static function oath_truncate($hash, $length = 6, $debug=false) {
|
||||
$result="";
|
||||
|
||||
// Convert to dec
|
||||
if($debug) {
|
||||
print "converting hex hash into characters<br/>";
|
||||
}
|
||||
|
||||
$hashcharacters = str_split($hash,2);
|
||||
|
||||
if($debug) {
|
||||
print_r($hashcharacters);
|
||||
print "<br/>and convert to decimals:<br/>";
|
||||
}
|
||||
for ($j=0; $j<count($hashcharacters); $j++) {
|
||||
$hmac_result[]=hexdec($hashcharacters[$j]);
|
||||
}
|
||||
|
||||
if($debug) {
|
||||
print_r($hmac_result);
|
||||
}
|
||||
// http://php.net/manual/ru/function.hash-hmac.php
|
||||
// adopted from brent at thebrent dot net 21-May-2009 08:17 comment
|
||||
$offset = $hmac_result[19] & 0xf;
|
||||
|
||||
if($debug) {
|
||||
print "Calculating offset as 19th element of hmac:".$hmac_result[19]."<br/>";
|
||||
print "offset:".$offset;
|
||||
}
|
||||
|
||||
$result = (
|
||||
(($hmac_result[$offset+0] & 0x7f) << 24 ) |
|
||||
(($hmac_result[$offset+1] & 0xff) << 16 ) |
|
||||
(($hmac_result[$offset+2] & 0xff) << 8 ) |
|
||||
($hmac_result[$offset+3] & 0xff)
|
||||
) % pow(10,$length);
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
<?php include("header.php");
|
||||
|
||||
|
||||
|
||||
?>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h6 class="float-left mt-1"><i class="fa fa-fw fa-cog mr-2"></i>User Settings</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form class="p-3" action="post.php" method="post" autocomplete="off">
|
||||
<input type="hidden" name="secretkey" value="<?php echo $secret_key; ?>">
|
||||
<div class="custom-control custom-switch mb-2">
|
||||
<input type="checkbox" class="custom-control-input" name="en2fa" <?php if($en2fa == 1){ echo "checked"; } ?> value="1" id="customSwitch1">
|
||||
<label class="custom-control-label" for="customSwitch1">Enable Two Factor Authentication</label>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
|
||||
require_once('rfc6238.php');
|
||||
|
||||
//Generate a base32 Key
|
||||
$secretkey = key32gen();
|
||||
|
||||
//Generate QR Code based off the generated key
|
||||
print sprintf('<img src="%s"/>',TokenAuth6238::getBarCodeUrl('','',$secretkey,'PittPC-CRM'));
|
||||
|
||||
?>
|
||||
|
||||
<input type="hidden" name="token" value="<?php echo $secretkey; ?>">
|
||||
<hr>
|
||||
<button type="submit" name="settings_2fa" class="btn btn-primary">Enable</button>
|
||||
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<form class="p-3" action="post.php" method="post" autocomplete="off">
|
||||
<div class="form-group">
|
||||
<label>Enter Code</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-key"></i></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="code" placeholder="Enter Code" required>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<button type="submit" name="verify" class="btn btn-primary">Verify</button>
|
||||
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include("footer.php"); ?>
|
||||
16
test.php
16
test.php
|
|
@ -22,6 +22,22 @@
|
|||
<h1>User Agent: <?php echo $_SERVER['HTTP_USER_AGENT']; ?>
|
||||
<p>This is a great starting point for new custom pages.</p>
|
||||
|
||||
<?php
|
||||
require_once('rfc6238.php');
|
||||
|
||||
$secretkey = 'GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ';
|
||||
$currentcode = '739453';
|
||||
if (TokenAuth6238::verify($secretkey,$currentcode)) {
|
||||
echo "Code is valid\n";
|
||||
} else {
|
||||
echo "Invalid code\n";
|
||||
}
|
||||
print sprintf('<img src="%s"/>',TokenAuth6238::getBarCodeUrl('','',$secretkey,'My%20App'));
|
||||
print TokenAuth6238::getTokenCodeDebug($secretkey,0);
|
||||
|
||||
|
||||
?>
|
||||
|
||||
|
||||
<h3><?php echo $config_quote_email_subject; ?></h3>
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
<center>
|
||||
<img height="128" width="128" src="<?php echo "$session_avatar"; ?>" class="img-fluid rounded-circle">
|
||||
</center>
|
||||
<a class="dropdown-item" href="settings-user.php"><i class="fa fa-fw fa-cog"></i> Settings</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="logout.php"><i class="fa fa-fw fa-sign-out-alt"></i> Logout</a>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue