Google Authenticator

This commit is contained in:
xiaomlove
2021-06-10 21:07:20 +08:00
parent 37e0d74bae
commit 3bb15d6a41
17 changed files with 339 additions and 23 deletions
@@ -0,0 +1,71 @@
<?php
namespace App\Console\Commands;
use App\Models\Attendance;
use Illuminate\Console\Command;
class AttendanceCleanup extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'attendance:cleanup';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Cleanup attendance data.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$query = Attendance::query()->groupBy('uid')->selectRaw('uid, max(id) as max_id');
$page = 1;
$size = 1000;
while (true) {
$rows = $query->forPage($page, $size)->get();
$log = "sql: " . last_query() . ", count: " . $rows->count();
do_log($log);
$this->info($log);
if ($rows->isEmpty()) {
$log = "no more data....";
do_log($log);
$this->info($log);
break;
}
foreach ($rows as $row) {
do {
$deleted = Attendance::query()
->where('uid', $row->uid)
->where('id', '<', $row->max_id)
->limit(10000)
->delete();
$log = "delete: $deleted by sql: " . last_query();
do_log($log);
$this->info($log);
} while ($deleted > 0);
}
$page++;
}
return 0;
}
}
+2 -2
View File
@@ -2,6 +2,7 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use App\Models\Attendance;
use App\Models\Exam; use App\Models\Exam;
use App\Models\ExamProgress; use App\Models\ExamProgress;
use App\Models\ExamUser; use App\Models\ExamUser;
@@ -52,8 +53,7 @@ class Test extends Command
*/ */
public function handle() public function handle()
{ {
$r = 'https://hdtime.org/download.php?downhash=' . urlencode('1|Roqd');
dd($r);
} }
} }
+12
View File
@@ -0,0 +1,12 @@
<?php
namespace App\Models;
class Attendance extends NexusModel
{
protected $table = 'attendance';
protected $casts = [
'added' => 'datetime',
];
}
+25 -6
View File
@@ -23,10 +23,16 @@ class Attendance
public function attend($initial = 10, $step = 5, $maximum = 2000, $continous = array()) public function attend($initial = 10, $step = 5, $maximum = 2000, $continous = array())
{ {
if($this->check(true)) return false; if($this->check(true)) return false;
$count = get_row_count('attendance', sprintf('WHERE `uid` = %u', $this->userid)); $res = sql_query(sprintf('SELECT DATEDIFF(%s, `added`) AS diff, `days`, `total_days`, `total_points` FROM `attendance` WHERE `uid` = %u ORDER BY `id` DESC LIMIT 1', sqlesc($this->curdate), $this->userid)) or sqlerr(__FILE__,__LINE__);
$points = min($initial + $step * $count, $maximum); $doUpdate = mysql_num_rows($res);
$res = sql_query(sprintf('SELECT DATEDIFF(%s, `added`) AS diff, `days` FROM `attendance` WHERE `uid` = %u ORDER BY `id` DESC LIMIT 1', sqlesc($this->curdate), $this->userid)) or sqlerr(__FILE__,__LINE__); if ($doUpdate) {
list($datediff, $days) = mysql_num_rows($res) ? mysql_fetch_row($res) : array('diff' => 0, 'days' => 0); $row = mysql_fetch_row($res);
do_log("uid: {$this->userid}, row: " . json_encode($row));
} else {
$row = [0, 0, 0, 0];
}
$points = min($initial + $step * $row['total_attend_times'], $maximum);
list($datediff, $days, $totalDays, $totalPoints) = $row;
$cdays = $datediff == 1 ? ++$days : 1; $cdays = $datediff == 1 ? ++$days : 1;
if($cdays > 1){ if($cdays > 1){
krsort($continous); krsort($continous);
@@ -37,10 +43,23 @@ class Attendance
} }
} }
} }
sql_query(sprintf('INSERT INTO `attendance` (`uid`,`added`,`points`,`days`) VALUES (%u, %s, %u, %u)', $this->userid, sqlesc(date('Y-m-d H:i:s')), $points, $cdays)) or sqlerr(__FILE__, __LINE__); // sql_query(sprintf('INSERT INTO `attendance` (`uid`,`added`,`points`,`days`) VALUES (%u, %s, %u, %u)', $this->userid, sqlesc(date('Y-m-d H:i:s')), $points, $cdays)) or sqlerr(__FILE__, __LINE__);
if ($doUpdate) {
$sql = sprintf(
'UPDATE `attendance` set added = %s, points = %s, days = %s, total_days= %s, total_points = %s where uid = %s order by id desc limit 1',
sqlesc(date('Y-m-d H:i:s')), $points, $cdays, $totalDays + 1, $totalPoints + $points, $this->userid
);
} else {
$sql = sprintf(
'INSERT INTO `attendance` (`uid`, `added`, `points`, `days`, `total_days`, `total_points`) VALUES (%u, %s, %u, %u, %u, %u)',
$this->userid, sqlesc(date('Y-m-d H:i:s')), $points, $cdays, $totalDays + 1, $totalPoints + $points
);
}
do_log(sprintf('uid: %s, date: %s, doUpdate: %s, sql: %s', $this->userid, $this->curdate, $doUpdate, $sql), 'notice');
sql_query($sql) or sqlerr(__FILE__, __LINE__);
KPS('+', $points, $this->userid); KPS('+', $points, $this->userid);
global $Cache; global $Cache;
$Cache->delete_value($this->cachename); $Cache->delete_value($this->cachename);
return array(++$count, $cdays, $points); return array(++$totalDays, $cdays, $points);
} }
} }
+1
View File
@@ -41,6 +41,7 @@
"laravel/tinker": "^2.5", "laravel/tinker": "^2.5",
"nao-pon/flysystem-google-drive": "^1.1", "nao-pon/flysystem-google-drive": "^1.1",
"orangehill/iseed": "^3.0", "orangehill/iseed": "^3.0",
"phpgangsta/googleauthenticator": "dev-master",
"rhilip/bencode": "^1.1", "rhilip/bencode": "^1.1",
"swiftmailer/swiftmailer": "^6.2" "swiftmailer/swiftmailer": "^6.2"
}, },
Generated
+58 -2
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "a4f805b49bd52cf34ee5f763976ed030", "content-hash": "fcf04cef5848b9eb1d15b0c297de364f",
"packages": [ "packages": [
{ {
"name": "asm89/stack-cors", "name": "asm89/stack-cors",
@@ -3282,6 +3282,60 @@
}, },
"time": "2020-10-15T08:29:30+00:00" "time": "2020-10-15T08:29:30+00:00"
}, },
{
"name": "phpgangsta/googleauthenticator",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/PHPGangsta/GoogleAuthenticator.git",
"reference": "505c2af8337b559b33557f37cda38e5f843f3768"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPGangsta/GoogleAuthenticator/zipball/505c2af8337b559b33557f37cda38e5f843f3768",
"reference": "505c2af8337b559b33557f37cda38e5f843f3768",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": ">=5.3"
},
"default-branch": true,
"type": "library",
"autoload": {
"classmap": [
"PHPGangsta/GoogleAuthenticator.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-4-Clause"
],
"authors": [
{
"name": "Michael Kliewe",
"email": "info@phpgangsta.de",
"homepage": "http://www.phpgangsta.de/",
"role": "Developer"
}
],
"description": "Google Authenticator 2-factor authentication",
"keywords": [
"googleauthenticator",
"rfc6238",
"totp"
],
"support": {
"issues": "https://github.com/PHPGangsta/GoogleAuthenticator/issues",
"source": "https://github.com/PHPGangsta/GoogleAuthenticator"
},
"time": "2019-03-20T00:55:58+00:00"
},
{ {
"name": "phpoption/phpoption", "name": "phpoption/phpoption",
"version": "1.7.5", "version": "1.7.5",
@@ -9400,7 +9454,9 @@
], ],
"aliases": [], "aliases": [],
"minimum-stability": "dev", "minimum-stability": "dev",
"stability-flags": [], "stability-flags": {
"phpgangsta/googleauthenticator": 20
},
"prefer-stable": true, "prefer-stable": true,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
@@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddTotalDaysAndTotalPointsToAttendanceTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
if (Schema::hasColumns('attendance',['total_days', 'total_points'])) {
return;
}
Schema::table('attendance', function (Blueprint $table) {
$table->integer('total_days')->default(0);
$table->integer('total_points')->default(0);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('attendance', function (Blueprint $table) {
$table->dropColumn(['total_days', 'total_points']);
});
}
}
@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddTwoStepSecretToUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
if (Schema::hasColumns('users',['two_step_secret', ])) {
return;
}
Schema::table('users', function (Blueprint $table) {
$table->string('two_step_secret')->default('');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('two_step_secret');
});
}
}
+1 -1
View File
@@ -2476,7 +2476,7 @@ else {
<?php if (get_user_class() >= UC_SYSOP) { ?> [<a href="settings.php"><?php echo $lang_functions['text_site_settings'] ?></a>]<?php } ?> <?php if (get_user_class() >= UC_SYSOP) { ?> [<a href="settings.php"><?php echo $lang_functions['text_site_settings'] ?></a>]<?php } ?>
[<a href="torrents.php?inclbookmarked=1&amp;allsec=1&amp;incldead=0"><?php echo $lang_functions['text_bookmarks'] ?></a>] [<a href="torrents.php?inclbookmarked=1&amp;allsec=1&amp;incldead=0"><?php echo $lang_functions['text_bookmarks'] ?></a>]
<font class = 'color_bonus'><?php echo $lang_functions['text_bonus'] ?></font>[<a href="mybonus.php"><?php echo $lang_functions['text_use'] ?></a>]: <?php echo number_format($CURUSER['seedbonus'], 1)?> <font class = 'color_bonus'><?php echo $lang_functions['text_bonus'] ?></font>[<a href="mybonus.php"><?php echo $lang_functions['text_use'] ?></a>]: <?php echo number_format($CURUSER['seedbonus'], 1)?>
<?php if($attendance){ printf('&nbsp;'.$lang_functions['text_attended'], $attendance['points']); }else{ printf(' <a href="attendance.php" class="faqlink">%s</a>', $lang_functions['text_attendance']);}?> <?php if($attendance){ printf('&nbsp;'.$lang_functions['text_attended'], $attendance['total_points']); }else{ printf(' <a href="attendance.php" class="faqlink">%s</a>', $lang_functions['text_attendance']);}?>
<font class = 'color_invite'><?php echo $lang_functions['text_invite'] ?></font>[<a href="invite.php?id=<?php echo $CURUSER['id']?>"><?php echo $lang_functions['text_send'] ?></a>]: <?php echo $CURUSER['invites']?><br /> <font class = 'color_invite'><?php echo $lang_functions['text_invite'] ?></font>[<a href="invite.php?id=<?php echo $CURUSER['id']?>"><?php echo $lang_functions['text_send'] ?></a>]: <?php echo $CURUSER['invites']?><br />
<font class="color_ratio"><?php echo $lang_functions['text_ratio'] ?></font> <?php echo $ratio?> <font class="color_ratio"><?php echo $lang_functions['text_ratio'] ?></font> <?php echo $ratio?>
<font class='color_uploaded'><?php echo $lang_functions['text_uploaded'] ?></font> <?php echo mksize($CURUSER['uploaded'])?> <font class='color_uploaded'><?php echo $lang_functions['text_uploaded'] ?></font> <?php echo mksize($CURUSER['uploaded'])?>
+24 -7
View File
@@ -544,16 +544,33 @@ function fail(...$args)
function last_query($all = false) function last_query($all = false)
{ {
if (IN_NEXUS) { static $connection, $pdo;
$queries = \Illuminate\Database\Capsule\Manager::connection(\Nexus\Database\NexusDB::ELOQUENT_CONNECTION_NAME)->getQueryLog(); if (is_null($connection)) {
} else { if (IN_NEXUS) {
$queries = \Illuminate\Support\Facades\DB::connection(config('database.default'))->getQueryLog(); $connection = \Illuminate\Database\Capsule\Manager::connection(\Nexus\Database\NexusDB::ELOQUENT_CONNECTION_NAME);
} else {
$connection = \Illuminate\Support\Facades\DB::connection(config('database.default'));
}
$pdo = $connection->getPdo();
}
$queries = $connection->getQueryLog();
if (!$all) {
$queries = [last($queries)];
}
$queryFormatted = [];
foreach ($queries as $query) {
$sqlWithPlaceholders = str_replace(['%', '?'], ['%%', '%s'], $query['query']);
$bindings = $query['bindings'];
$realSql = $sqlWithPlaceholders;
if (count($bindings) > 0) {
$realSql = vsprintf($sqlWithPlaceholders, array_map([$pdo, 'quote'], $bindings));
}
$queryFormatted[] = $realSql;
} }
if ($all) { if ($all) {
return nexus_json_encode($queries); return nexus_json_encode($queryFormatted);
} }
$query = last($queries); return $queryFormatted[0];
return nexus_json_encode($query);
} }
function format_datetime($datetime, $format = 'Y-m-d H:i') function format_datetime($datetime, $format = 'Y-m-d H:i')
+2
View File
@@ -32,5 +32,7 @@ $lang_login = array
'submit_clear' => "清空", 'submit_clear' => "清空",
'text_select_lang' => "Select Site Language: ", 'text_select_lang' => "Select Site Language: ",
'head_login' => "登录", 'head_login' => "登录",
'rowhead_two_step_code' => '两步验证',
'two_step_code_tooltip' => '如有设置必须填写',
); );
?> ?>
+2
View File
@@ -6,6 +6,8 @@ $lang_takelogin = array
'std_login_fail' => "登录失败!", 'std_login_fail' => "登录失败!",
'std_account_disabled' => "该账号已被禁用。", 'std_account_disabled' => "该账号已被禁用。",
'std_user_account_unconfirmed' => "该账户还未通过验证。如果你没有收到验证邮件,试试<a href='confirm_resend.php'><b>重新发送验证邮件</b></a>。", 'std_user_account_unconfirmed' => "该账户还未通过验证。如果你没有收到验证邮件,试试<a href='confirm_resend.php'><b>重新发送验证邮件</b></a>。",
'std_require_two_step_code' => '需要两步验证 code',
'std_invalid_two_step_code' => '两步验证 code 无效',
); );
?> ?>
+6 -1
View File
@@ -245,7 +245,12 @@ $lang_usercp = array
'text_show_advertisement_note' => "我想看到广告", 'text_show_advertisement_note' => "我想看到广告",
'row_promotion_link' => "宣传链接", 'row_promotion_link' => "宣传链接",
'text_update_promotion_link' => "更新宣传链接", 'text_update_promotion_link' => "更新宣传链接",
'text_read_more' => "了解更多" 'text_read_more' => "了解更多",
'row_two_step_secret' => '两步验证',
'text_two_step_secret_bind_by_qrdoe_note' => '你可以使用 Google Authenticator 或 Authy 扫描左侧二维码<br/><br/>如果左侧二维码没有加载成功,可以尝试打开此链接进行加载:',
'text_two_step_secret_bind_manually_note' => '或者在 APP 中手动输入以下 Key',
'text_two_step_secret_bind_complete_note' => '输入 code 完成两步验证',
'text_two_step_secret_unbind_note' => '输入 code 取消两步验证',
); );
?> ?>
+4 -1
View File
@@ -245,7 +245,10 @@ $lang_usercp = array
'text_show_advertisement_note' => "I'd like to see the advertisements", 'text_show_advertisement_note' => "I'd like to see the advertisements",
'row_promotion_link' => "Promotion Link", 'row_promotion_link' => "Promotion Link",
'text_update_promotion_link' => "Update Promotion Link", 'text_update_promotion_link' => "Update Promotion Link",
'text_read_more' => "Read More" 'text_read_more' => "Read More",
'row_two_step_secret' => 'Two step authentication',
'text_two_step_secret_bind_note' => '',
'text_two_step_secret_remove_note' => '',
); );
?> ?>
+1
View File
@@ -53,6 +53,7 @@ if (!empty($_GET["returnto"])) {
<table border="0" cellpadding="5"> <table border="0" cellpadding="5">
<tr><td class="rowhead"><?php echo $lang_login['rowhead_username']?></td><td class="rowfollow" align="left"><input type="text" name="username" style="width: 180px; border: 1px solid gray" /></td></tr> <tr><td class="rowhead"><?php echo $lang_login['rowhead_username']?></td><td class="rowfollow" align="left"><input type="text" name="username" style="width: 180px; border: 1px solid gray" /></td></tr>
<tr><td class="rowhead"><?php echo $lang_login['rowhead_password']?></td><td class="rowfollow" align="left"><input type="password" name="password" style="width: 180px; border: 1px solid gray"/></td></tr> <tr><td class="rowhead"><?php echo $lang_login['rowhead_password']?></td><td class="rowfollow" align="left"><input type="password" name="password" style="width: 180px; border: 1px solid gray"/></td></tr>
<tr><td class="rowhead"><?php echo $lang_login['rowhead_two_step_code']?></td><td class="rowfollow" align="left"><input type="text" name="two_step_code" placeholder="<?php echo $lang_login['two_step_code_tooltip'] ?>" style="width: 180px; border: 1px solid gray"/></td></tr>
<?php <?php
show_image_code (); show_image_code ();
if ($securelogin == "yes") if ($securelogin == "yes")
+11 -1
View File
@@ -16,7 +16,7 @@ function bark($text = "")
} }
if ($iv == "yes") if ($iv == "yes")
check_code ($_POST['imagehash'], $_POST['imagestring'],'login.php',true); check_code ($_POST['imagehash'], $_POST['imagestring'],'login.php',true);
$res = sql_query("SELECT id, passhash, secret, enabled, status FROM users WHERE username = " . sqlesc($username)); $res = sql_query("SELECT id, passhash, secret, enabled, status, two_step_secret FROM users WHERE username = " . sqlesc($username));
$row = mysql_fetch_array($res); $row = mysql_fetch_array($res);
if (!$row) if (!$row)
@@ -24,6 +24,16 @@ if (!$row)
if ($row['status'] == 'pending') if ($row['status'] == 'pending')
failedlogins($lang_takelogin['std_user_account_unconfirmed']); failedlogins($lang_takelogin['std_user_account_unconfirmed']);
if (!empty($row['two_step_secret'])) {
if (empty($_POST['two_step_code'])) {
failedlogins($lang_takelogin['std_require_two_step_code']);
}
$ga = new \PHPGangsta_GoogleAuthenticator();
if (!$ga->verifyCode($row['two_step_secret'], $_POST['two_step_code'])) {
failedlogins($lang_takelogin['std_invalid_two_step_code']);
}
}
if ($row["passhash"] != md5($row["secret"] . $password . $row["secret"])) if ($row["passhash"] != md5($row["secret"] . $password . $row["secret"]))
login_failedlogins(); login_failedlogins();
+46
View File
@@ -677,6 +677,25 @@ tr_small($lang_usercp['row_funbox'],"<input type=checkbox name=showfb".($CURUSER
$chpassword = $_POST["chpassword"]; $chpassword = $_POST["chpassword"];
$passagain = $_POST["passagain"]; $passagain = $_POST["passagain"];
$privacy = $_POST["privacy"]; $privacy = $_POST["privacy"];
$twoStepSecret = $_POST['two_step_secret'] ?? '';
$twoStepSecretHash = $_POST['two_step_code'];
if (!empty($twoStepSecretHash)) {
$ga = new \PHPGangsta_GoogleAuthenticator();
if (empty($CURUSER['two_step_secret'])) {
//do bind
$secretToVerify = $twoStepSecret;
$updateset[] = "two_step_secret = " . sqlesc($twoStepSecret);
} else {
//unbind
$secretToVerify = $CURUSER['two_step_secret'];
$updateset[] = "two_step_secret = ''";
}
if (!$ga->verifyCode($secretToVerify, $twoStepSecretHash)) {
stderr($lang_usercp['std_error'], 'Invalid two step code'.goback("-2"), 0);
die;
}
}
if ($chpassword != "") { if ($chpassword != "") {
if ($chpassword == $CURUSER["username"]) { if ($chpassword == $CURUSER["username"]) {
@@ -809,6 +828,8 @@ EOD;
$chpassword = $_POST["chpassword"]; $chpassword = $_POST["chpassword"];
$passagain = $_POST["passagain"]; $passagain = $_POST["passagain"];
$privacy = $_POST["privacy"]; $privacy = $_POST["privacy"];
$two_step_secret = $_POST["two_step_secret"] ?? '';
$two_step_code = $_POST["two_step_code"];
if ($resetpasskey == 1) if ($resetpasskey == 1)
print("<input type=\"hidden\" name=\"resetpasskey\" value=\"1\">"); print("<input type=\"hidden\" name=\"resetpasskey\" value=\"1\">");
if ($resetauthkey == 1) if ($resetauthkey == 1)
@@ -817,6 +838,8 @@ EOD;
print("<input type=\"hidden\" name=\"chpassword\" value=\"$chpassword\">"); print("<input type=\"hidden\" name=\"chpassword\" value=\"$chpassword\">");
print("<input type=\"hidden\" name=\"passagain\" value=\"$passagain\">"); print("<input type=\"hidden\" name=\"passagain\" value=\"$passagain\">");
print("<input type=\"hidden\" name=\"privacy\" value=\"$privacy\">"); print("<input type=\"hidden\" name=\"privacy\" value=\"$privacy\">");
print("<input type=\"hidden\" name=\"two_step_secret\" value=\"$two_step_secret\">");
print("<input type=\"hidden\" name=\"two_step_code\" value=\"$two_step_code\">");
Print("<tr><td class=\"rowhead nowrap\" valign=\"top\" align=\"right\" width=1%>".$lang_usercp['row_security_check']."</td><td valign=\"top\" align=\"left\" width=\"99%\"><input type=password name=oldpassword style=\"width: 200px\"><br /><font class=small>".$lang_usercp['text_security_check_note']."</font></td></tr>\n"); Print("<tr><td class=\"rowhead nowrap\" valign=\"top\" align=\"right\" width=1%>".$lang_usercp['row_security_check']."</td><td valign=\"top\" align=\"left\" width=\"99%\"><input type=password name=oldpassword style=\"width: 200px\"><br /><font class=small>".$lang_usercp['text_security_check_note']."</font></td></tr>\n");
submit(); submit();
print("</table>"); print("</table>");
@@ -828,6 +851,29 @@ EOD;
form ("security"); form ("security");
tr_small($lang_usercp['row_reset_passkey'],"<input type=checkbox name=resetpasskey value=1 />".$lang_usercp['checkbox_reset_my_passkey']."<br /><font class=small>".$lang_usercp['text_reset_passkey_note']."</font>", 1); tr_small($lang_usercp['row_reset_passkey'],"<input type=checkbox name=resetpasskey value=1 />".$lang_usercp['checkbox_reset_my_passkey']."<br /><font class=small>".$lang_usercp['text_reset_passkey_note']."</font>", 1);
tr_small($lang_usercp['row_reset_authkey'],"<input type=checkbox name=resetauthkey value=1 />".$lang_usercp['checkbox_reset_my_authkey']."<br /><font class=small>".$lang_usercp['text_reset_authkey_note']."</font>", 1); tr_small($lang_usercp['row_reset_authkey'],"<input type=checkbox name=resetauthkey value=1 />".$lang_usercp['checkbox_reset_my_authkey']."<br /><font class=small>".$lang_usercp['text_reset_authkey_note']."</font>", 1);
//two step authentication
if (!empty($CURUSER['two_step_secret'])) {
tr_small($lang_usercp['row_two_step_secret'],"<input type=text name=two_step_code />".$lang_usercp['text_two_step_secret_unbind_note'], 1);
} else {
$ga = new \PHPGangsta_GoogleAuthenticator();
$twoStepSecret = $ga->createSecret();
$twoStepQrCodeUrl = $ga->getQRCodeGoogleUrl(sprintf('%s(%s)', get_setting('basic.SITENAME'), $CURUSER['username']), $twoStepSecret);
$twoStepY = '<div style="display: flex;align-items:center">';
$twoStepY .= sprintf('<div><img src="%s" /></div>', $twoStepQrCodeUrl);
$twoStepY .= sprintf(
'<div style="padding-left: 20px">%s<a href="%s" target="_blank">Link</a><br /><br />%s%s<br/><br/>%s<input type=hidden name=two_step_secret value="%s" /><input type=text name=two_step_code /></div>',
$lang_usercp['text_two_step_secret_bind_by_qrdoe_note'],
$twoStepQrCodeUrl,
$lang_usercp['text_two_step_secret_bind_manually_note'],
$twoStepSecret,
$lang_usercp['text_two_step_secret_bind_complete_note'],
$twoStepSecret
);
$twoStepY .= '</div>';
tr_small($lang_usercp['row_two_step_secret'], $twoStepY, 1);
}
if ($disableemailchange != 'no' && $smtptype != 'none') //system-wide setting if ($disableemailchange != 'no' && $smtptype != 'none') //system-wide setting
tr_small($lang_usercp['row_email_address'], "<input type=\"text\" name=\"email\" style=\"width: 200px\" value=\"" . htmlspecialchars($CURUSER["email"]) . "\" /> <br /><font class=small>".$lang_usercp['text_email_address_note']."</font>", 1); tr_small($lang_usercp['row_email_address'], "<input type=\"text\" name=\"email\" style=\"width: 200px\" value=\"" . htmlspecialchars($CURUSER["email"]) . "\" /> <br /><font class=small>".$lang_usercp['text_email_address_note']."</font>", 1);
tr_small($lang_usercp['row_change_password'], "<input type=\"password\" name=\"chpassword\" style=\"width: 200px\" />", 1); tr_small($lang_usercp['row_change_password'], "<input type=\"password\" name=\"chpassword\" style=\"width: 200px\" />", 1);