261 lines
12 KiB
PHP
261 lines
12 KiB
PHP
<?php
|
|
require $_SERVER['DOCUMENT_ROOT'].'/api/private/core.php';
|
|
users::requireLogin();
|
|
$gauth = twofa::initialize();
|
|
|
|
$userinfo = (object)SESSION["userInfo"];
|
|
|
|
$sessions = $pdo->prepare("SELECT * FROM sessions WHERE userId = :uid AND valid AND created+157700000 > UNIX_TIMESTAMP() AND lastonline+432000 > UNIX_TIMESTAMP() ORDER BY created DESC");
|
|
$sessions->bindParam(":uid", $userinfo->id, PDO::PARAM_INT);
|
|
$sessions->execute();
|
|
|
|
$twofa = SESSION["2fa"];
|
|
$twofaSecret = $userinfo->twofaSecret;
|
|
|
|
//2fa stuff is not done dynamically cause 1. its less hassle and 2. because the 2fa panel is the default panel shown in the security area its basically seamless anyway so ehh
|
|
if(isset($_POST["2fa"]))
|
|
{
|
|
$csrf = $_POST['polygon_csrf'] ?? false;
|
|
$code = $_POST['code'] ?? false;
|
|
$password = $_POST['password'] ?? false;
|
|
|
|
if($csrf != SESSION["csrfToken"])
|
|
{
|
|
pageBuilder::showStaticNotification("error", "Invalid CSRF token"); goto pb;
|
|
}
|
|
|
|
if(!$gauth->checkCode($twofaSecret, $code, 1))
|
|
{
|
|
pageBuilder::showStaticNotification("error", "Incorrect code"); goto pb;
|
|
}
|
|
|
|
if(!password_verify($password, $userinfo->password))
|
|
{
|
|
pageBuilder::showStaticNotification("error", "Incorrect password"); goto pb;
|
|
}
|
|
|
|
twofa::toggle();
|
|
$twofa = !SESSION["2fa"];
|
|
|
|
if($twofa)
|
|
{
|
|
$recoveryCodes = twofa::generateRecoveryCodes();
|
|
ob_start();
|
|
?>
|
|
|
|
Congratulations! Your account is now more secure. But, before you go there's one last thing which is <b>really important</b>.
|
|
<br><br>
|
|
If all else fails, if you just cannot regain access to your 2FA app codes, you can use a 2FA recovery code.
|
|
<br><br>
|
|
<div class="row" style="max-width: 16rem; margin: auto;">
|
|
<?php foreach($recoveryCodes as $code) { ?>
|
|
<div class="col-sm-6">
|
|
<code><?=$code?></code>
|
|
</div>
|
|
<?php } ?>
|
|
</div>
|
|
<br>
|
|
These are a set of static, one-time use codes that never expire unless they are used or you re-enable 2FA. You can use these to get back into your account without the need of a 2FA app.
|
|
<br><br>
|
|
This is the only time you'll ever see these here, so write them down somewhere <b>now</b>.
|
|
|
|
<?php
|
|
pageBuilder::showStaticModal(
|
|
"Two-Factor Authentication is now active",
|
|
ob_get_clean(),
|
|
"[{'class':'btn btn-outline-primary', 'isDismissButton':true, 'text':'I understand'}]",
|
|
"{'show':true, 'backdrop':'static'}");
|
|
}
|
|
}
|
|
elseif(!$userinfo->twofa)
|
|
{
|
|
$twofaSecret = $gauth->generateSecret();
|
|
$query = $pdo->prepare("UPDATE users SET twofaSecret = :secret WHERE id = :uid");
|
|
$query->bindParam(":uid", $userinfo->id, PDO::PARAM_INT);
|
|
$query->bindParam(":secret", $twofaSecret, PDO::PARAM_STR);
|
|
$query->execute();
|
|
}
|
|
|
|
pb:
|
|
pageBuilder::$pageConfig["title"] = "My Account";
|
|
pageBuilder::buildHeader();
|
|
?>
|
|
|
|
<h2 class="font-weight-normal">My Account</h2>
|
|
<div class="row">
|
|
<div class="col-md-6 p-0 divider-right">
|
|
<div class="px-4 py-3">
|
|
<h3 class="pb-4 font-weight-normal">Settings</h3>
|
|
<div class="form-group row">
|
|
<label for="blurb" class="col-sm-3 col-form-label">Blurb</label>
|
|
<div class="col-sm-9">
|
|
<textarea type="text" class="form-control" id="blurb"><?=$userinfo->blurb?></textarea>
|
|
<p class="text-muted mb-0">1000 characters max, Markdown is supported</p>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-sm-3">Filter</div>
|
|
<div class="col-sm-9">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="filter"<?=$userinfo->filter?' checked':''?> value="true">
|
|
<p class="text-muted mb-0">[ this replaces words with <strong><em>baba booey</em></strong> ]</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-sm-3">Transitions</div>
|
|
<div class="col-sm-9">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="pageanims"<?=$userinfo->pageanim?' checked':''?> value="true">
|
|
<p class="text-muted mb-0">[ this plays a sliding transition on page loading ]</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<button class="btn btn-primary btn-block" data-control="updateSettings"><span class="spinner-border spinner-border-sm" role="status" aria-hidden="true" style="display:none"></span> Update Account Settings</button>
|
|
</div>
|
|
<!--div class="divider-top"></div>
|
|
<div class="p-3">
|
|
<h3 class="pb-4">Privacy</h3>
|
|
</div-->
|
|
</div>
|
|
<div class="col-md-6 p-0">
|
|
<div class="py-3">
|
|
<h3 class="pb-4 pl-4 font-weight-normal">Security</h3>
|
|
<ul class="nav nav-tabs pl-4" id="securityTabs" role="tablist">
|
|
<li class="nav-item">
|
|
<a class="nav-link active" id="twofa-tab" data-toggle="tab" href="#twofa" role="tab" aria-controls="twofa" aria-selected="true">Two-Factor Authentication</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" id="changepwd-tab" data-toggle="tab" href="#changepwd" role="tab" aria-controls="changepwd" aria-selected="false">Change Password</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" id="sessions-tab" data-toggle="tab" href="#sessions" role="tab" aria-controls="sessions" aria-selected="false">Sessions</a>
|
|
</li>
|
|
</ul>
|
|
<div class="tab-content pt-4 px-4" id="securityTabsContent">
|
|
<div class="tab-pane active" id="twofa" role="tabpanel" aria-labelledby="twofa-tab">
|
|
<?php if($twofa) { ?>
|
|
<p>Two-Factor Authentication is currently active. If you wish to disable it, just fill in the fields below.</p>
|
|
<p>If you disable 2FA your old recovery codes will be invalidated, so just be mindful of that.</p>
|
|
<?php } else { ?>
|
|
<p>It is highly recommended to use a two-factor authentication app that supports backups so that in the event that you lose access to the app or something, you can still get your codes back. Authy is an excellent one.</p>
|
|
<div class="row">
|
|
<div class="col-lg-5 text-center">
|
|
<img class="img-fluid pb-3" style="display:inline" src="<?=$gauth->getURL(SESSION["userName"], "Project Polygon", $twofaSecret)?>">
|
|
</div>
|
|
<div class="col-lg-7">
|
|
<p>Scan the QR code with your authenticator app of choice.</p>
|
|
<p>This changes with every page refresh, so be careful.</p>
|
|
<p>There's also a manual key here if you prefer that: <code><?=$twofaSecret?></code></p>
|
|
</div>
|
|
</div>
|
|
<?php } ?>
|
|
<form method="post">
|
|
<div class="form-group row">
|
|
<label for="code" class="col-sm-3 col-form-label">2FA Code:</label>
|
|
<div class="col-sm-9">
|
|
<input type="number" max="99999999" class="form-control" name="code" id="code" placeholder="00000000 - get this from your 2FA app">
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<label for="password" class="col-sm-3 col-form-label">Password:</label>
|
|
<div class="col-sm-9">
|
|
<input type="password" class="form-control" name="password" id="password" placeholder="just your normal account password">
|
|
</div>
|
|
</div>
|
|
<input type="hidden" name="polygon_csrf" value="<?=SESSION["csrfToken"]?>">
|
|
<input type="hidden" name="twofa_state" value="<?=$twofa?>">
|
|
<button type="submit" name="2fa" class="btn btn-<?=$twofa?'danger':'success'?> btn-block"><?=$twofa?'Dis':'En'?>able Two-Factor Authentication</button>
|
|
</form>
|
|
</div>
|
|
<div class="tab-pane" id="changepwd" role="tabpanel" aria-labelledby="changepwd-tab">
|
|
<div class="form-group row">
|
|
<label for="currentpwd" class="col-sm-4 col-form-label">Current Password</label>
|
|
<div class="col-sm-8">
|
|
<input type="password" class="form-control" id="currentpwd">
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<label for="newpwd" class="col-sm-4 col-form-label">New Password</label>
|
|
<div class="col-sm-8">
|
|
<input type="password" class="form-control" id="newpwd">
|
|
<small class="form-text text-muted">8 - 64 characters, must have at least 6 characters and 2 numbers</small>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<label for="newpwd" class="col-sm-4 col-form-label">Confirm New Password</label>
|
|
<div class="col-sm-8">
|
|
<input type="password" class="form-control" id="confnewpwd">
|
|
</div>
|
|
</div>
|
|
<button class="btn btn-warning btn-block" data-control="updatePassword"><span class="spinner-border spinner-border-sm" role="status" aria-hidden="true" style="display:none"></span> Change Password</button>
|
|
</div>
|
|
<div class="tab-pane" id="sessions" role="tabpanel" aria-labelledby="sessions-tab">
|
|
<div class="row">
|
|
<?php while($session = $sessions->fetch(PDO::FETCH_OBJ)) { $ipInfo = general::getIpInfo($session->loginIp); $browserInfo = get_browser($session->userAgent); ?>
|
|
<div class="col-sm-6 mb-4 <?=$session->sessionKey == $_COOKIE['polygon_session']?'current-session':'session'?>">
|
|
<div class="card<?=$session->sessionKey == $_COOKIE['polygon_session']?' bg-primary text-white':''?>">
|
|
<div class="card-body text-center">
|
|
<h5 class="font-weight-normal"><?=$browserInfo->device_type?> / <?=$browserInfo->browser?></h5>
|
|
<?=$browserInfo->platform?> - <?=$ipInfo->unofficial_names[0]?><br>
|
|
Started <span title="<?=date('j/n/Y h:i:s A', $session->created)?>"><?=general::time_elapsed("@".$session->created)?></span><br>
|
|
<?php if($session->sessionKey == $_COOKIE['polygon_session']){ ?>This is your current session<?php } else { ?>
|
|
Last seen: <span title="<?=date('j/n/Y h:i:s A', $session->lastonline)?>"><?=general::time_elapsed("@".$session->lastonline)?></span><?php } ?>
|
|
<br>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php } ?>
|
|
</div>
|
|
<button class="btn btn-danger btn-block" data-control="destroyOtherSessions"><span class="spinner-border spinner-border-sm" role="status" aria-hidden="true" style="display:none"></span> Log out of all other sessions</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
//account.js
|
|
$('[data-control="updateSettings"]').on('click', this, function()
|
|
{
|
|
var button = this;
|
|
$(button).attr("disabled", "disabled").find("span").show();
|
|
$.post('/api/account/updateSettings', {"blurb": $("#blurb").val(), "filter": $("#filter").is(":checked"), "pageanimations": $("#pageanims").is(":checked")}, function(data)
|
|
{
|
|
if(data.success){ toastr["success"]("Your settings have been updated"); }
|
|
else{ toastr["error"](data.message); }
|
|
$(button).removeAttr("disabled").find("span").hide();
|
|
});
|
|
});
|
|
|
|
$('[data-control="updatePassword"]').on('click', this, function()
|
|
{
|
|
var button = this;
|
|
$(button).attr("disabled", "disabled").find("span").show();
|
|
$.post('/api/account/updatePassword', {"currentpwd": $("#currentpwd").val(), "newpwd": $("#newpwd").val(), "confnewpwd": $("#confnewpwd").val()}, function(data)
|
|
{
|
|
if(data.success){ toastr["success"]("Your password has been updated"); }
|
|
else{ toastr["error"](data.message); }
|
|
$(button).removeAttr("disabled").find("span").hide();
|
|
});
|
|
});
|
|
|
|
$('[data-control="destroyOtherSessions"]').on('click', this, function()
|
|
{
|
|
var button = this;
|
|
$(button).attr("disabled", "disabled").find("span").show();
|
|
$.post('/api/account/destroyOtherSessions', function(data)
|
|
{
|
|
if(data.success)
|
|
{
|
|
toastr["success"]("All other sessions have been logged out");
|
|
$(".session").fadeOut(500);
|
|
}
|
|
else{ toastr["error"](data.message); }
|
|
$(button).removeAttr("disabled").find("span").hide();
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<?php pageBuilder::buildFooter(); ?>
|