前几天看到payjs不给个人用户充值了,就想着把早就想好的TePass插件本地域名授权给做出来,防止哪天我的网站或者接口挂了,用户不能使用,既然用户花钱买了,就算我的网站挂了,用户也应该有资格继续使用。
于是今天就做了出来,要实现的功能很简单,下面讲一下:
一个简单的PHP页面
为了让用户使用简单,不能给用户带来太多的麻烦,我就做了一个简单的PHP页面,用户只需要将页面放到网站的根目录,通过下面的地址访问即可打开:
你的网址/tepass_verify.php这里将你的网址改为你网址的地址,比如我的https://pangsuan.com,而tepass_verify.php就是授权信息的PHP页面,如果你更改了名称,记得也要做相应更改才能访问。
比如我的就是https://pangsuan.com/tepass_verify.php
当然为了防止任何人都可以更改授权,或者说知道你的授权信息,这里限制了只有ID为1的用户才可以进入页面,修改信息。
页面操作逻辑
ID为1的用户登录网站后,打开页面就会看到验证信息,授权接口等相关情况,如果授权接口断开了,可以通过自己之前保存的授权信息,输入到本地授权信息里面,更新后,TePass插件也能正常使用。
TePass插件授权待更新
目前TePass插件对应的授权验证还未更新,这里只是做了一个域名授权的页面,后面找时间更新TePass插件的,那么到时候就不再依赖在线授权接口了。虽说现在基本也用不到,因为只要激活了插件,就不再验证授权信息了。
tepass_verify.php代码
下面是tepass_verify.php代码,复制之后放在网站根目录即可。
<?php
require_once 'config.inc.php';
/** 载入API支持 */
require_once 'var/Typecho/Common.php';
/** 初始化组件 */
Typecho_Widget::widget('Widget_Init');
/** 程序初始化 */
Typecho_Common::init();
// 用户验证 - 只有用户ID为1才能访问
Typecho_Widget::widget('Widget_User')->to($user);
Typecho_Widget::widget('Widget_Options')->to($options);
if (!$user->hasLogin() || $user->uid != "1") {
// 未登录或不是ID为1的用户,跳转到登录页面
echo("<script> top.location.href='/tepass/signin'</script>");
exit;
}
// 增加安全性检查
session_start();
if (!isset($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
$current_domain = trim($_SERVER['HTTP_HOST']);
// 获取远程授权信息
function getRemoteAuthInfo() {
try {
$servername = trim($_SERVER['HTTP_HOST']);
$api_url = 'https://api.pangsuan.com/authority.php?indentify=tepass&domain=' . $servername;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $api_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_USERAGENT, 'TePass-Auth-Verifier/1.0');
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($http_code != 200) {
return [
'status' => 'error',
'error_type' => 'http_error',
'http_code' => $http_code,
'message' => '接口请求失败,HTTP状态码:' . $http_code,
'timestamp' => time()
];
}
if ($response === false) {
return [
'status' => 'error',
'error_type' => 'curl_error',
'message' => '接口连接失败:' . $error,
'timestamp' => time()
];
}
$authority = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
return [
'status' => 'error',
'error_type' => 'json_error',
'message' => '接口返回数据解析失败:' . json_last_error_msg(),
'timestamp' => time()
];
}
if (isset($authority["status"]) && $authority["status"] === 'ok') {
return [
'status' => 'success',
'domain' => $_SERVER['HTTP_HOST'] ?? $servername,
'auth_data' => $authority["key"] ?? '',
'api_response' => $authority,
'timestamp' => time()
];
} else {
return [
'status' => 'api_error',
'error_type' => 'api_status',
'message' => '接口返回状态异常',
'api_response' => $authority,
'timestamp' => time()
];
}
} catch (Exception $e) {
return [
'status' => 'error',
'error_type' => 'exception',
'message' => '接口请求异常:' . $e->getMessage(),
'timestamp' => time()
];
}
}
// 获取本地授权信息
function getLocalAuthInfo() {
try {
$db = Typecho_Db::get();
$rstepassValidation = $db->fetchRow($db->select()->from('table.options')->where('name = ?', "tepassValidation")->limit(1));
if ($rstepassValidation && isset($rstepassValidation['value'])) {
return $rstepassValidation['value'];
}
return '';
} catch (Exception $e) {
return '';
}
}
// 更新本地授权信息
function updateLocalAuthInfo($auth_data) {
try {
$db = Typecho_Db::get();
$existing = $db->fetchRow($db->select()->from('table.options')->where('name = ?', "tepassValidation")->limit(1));
if ($existing) {
$result = $db->query($db->update('table.options')->rows(array('value' => $auth_data))->where('name = ?', "tepassValidation"));
} else {
$result = $db->query($db->insert('table.options')->rows(array(
'name' => 'tepassValidation',
'value' => $auth_data,
'user' => 0
)));
}
return $result !== false;
} catch (Exception $e) {
return false;
}
}
// 验证授权格式
function validateAuthFormat($auth_data) {
if (empty($auth_data)) {
return false;
}
if (strlen($auth_data) < 10) {
return false;
}
return true;
}
// 验证CSRF令牌
function validateCSRFToken($token) {
return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
}
// 处理Ajax请求
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
header('Content-Type: application/json');
// 首先验证用户权限
if (!$user->hasLogin() || $user->uid != "1") {
echo json_encode([
'success' => false,
'message' => '用户权限不足,请重新登录',
'type' => 'error',
'redirect' => '/tepass/signin'
]);
exit;
}
// 验证CSRF令牌
$csrf_token = $_POST['csrf_token'] ?? '';
if (!validateCSRFToken($csrf_token)) {
echo json_encode([
'success' => false,
'message' => '安全令牌验证失败',
'type' => 'error'
]);
exit;
}
$action = $_POST['action'] ?? '';
$response = ['success' => false, 'message' => '未知操作'];
switch ($action) {
case 'refresh_remote':
$remote_data = getRemoteAuthInfo();
$api_status = $remote_data['status'];
if ($api_status === 'success') {
$response = [
'success' => true,
'message' => '远程授权信息刷新成功',
'type' => 'success',
'data' => [
'remote_auth' => $remote_data['auth_data'],
'api_status' => $api_status,
'timestamp' => date('Y-m-d H:i:s', $remote_data['timestamp']),
'status_text' => '接口连接正常'
]
];
} else {
$response = [
'success' => false,
'message' => '远程授权信息刷新失败:' . ($remote_data['message'] ?? '未知错误'),
'type' => 'error',
'data' => [
'api_status' => $api_status,
'error_detail' => $remote_data['message'] ?? '未知错误',
'status_text' => '接口连接异常'
]
];
}
break;
case 'update_local':
$new_auth = trim($_POST['local_auth'] ?? '');
if (empty($new_auth)) {
$response = [
'success' => false,
'message' => '授权信息不能为空',
'type' => 'error'
];
break;
}
if (!validateAuthFormat($new_auth)) {
$response = [
'success' => false,
'message' => '授权信息格式不正确,应为至少10位的字符串',
'type' => 'error'
];
break;
}
if (updateLocalAuthInfo($new_auth)) {
// 获取最新远程信息进行对比
$remote_data = getRemoteAuthInfo();
$api_status = $remote_data['status'];
$remote_auth = ($api_status === 'success') ? $remote_data['auth_data'] : '';
$comparison_result = ($remote_auth === $new_auth) ? 'match' : 'mismatch';
$response = [
'success' => true,
'message' => '本地授权信息已更新' . ($comparison_result === 'match' ? ',且与远程信息一致!' : ',但与远程信息不一致。'),
'type' => 'success',
'data' => [
'local_auth' => $new_auth,
'remote_auth' => $remote_auth,
'api_status' => $api_status,
'comparison_result' => $comparison_result,
'timestamp' => date('Y-m-d H:i:s')
]
];
} else {
$response = [
'success' => false,
'message' => '更新失败,数据库错误',
'type' => 'error'
];
}
break;
case 'verify_auth':
$local_auth = getLocalAuthInfo();
$remote_data = getRemoteAuthInfo();
$api_status = $remote_data['status'];
$remote_auth = ($api_status === 'success') ? $remote_data['auth_data'] : '';
if ($api_status === 'success') {
if (empty($local_auth)) {
$comparison_result = 'no_local';
$message = '本地未找到授权信息';
} else {
$comparison_result = ($remote_auth === $local_auth) ? 'match' : 'mismatch';
$message = ($remote_auth === $local_auth) ? '授权信息一致' : '授权信息不一致';
}
$response = [
'success' => true,
'message' => $message,
'type' => $comparison_result === 'match' ? 'success' : 'warning',
'data' => [
'local_auth' => $local_auth,
'remote_auth' => $remote_auth,
'api_status' => $api_status,
'comparison_result' => $comparison_result,
'timestamp' => date('Y-m-d H:i:s')
]
];
} else {
$response = [
'success' => false,
'message' => '接口连接失败:' . ($remote_data['message'] ?? '未知错误'),
'type' => 'error',
'data' => [
'local_auth' => $local_auth,
'api_status' => $api_status,
'comparison_result' => 'api_error'
]
];
}
break;
default:
$response = ['success' => false, 'message' => '无效的操作类型', 'type' => 'error'];
}
echo json_encode($response);
exit;
}
// 初始化变量 - 仅用于首次页面加载
$comparison_result = "";
$remote_auth = "";
$local_auth = "";
$message = "";
$message_type = "";
$api_status = "unknown";
$api_error_detail = "";
$last_checked = "";
$remote_timestamp = "";
// 页面首次加载时获取授权信息
$local_auth = getLocalAuthInfo();
$remote_data = getRemoteAuthInfo();
$api_status = $remote_data['status'];
$remote_timestamp = isset($remote_data['timestamp']) ? $remote_data['timestamp'] : time();
$last_checked = date('Y-m-d H:i:s');
if ($api_status === 'success') {
$remote_auth = $remote_data['auth_data'];
$api_error_detail = "";
if (empty($local_auth)) {
$comparison_result = 'no_local';
} else {
$comparison_result = ($remote_auth === $local_auth) ? 'match' : 'mismatch';
}
} else {
$comparison_result = 'api_error';
$api_error_detail = isset($remote_data['message']) ? $remote_data['message'] : '未知错误';
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TePass插件域名授权验证系统 - 管理员</title>
<!-- 使用国内可访问的Font Awesome CDN -->
<link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary-color: #3498db;
--success-color: #27ae60;
--warning-color: #f39c12;
--error-color: #e74c3c;
--info-color: #17a2b8;
--light-bg: #f8f9fa;
--dark-text: #2c3e50;
--border-color: #dee2e6;
--shadow-color: rgba(0, 0, 0, 0.1);
--gradient-primary: linear-gradient(135deg, #3498db, #2980b9);
--gradient-success: linear-gradient(135deg, #27ae60, #219653);
--gradient-warning: linear-gradient(135deg, #f39c12, #d68910);
--modal-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Segoe UI', 'Microsoft YaHei', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #f5f7fa 0%, #e4edf5 100%);
color: #333;
line-height: 1.6;
padding: 20px;
min-height: 100vh;
}
.container {
max-width: 1000px;
margin: 30px auto;
background-color: #fff;
border-radius: 16px;
box-shadow: 0 10px 30px var(--shadow-color);
padding: 30px;
border: 1px solid var(--border-color);
position: relative;
overflow: hidden;
}
.container::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 5px;
background: var(--gradient-primary);
}
h1 {
text-align: center;
color: var(--dark-text);
margin-bottom: 15px;
padding-bottom: 15px;
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: center;
gap: 15px;
}
.logo {
font-size: 2.5rem;
color: var(--primary-color);
}
.subtitle {
text-align: center;
color: #7f8c8d;
margin-bottom: 30px;
font-size: 1.1rem;
}
.user-info {
background: var(--gradient-primary);
color: white;
padding: 10px 20px;
border-radius: 8px;
margin-bottom: 20px;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 4px 6px rgba(52, 152, 219, 0.3);
}
.user-info span {
display: flex;
align-items: center;
gap: 8px;
}
.user-info a {
color: white;
text-decoration: none;
font-size: 0.9rem;
padding: 5px 12px;
background: rgba(255, 255, 255, 0.2);
border-radius: 4px;
transition: background 0.3s;
}
.user-info a:hover {
background: rgba(255, 255, 255, 0.3);
}
.status-panel {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.status-box {
background-color: var(--light-bg);
padding: 25px;
border-radius: 12px;
border-left: 5px solid var(--primary-color);
transition: all 0.3s ease;
box-shadow: 0 4px 6px var(--shadow-color);
position: relative;
overflow: hidden;
}
.status-box:hover {
transform: translateY(-5px);
box-shadow: 0 6px 12px var(--shadow-color);
}
.status-box h3 {
font-size: 1rem;
color: #555;
margin-bottom: 15px;
display: flex;
align-items: center;
gap: 10px;
}
.status-value {
font-size: 1.5rem;
font-weight: bold;
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 10px;
}
.status-detail {
font-size: 0.9rem;
color: #777;
margin-top: 5px;
}
.auth-section {
margin-bottom: 30px;
padding: 25px;
background-color: var(--light-bg);
border-radius: 12px;
box-shadow: 0 4px 6px var(--shadow-color);
border: 1px solid var(--border-color);
}
.section-title {
font-size: 1.3rem;
color: var(--dark-text);
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid var(--border-color);
display: flex;
justify-content: space-between;
align-items: center;
}
.section-icon {
font-size: 1.5rem;
color: var(--primary-color);
}
.input-group {
margin-bottom: 25px;
}
label {
display: block;
margin-bottom: 10px;
font-weight: 600;
color: #555;
display: flex;
align-items: center;
gap: 8px;
}
.auth-input-container {
display: flex;
align-items: center;
gap: 10px;
width: 100%;
}
.auth-input {
flex: 1;
padding: 14px 16px;
border: 2px solid var(--border-color);
border-radius: 8px;
font-size: 16px;
transition: all 0.3s;
font-family: 'Consolas', 'Monaco', monospace;
background-color: #fff;
min-height: 52px;
}
.auth-input:focus {
border-color: var(--primary-color);
outline: none;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);
}
.auth-input[readonly] {
background-color: #f8f9fa;
color: #666;
border-color: #ced4da;
cursor: not-allowed;
}
.copy-btn {
background: var(--gradient-primary);
color: white;
border: none;
border-radius: 8px;
padding: 14px 20px;
cursor: pointer;
font-size: 0.95rem;
font-weight: 600;
transition: all 0.3s;
white-space: nowrap;
display: flex;
align-items: center;
gap: 8px;
min-height: 52px;
flex-shrink: 0;
}
.copy-btn:hover {
background: linear-gradient(135deg, #2980b9, #1f6394);
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(52, 152, 219, 0.3);
}
.copy-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none !important;
box-shadow: none !important;
}
.copy-btn.copied {
background: var(--gradient-success);
}
.input-hint {
font-size: 0.9rem;
color: #777;
margin-top: 8px;
padding: 10px;
background-color: rgba(52, 152, 219, 0.1);
border-radius: 6px;
display: flex;
align-items: center;
gap: 10px;
}
.input-hint.warning {
background-color: rgba(231, 76, 60, 0.1);
color: #c0392b;
}
.input-hint.success {
background-color: rgba(39, 174, 96, 0.1);
color: #27ae60;
}
.btn-group {
display: flex;
gap: 15px;
margin-top: 25px;
}
.btn {
padding: 14px 25px;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 16px;
font-weight: 600;
transition: all 0.3s;
text-align: center;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
text-decoration: none;
}
.btn-primary {
background: var(--gradient-primary);
color: white;
}
.btn-primary:hover:not(:disabled) {
background: linear-gradient(135deg, #2980b9, #1f6394);
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(52, 152, 219, 0.3);
}
.btn-success {
background: var(--gradient-success);
color: white;
}
.btn-success:hover:not(:disabled) {
background: linear-gradient(135deg, #219653, #1a7945);
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(39, 174, 96, 0.3);
}
.btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none !important;
box-shadow: none !important;
}
.message {
padding: 20px 25px;
border-radius: 10px;
margin-bottom: 30px;
border-left: 5px solid transparent;
display: flex;
align-items: center;
gap: 15px;
animation: fadeIn 0.5s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
.message-icon {
font-size: 1.8rem;
flex-shrink: 0;
}
.message-content {
flex-grow: 1;
}
.message.success {
background-color: rgba(39, 174, 96, 0.1);
color: #155724;
border-left-color: var(--success-color);
}
.message.error {
background-color: rgba(231, 76, 60, 0.1);
color: #721c24;
border-left-color: var(--error-color);
}
.message.warning {
background-color: rgba(243, 156, 18, 0.1);
color: #856404;
border-left-color: var(--warning-color);
}
.message.info {
background-color: rgba(23, 162, 184, 0.1);
color: #0c5460;
border-left-color: var(--info-color);
}
.security-alert {
background: linear-gradient(135deg, #fff3cd, #ffeaa7);
border: 2px solid #ffc107;
border-radius: 10px;
padding: 20px;
margin: 25px 0;
display: flex;
align-items: center;
gap: 15px;
animation: pulse 2s infinite;
}
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(255, 193, 7, 0.7); }
70% { box-shadow: 0 0 0 10px rgba(255, 193, 7, 0); }
100% { box-shadow: 0 0 0 0 rgba(255, 193, 7, 0); }
}
.security-alert-icon {
font-size: 2rem;
color: #856404;
flex-shrink: 0;
}
.info-box {
background-color: var(--light-bg);
border-left: 5px solid var(--primary-color);
padding: 25px;
margin-top: 30px;
border-radius: 12px;
box-shadow: 0 4px 6px var(--shadow-color);
}
.info-box h3 {
margin-top: 0;
color: var(--dark-text);
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 10px;
}
.info-list {
list-style-type: none;
padding-left: 0;
}
.info-list li {
margin-bottom: 15px;
padding-left: 30px;
position: relative;
}
.info-list li:before {
content: "✓";
color: var(--success-color);
font-size: 1.2rem;
position: absolute;
left: 0;
top: -2px;
font-weight: bold;
}
.info-list li.warning:before {
content: "⚠";
color: var(--warning-color);
}
.info-list li.error:before {
content: "✗";
color: var(--error-color);
}
.footer-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid var(--border-color);
color: #7f8c8d;
font-size: 0.9rem;
flex-wrap: wrap;
gap: 15px;
}
.last-checked {
display: flex;
align-items: center;
gap: 8px;
}
.loading-spinner {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
border-top-color: white;
animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.loading-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
opacity: 0;
visibility: hidden;
transition: all 0.3s;
}
.loading-overlay.active {
opacity: 1;
visibility: visible;
}
.loading-content {
background: white;
padding: 30px;
border-radius: 12px;
text-align: center;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
min-width: 200px;
}
.loading-text {
margin-top: 15px;
font-weight: 600;
color: var(--dark-text);
}
/* 现代化弹窗样式 */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 10000;
opacity: 0;
visibility: hidden;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
backdrop-filter: blur(5px);
}
.modal-overlay.active {
opacity: 1;
visibility: visible;
}
.modal {
background: white;
border-radius: 20px;
width: 90%;
max-width: 500px;
overflow: hidden;
transform: translateY(30px) scale(0.95);
opacity: 0;
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
box-shadow: var(--modal-shadow);
}
.modal-overlay.active .modal {
transform: translateY(0) scale(1);
opacity: 1;
}
.modal-header {
background: var(--gradient-primary);
color: white;
padding: 25px 30px;
position: relative;
}
.modal-header::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 5px;
background: rgba(255, 255, 255, 0.2);
}
.modal-title {
font-size: 1.5rem;
font-weight: 600;
display: flex;
align-items: center;
gap: 12px;
}
.modal-title i {
font-size: 1.8rem;
}
.modal-close {
position: absolute;
top: 20px;
right: 20px;
background: rgba(255, 255, 255, 0.2);
border: none;
width: 40px;
height: 40px;
border-radius: 50%;
color: white;
font-size: 1.2rem;
cursor: pointer;
transition: all 0.3s;
display: flex;
align-items: center;
justify-content: center;
}
.modal-close:hover {
background: rgba(255, 255, 255, 0.3);
transform: rotate(90deg);
}
.modal-body {
padding: 30px;
}
.modal-content {
font-size: 1.1rem;
line-height: 1.6;
color: var(--dark-text);
margin-bottom: 25px;
}
.modal-content i {
color: var(--warning-color);
margin-right: 10px;
font-size: 1.3rem;
}
.modal-actions {
display: flex;
gap: 15px;
margin-top: 30px;
}
.modal-btn {
flex: 1;
padding: 16px 20px;
border: none;
border-radius: 10px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
}
.modal-btn-primary {
background: var(--gradient-success);
color: white;
}
.modal-btn-primary:hover {
background: linear-gradient(135deg, #219653, #1a7945);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(39, 174, 96, 0.3);
}
.modal-btn-secondary {
background: #f8f9fa;
color: #6c757d;
border: 2px solid #dee2e6;
}
.modal-btn-secondary:hover {
background: #e9ecef;
border-color: #ced4da;
transform: translateY(-2px);
}
.modal-warning {
background: linear-gradient(135deg, #fff9e6, #fff3cd);
border-left: 5px solid var(--warning-color);
padding: 15px;
border-radius: 8px;
margin: 20px 0;
}
.modal-warning i {
color: var(--warning-color);
font-size: 1.2rem;
margin-right: 10px;
}
/* 成功提示弹窗 */
.success-modal .modal-header {
background: var(--gradient-success);
}
.success-modal .modal-title i {
animation: bounce 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
@keyframes bounce {
0%, 20%, 50%, 80%, 100% {transform: translateY(0);}
40% {transform: translateY(-15px);}
60% {transform: translateY(-7px);}
}
/* 错误提示弹窗 */
.error-modal .modal-header {
background: var(--gradient-warning);
}
.error-modal .modal-title i {
animation: shake 0.5s cubic-bezier(0.36, 0.07, 0.19, 0.97);
}
@keyframes shake {
10%, 90% {transform: translate3d(-1px, 0, 0);}
20%, 80% {transform: translate3d(2px, 0, 0);}
30%, 50%, 70% {transform: translate3d(-4px, 0, 0);}
40%, 60% {transform: translate3d(4px, 0, 0);}
}
/* Toast提示 */
.toast {
position: fixed;
top: 30px;
right: 30px;
background: white;
border-radius: 12px;
padding: 20px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
display: flex;
align-items: center;
gap: 15px;
z-index: 10001;
transform: translateX(100%);
opacity: 0;
transition: all 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
max-width: 400px;
}
.toast.show {
transform: translateX(0);
opacity: 1;
}
.toast-icon {
font-size: 1.8rem;
flex-shrink: 0;
}
.toast-success {
border-left: 5px solid var(--success-color);
}
.toast-success .toast-icon {
color: var(--success-color);
}
.toast-error {
border-left: 5px solid var(--error-color);
}
.toast-error .toast-icon {
color: var(--error-color);
}
.toast-warning {
border-left: 5px solid var(--warning-color);
}
.toast-warning .toast-icon {
color: var(--warning-color);
}
.toast-content {
flex-grow: 1;
}
.toast-title {
font-weight: 600;
margin-bottom: 5px;
color: var(--dark-text);
}
.toast-message {
font-size: 0.95rem;
color: #666;
}
@media (max-width: 768px) {
.status-panel {
grid-template-columns: 1fr;
}
.btn-group {
flex-direction: column;
}
.container {
padding: 20px;
}
.footer-info {
flex-direction: column;
align-items: flex-start;
}
.auth-input-container {
flex-direction: column;
align-items: stretch;
}
.copy-btn {
width: 100%;
justify-content: center;
}
.modal {
width: 95%;
margin: 10px;
}
.modal-actions {
flex-direction: column;
}
.toast {
left: 20px;
right: 20px;
max-width: none;
}
.user-info {
flex-direction: column;
gap: 10px;
text-align: center;
}
}
</style>
</head>
<body>
<div class="container">
<h1>
<i class="fas fa-shield-alt logo"></i>
TePass插件域名授权验证系统
</h1>
<p class="subtitle">安全、可靠的授权验证与管理工具</p>
<!-- 用户信息栏 -->
<div class="user-info">
<span>
<i class="fas fa-user-shield"></i>
管理员:<?php echo htmlspecialchars($user->screenName); ?> (ID: <?php echo $user->uid; ?>)
</span>
<a href="<?php $options->logoutUrl() ?>" title="退出登录"
<i class="fas fa-sign-out-alt"></i> 退出
</a>
</div>
<div class="security-alert">
<div class="security-alert-icon">
<i class="fas fa-exclamation-triangle"></i>
</div>
<div>
<strong>重要安全提醒:</strong> 请妥善保管您的授权信息,不要泄露给他人。授权信息是您使用TePass插件的唯一凭证,丢失可能导致服务中断。建议您将授权信息备份到安全的地方。
</div>
</div>
<div id="message-container"></div>
<div class="status-panel">
<div class="status-box api-status" id="api-status-box">
<h3><i class="fas fa-satellite-dish"></i> 接口状态</h3>
<div class="status-value">
<span id="api-status-icon">
<?php if ($api_status === 'success'): ?>
<i class="fas fa-check-circle" style="color: var(--success-color);"></i>
<span style="color: var(--success-color);">正常</span>
<?php elseif ($api_status === 'error' || $api_status === 'api_error'): ?>
<i class="fas fa-times-circle" style="color: var(--error-color);"></i>
<span style="color: var(--error-color);">异常</span>
<?php else: ?>
<i class="fas fa-question-circle" style="color: var(--warning-color);"></i>
<span style="color: var(--warning-color);">未知</span>
<?php endif; ?>
</span>
</div>
<div class="status-detail" id="api-status-detail">
<?php if ($api_error_detail): ?>
<i class="fas fa-exclamation-circle"></i> <?php echo htmlspecialchars($api_error_detail); ?>
<?php else: ?>
<i class="fas <?php echo $api_status === 'success' ? 'fa-wifi' : 'fa-wifi-slash'; ?>"></i>
<?php echo $api_status === 'success' ? '授权接口连接正常' : '无法连接授权接口'; ?>
<?php endif; ?>
</div>
</div>
<div class="status-box auth-status" id="auth-status-box">
<h3><i class="fas fa-key"></i> 授权状态</h3>
<div class="status-value">
<span id="auth-status-icon">
<?php if ($comparison_result === 'match'): ?>
<i class="fas fa-check-circle" style="color: var(--success-color);"></i>
<span style="color: var(--success-color);">已验证</span>
<?php elseif ($comparison_result === 'mismatch'): ?>
<i class="fas fa-times-circle" style="color: var(--error-color);"></i>
<span style="color: var(--error-color);">不一致</span>
<?php elseif ($comparison_result === 'no_local'): ?>
<i class="fas fa-exclamation-circle" style="color: var(--error-color);"></i>
<span style="color: var(--error-color);">未配置</span>
<?php elseif ($comparison_result === 'api_error'): ?>
<i class="fas fa-question-circle" style="color: var(--warning-color);"></i>
<span style="color: var(--warning-color);">待验证</span>
<?php else: ?>
<i class="fas fa-sync-alt fa-spin"></i>
<span style="color: var(--primary-color);">检查中...</span>
<?php endif; ?>
</span>
</div>
<div class="status-detail" id="auth-status-detail">
<?php
if ($comparison_result === 'match') {
echo '<i class="fas fa-thumbs-up"></i> 远程与本地授权信息一致';
} elseif ($comparison_result === 'mismatch') {
echo '<i class="fas fa-exclamation-triangle"></i> 远程与本地授权信息不一致';
} elseif ($comparison_result === 'no_local') {
echo '<i class="fas fa-database"></i> 本地未找到授权信息';
} elseif ($comparison_result === 'api_error') {
echo '<i class="fas fa-cloud-slash"></i> 接口异常,无法验证';
} else {
echo '<i class="fas fa-cog fa-spin"></i> 正在验证授权信息...';
}
?>
</div>
</div>
<div class="status-box">
<h3><i class="fas fa-globe"></i> 域名信息</h3>
<div class="status-value"><?php echo htmlspecialchars($current_domain); ?></div>
<div class="status-detail">
<i class="fas fa-clock"></i> 最后检查: <span id="last-checked"><?php echo $last_checked; ?></span>
</div>
</div>
</div>
<div class="auth-section">
<h2 class="section-title">
<span><i class="fas fa-cloud section-icon"></i> 远程授权信息</span>
<span id="remote-timestamp" style="font-size: 0.9rem; color: var(--success-color);">
<?php if ($api_status === 'success'): ?>
<i class="fas fa-clock"></i> <?php echo date('H:i:s', $remote_timestamp); ?>
<?php endif; ?>
</span>
</h2>
<div class="input-group">
<label for="remote_auth">
<i class="fas fa-download"></i> 从授权接口获取的信息
</label>
<div class="auth-input-container">
<input
type="text"
id="remote_auth"
class="auth-input"
value="<?php echo htmlspecialchars($remote_auth); ?>"
readonly
placeholder="<?php echo $api_status !== 'success' ? '接口连接失败,无法获取远程授权信息' : ''; ?>"
>
<?php if ($remote_auth): ?>
<button type="button" class="copy-btn" id="copy-remote-btn">
<i class="fas fa-copy"></i> 复制
</button>
<?php endif; ?>
</div>
<?php if ($api_status !== 'success'): ?>
<div class="input-hint warning">
<i class="fas fa-exclamation-triangle"></i>
授权接口连接失败时,请手动输入正确的授权信息保存到本地
</div>
<?php endif; ?>
</div>
<div class="btn-group">
<button type="button" id="refresh-remote-btn" class="btn btn-primary">
<i class="fas fa-sync-alt"></i> 刷新远程信息
</button>
</div>
</div>
<div class="auth-section">
<h2 class="section-title">
<span><i class="fas fa-database section-icon"></i> 本地授权信息</span>
<span id="local-saved-status" style="font-size: 0.9rem; color: var(--success-color);">
<?php if ($local_auth): ?>
<i class="fas fa-check"></i> 已保存
<?php endif; ?>
</span>
</h2>
<div class="input-group">
<label for="local_auth">
<i class="fas fa-edit"></i> 本地数据库保存的授权信息
</label>
<div class="auth-input-container">
<input
type="text"
id="local_auth"
class="auth-input"
value="<?php echo htmlspecialchars($local_auth); ?>"
placeholder="请输入正确的授权信息"
autocomplete="off"
>
<?php if ($local_auth): ?>
<button type="button" class="copy-btn" id="copy-local-btn">
<i class="fas fa-copy"></i> 复制
</button>
<?php endif; ?>
</div>
<div class="input-hint">
<i class="fas fa-info-circle"></i>
当授权接口断开时,请在此处输入正确的授权信息并保存到本地
</div>
</div>
<div class="btn-group">
<button type="button" id="update-local-btn" class="btn btn-success">
<i class="fas fa-save"></i> 保存到本地
</button>
</div>
</div>
<div class="info-box">
<h3><i class="fas fa-book"></i> 使用说明与安全注意事项</h3>
<ul class="info-list">
<li><strong>访问权限:</strong>只有管理员(用户ID为1)可以访问和操作此系统</li>
<li><strong>自动验证:</strong>页面加载时会自动获取远程和本地授权信息并进行对比验证</li>
<li class="warning"><strong>安全提醒:</strong>授权信息是您使用TePass插件的唯一凭证,请勿泄露给他人,并建议做好备份</li>
<li><strong>无刷新操作:</strong>刷新远程信息和保存本地信息均采用Ajax方式,无需刷新整个页面</li>
<li><strong>实时状态更新:</strong>所有操作后状态面板会实时更新,显示最新状态</li>
<li><strong>复制功能:</strong>点击右侧复制按钮可快速复制授权信息</li>
<li class="error"><strong>注意事项:</strong>请确保输入的授权信息格式正确,授权信息丢失可能导致服务中断</li>
<li><strong>快捷操作:</strong>使用 Ctrl+R 刷新远程信息,Ctrl+S 保存本地信息</li>
</ul>
</div>
<div class="footer-info">
<div>
<i class="fas fa-code"></i> TePass插件域名授权验证系统 © <?php echo date('Y'); ?>
</div>
<div class="last-checked">
<i class="fas fa-clock"></i> 最后检查时间: <span id="footer-last-checked"><?php echo $last_checked; ?></span>
</div>
<div>
<i class="fas fa-shield-alt"></i> 当前域名: <?php echo htmlspecialchars($current_domain); ?>
</div>
</div>
</div>
<!-- 加载遮罩层 -->
<div class="loading-overlay" id="loading-overlay">
<div class="loading-content">
<div class="loading-spinner"></div>
<div class="loading-text" id="loading-text">处理中...</div>
</div>
</div>
<!-- 确认保存弹窗 -->
<div class="modal-overlay" id="confirm-modal">
<div class="modal">
<div class="modal-header">
<div class="modal-title">
<i class="fas fa-shield-alt"></i>
确认保存授权信息
</div>
<button class="modal-close" id="confirm-modal-close">
<i class="fas fa-times"></i>
</button>
</div>
<div class="modal-body">
<div class="modal-content">
<i class="fas fa-exclamation-circle"></i>
您确定要保存授权信息到本地数据库吗?
</div>
<div class="modal-warning">
<i class="fas fa-exclamation-triangle"></i>
<strong>重要提醒:</strong>请确保这是正确的授权信息,错误的授权信息可能导致插件无法正常工作。
</div>
<div class="modal-actions">
<button class="modal-btn modal-btn-secondary" id="confirm-cancel">
<i class="fas fa-times"></i> 取消
</button>
<button class="modal-btn modal-btn-primary" id="confirm-save">
<i class="fas fa-save"></i> 确认保存
</button>
</div>
</div>
</div>
</div>
<!-- 成功提示弹窗 -->
<div class="modal-overlay success-modal" id="success-modal">
<div class="modal">
<div class="modal-header">
<div class="modal-title">
<i class="fas fa-check-circle"></i>
保存成功
</div>
<button class="modal-close" id="success-modal-close">
<i class="fas fa-times"></i>
</button>
</div>
<div class="modal-body">
<div class="modal-content" id="success-message">
授权信息已成功保存到本地数据库!
</div>
<div class="modal-actions">
<button class="modal-btn modal-btn-primary" id="success-ok">
<i class="fas fa-check"></i> 确定
</button>
</div>
</div>
</div>
</div>
<!-- 错误提示弹窗 -->
<div class="modal-overlay error-modal" id="error-modal">
<div class="modal">
<div class="modal-header">
<div class="modal-title">
<i class="fas fa-exclamation-triangle"></i>
保存失败
</div>
<button class="modal-close" id="error-modal-close">
<i class="fas fa-times"></i>
</button>
</div>
<div class="modal-body">
<div class="modal-content" id="error-message">
授权信息保存失败,请检查后重试。
</div>
<div class="modal-actions">
<button class="modal-btn modal-btn-primary" id="error-ok">
<i class="fas fa-redo"></i> 重试
</button>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const csrfToken = '<?php echo $_SESSION['csrf_token']; ?>';
const currentDomain = '<?php echo htmlspecialchars($current_domain); ?>';
// 自动聚焦逻辑
const apiStatus = '<?php echo $api_status; ?>';
const comparisonResult = '<?php echo $comparison_result; ?>';
const localAuthInput = document.getElementById('local_auth');
if ((apiStatus !== 'success' || comparisonResult === 'mismatch' || comparisonResult === 'no_local') && localAuthInput) {
setTimeout(() => {
localAuthInput.focus();
localAuthInput.select();
}, 300);
}
// 键盘快捷键
document.addEventListener('keydown', function(e) {
if (e.ctrlKey) {
if (e.key === 'r' || e.key === 'R') {
e.preventDefault();
refreshRemoteAuth();
} else if (e.key === 's' || e.key === 'S') {
e.preventDefault();
showConfirmModal();
}
}
});
// 复制按钮功能
document.querySelectorAll('.copy-btn').forEach(button => {
button.addEventListener('click', function() {
const targetId = this.id === 'copy-remote-btn' ? 'remote_auth' : 'local_auth';
const input = document.getElementById(targetId);
input.select();
input.setSelectionRange(0, 99999);
try {
const successful = document.execCommand('copy');
if (successful) {
showToast('授权信息已复制到剪贴板!', 'success');
// 按钮反馈效果
const icon = this.querySelector('i');
const originalIconClass = icon.className;
const originalText = this.textContent;
icon.className = 'fas fa-check';
this.textContent = '已复制';
this.classList.add('copied');
setTimeout(() => {
icon.className = originalIconClass;
this.textContent = originalText;
this.classList.remove('copied');
}, 2000);
}
} catch (err) {
console.error('复制失败:', err);
showToast('复制失败,请手动选择并复制', 'error');
}
if (window.getSelection) {
window.getSelection().removeAllRanges();
}
});
});
// 刷新远程信息按钮
document.getElementById('refresh-remote-btn').addEventListener('click', refreshRemoteAuth);
// 更新本地信息按钮
document.getElementById('update-local-btn').addEventListener('click', showConfirmModal);
// 弹窗控制
const confirmModal = document.getElementById('confirm-modal');
const successModal = document.getElementById('success-modal');
const errorModal = document.getElementById('error-modal');
// 确认弹窗
document.getElementById('confirm-modal-close').addEventListener('click', () => hideModal(confirmModal));
document.getElementById('confirm-cancel').addEventListener('click', () => hideModal(confirmModal));
document.getElementById('confirm-save').addEventListener('click', updateLocalAuth);
// 成功弹窗
document.getElementById('success-modal-close').addEventListener('click', () => hideModal(successModal));
document.getElementById('success-ok').addEventListener('click', () => hideModal(successModal));
// 错误弹窗
document.getElementById('error-modal-close').addEventListener('click', () => hideModal(errorModal));
document.getElementById('error-ok').addEventListener('click', () => {
hideModal(errorModal);
setTimeout(showConfirmModal, 300);
});
// 显示弹窗函数
function showModal(modal) {
document.body.style.overflow = 'hidden';
modal.classList.add('active');
}
// 隐藏弹窗函数
function hideModal(modal) {
document.body.style.overflow = '';
modal.classList.remove('active');
}
// 显示确认弹窗
function showConfirmModal() {
const localAuth = document.getElementById('local_auth').value.trim();
if (!localAuth) {
showToast('授权信息不能为空', 'error');
document.getElementById('local_auth').focus();
return;
}
if (localAuth.length < 10) {
showToast('授权信息格式不正确,应为至少10位的字符串', 'error');
document.getElementById('local_auth').focus();
document.getElementById('local_auth').select();
return;
}
showModal(confirmModal);
}
// Toast提示函数
function showToast(message, type = 'info', title = '') {
// 移除现有的toast
const existingToast = document.querySelector('.toast');
if (existingToast) {
existingToast.remove();
}
// 创建新的toast
const toast = document.createElement('div');
toast.className = `toast toast-${type}`;
let icon = 'info-circle';
if (type === 'success') icon = 'check-circle';
if (type === 'error') icon = 'exclamation-circle';
if (type === 'warning') icon = 'exclamation-triangle';
toast.innerHTML = `
<div class="toast-icon">
<i class="fas fa-${icon}"></i>
</div>
<div class="toast-content">
${title ? `<div class="toast-title">${title}</div>` : ''}
<div class="toast-message">${message}</div>
</div>
`;
document.body.appendChild(toast);
// 触发动画
setTimeout(() => {
toast.classList.add('show');
}, 10);
// 5秒后自动移除
setTimeout(() => {
toast.classList.remove('show');
setTimeout(() => {
if (toast.parentNode) {
toast.remove();
}
}, 400);
}, 5000);
}
// 显示加载中
function showLoading(text = '处理中...') {
const overlay = document.getElementById('loading-overlay');
const loadingText = document.getElementById('loading-text');
loadingText.textContent = text;
overlay.classList.add('active');
}
// 隐藏加载中
function hideLoading() {
const overlay = document.getElementById('loading-overlay');
overlay.classList.remove('active');
}
// Ajax请求函数
function sendAjaxRequest(action, data = {}) {
return new Promise((resolve, reject) => {
showLoading('正在处理...');
const xhr = new XMLHttpRequest();
xhr.open('POST', '', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
hideLoading();
if (xhr.status === 200) {
try {
const response = JSON.parse(xhr.responseText);
// 检查是否有重定向(权限不足)
if (response.redirect) {
window.location.href = response.redirect;
return;
}
resolve(response);
} catch (e) {
reject(new Error('响应解析失败'));
}
} else {
reject(new Error('请求失败,状态码:' + xhr.status));
}
}
};
xhr.onerror = function() {
hideLoading();
reject(new Error('网络请求失败'));
};
const params = new URLSearchParams();
params.append('action', action);
params.append('csrf_token', csrfToken);
for (const key in data) {
params.append(key, data[key]);
}
xhr.send(params.toString());
});
}
// 刷新远程授权信息
async function refreshRemoteAuth() {
const refreshBtn = document.getElementById('refresh-remote-btn');
const originalContent = refreshBtn.innerHTML;
refreshBtn.disabled = true;
refreshBtn.innerHTML = '<div class="loading-spinner"></div> 刷新中...';
try {
const response = await sendAjaxRequest('refresh_remote');
if (response.success) {
// 更新远程授权信息
document.getElementById('remote_auth').value = response.data.remote_auth;
// 更新状态面板
updateStatusPanel(response.data);
// 显示成功消息
showToast(response.message, 'success', '刷新成功');
// 启用复制按钮
if (response.data.remote_auth && !document.getElementById('copy-remote-btn')) {
const inputContainer = document.querySelector('.auth-input-container');
const copyBtn = document.createElement('button');
copyBtn.type = 'button';
copyBtn.className = 'copy-btn';
copyBtn.id = 'copy-remote-btn';
copyBtn.innerHTML = '<i class="fas fa-copy"></i> 复制';
copyBtn.addEventListener('click', function() {
const input = document.getElementById('remote_auth');
input.select();
document.execCommand('copy');
showToast('已复制到剪贴板', 'success');
});
inputContainer.appendChild(copyBtn);
}
} else {
showToast(response.message, 'error', '刷新失败');
updateStatusPanel(response.data);
}
} catch (error) {
console.error('刷新失败:', error);
showToast('刷新失败:' + error.message, 'error', '网络错误');
} finally {
refreshBtn.disabled = false;
refreshBtn.innerHTML = originalContent;
}
}
// 更新本地授权信息
async function updateLocalAuth() {
hideModal(confirmModal);
const localAuth = document.getElementById('local_auth').value.trim();
const updateBtn = document.getElementById('update-local-btn');
const originalContent = updateBtn.innerHTML;
updateBtn.disabled = true;
updateBtn.innerHTML = '<div class="loading-spinner"></div> 保存中...';
try {
const response = await sendAjaxRequest('update_local', { local_auth: localAuth });
if (response.success) {
// 更新本地授权信息显示
document.getElementById('local_auth').value = response.data.local_auth;
// 更新状态面板
updateStatusPanel(response.data);
// 显示保存状态
const savedStatus = document.getElementById('local-saved-status');
savedStatus.innerHTML = '<i class="fas fa-check"></i> 已保存';
savedStatus.style.color = 'var(--success-color)';
// 显示成功弹窗
document.getElementById('success-message').textContent = response.message;
showModal(successModal);
// 启用复制按钮
if (response.data.local_auth && !document.getElementById('copy-local-btn')) {
const inputContainer = document.querySelectorAll('.auth-input-container')[1];
const copyBtn = document.createElement('button');
copyBtn.type = 'button';
copyBtn.className = 'copy-btn';
copyBtn.id = 'copy-local-btn';
copyBtn.innerHTML = '<i class="fas fa-copy"></i> 复制';
copyBtn.addEventListener('click', function() {
const input = document.getElementById('local_auth');
input.select();
document.execCommand('copy');
showToast('已复制到剪贴板', 'success');
});
inputContainer.appendChild(copyBtn);
}
} else {
document.getElementById('error-message').textContent = response.message;
showModal(errorModal);
}
} catch (error) {
console.error('保存失败:', error);
document.getElementById('error-message').textContent = '保存失败:' + error.message;
showModal(errorModal);
} finally {
updateBtn.disabled = false;
updateBtn.innerHTML = originalContent;
}
}
// 更新状态面板
function updateStatusPanel(data) {
const now = new Date();
const timestamp = now.toLocaleString('zh-CN');
// 更新最后检查时间
document.getElementById('last-checked').textContent = timestamp;
document.getElementById('footer-last-checked').textContent = timestamp;
// 更新API状态
const apiStatusBox = document.getElementById('api-status-box');
const apiStatusIcon = document.getElementById('api-status-icon');
const apiStatusDetail = document.getElementById('api-status-detail');
if (data.api_status === 'success') {
apiStatusIcon.innerHTML = '<i class="fas fa-check-circle" style="color: var(--success-color);"></i><span style="color: var(--success-color);">正常</span>';
apiStatusDetail.innerHTML = '<i class="fas fa-wifi"></i> 授权接口连接正常';
apiStatusBox.style.borderLeftColor = 'var(--success-color)';
// 更新远程时间戳
const remoteTimestamp = document.getElementById('remote-timestamp');
if (remoteTimestamp) {
remoteTimestamp.innerHTML = `<i class="fas fa-clock"></i> ${data.timestamp || timestamp.split(' ')[1]}`;
}
} else {
apiStatusIcon.innerHTML = '<i class="fas fa-times-circle" style="color: var(--error-color);"></i><span style="color: var(--error-color);">异常</span>';
apiStatusDetail.innerHTML = `<i class="fas fa-exclamation-circle"></i> ${data.error_detail || '无法连接授权接口'}`;
apiStatusBox.style.borderLeftColor = 'var(--error-color)';
}
// 更新授权状态
const authStatusBox = document.getElementById('auth-status-box');
const authStatusIcon = document.getElementById('auth-status-icon');
const authStatusDetail = document.getElementById('auth-status-detail');
if (data.comparison_result === 'match') {
authStatusIcon.innerHTML = '<i class="fas fa-check-circle" style="color: var(--success-color);"></i><span style="color: var(--success-color);">已验证</span>';
authStatusDetail.innerHTML = '<i class="fas fa-thumbs-up"></i> 远程与本地授权信息一致';
authStatusBox.style.borderLeftColor = 'var(--success-color)';
} else if (data.comparison_result === 'mismatch') {
authStatusIcon.innerHTML = '<i class="fas fa-times-circle" style="color: var(--error-color);"></i><span style="color: var(--error-color);">不一致</span>';
authStatusDetail.innerHTML = '<i class="fas fa-exclamation-triangle"></i> 远程与本地授权信息不一致';
authStatusBox.style.borderLeftColor = 'var(--error-color)';
} else if (data.comparison_result === 'no_local') {
authStatusIcon.innerHTML = '<i class="fas fa-exclamation-circle" style="color: var(--error-color);"></i><span style="color: var(--error-color);">未配置</span>';
authStatusDetail.innerHTML = '<i class="fas fa-database"></i> 本地未找到授权信息';
authStatusBox.style.borderLeftColor = 'var(--error-color)';
} else if (data.comparison_result === 'api_error') {
authStatusIcon.innerHTML = '<i class="fas fa-question-circle" style="color: var(--warning-color);"></i><span style="color: var(--warning-color);">待验证</span>';
authStatusDetail.innerHTML = '<i class="fas fa-cloud-slash"></i> 接口异常,无法验证';
authStatusBox.style.borderLeftColor = 'var(--warning-color)';
}
// 更新远程授权信息输入框
if (data.remote_auth !== undefined) {
const remoteInput = document.getElementById('remote_auth');
remoteInput.value = data.remote_auth || '';
remoteInput.placeholder = data.remote_auth ? '' : '接口连接失败,无法获取远程授权信息';
}
// 更新本地授权信息输入框
if (data.local_auth !== undefined) {
const localInput = document.getElementById('local_auth');
localInput.value = data.local_auth || '';
}
}
// 页面加载动画
const container = document.querySelector('.container');
container.style.opacity = '0';
container.style.transform = 'translateY(20px)';
setTimeout(() => {
container.style.transition = 'opacity 0.5s ease, transform 0.5s ease';
container.style.opacity = '1';
container.style.transform = 'translateY(0)';
}, 100);
// 定期自动验证(每5分钟)
setInterval(async () => {
try {
const response = await sendAjaxRequest('verify_auth');
if (response.success) {
updateStatusPanel(response.data);
}
} catch (error) {
console.error('自动验证失败:', error);
}
}, 5 * 60 * 1000); // 5分钟
});
</script>
</body>
</html>当然我也会发送一份到我的TePass交流群,可以从群文件获取。
本文属原创,转载请注明原文:https://pangsuan.com/p/tepass_verify.html
评论 (0)