项目整理:添加Cookie Cloud下载功能、优化前端界面、配置改为config.json、打包脚本、清理无用文件
This commit is contained in:
+1
-1
@@ -49,4 +49,4 @@ def create_app(config_class=Config):
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app = create_app()
|
app = create_app()
|
||||||
app.run(host='0.0.0.0', port=5000, debug=True)
|
app.run(host='0.0.0.0', port=5000, debug=False)
|
||||||
|
|||||||
Binary file not shown.
@@ -13,17 +13,34 @@ website_bp = Blueprint('websites', __name__)
|
|||||||
@website_bp.route('/check-network', methods=['GET'])
|
@website_bp.route('/check-network', methods=['GET'])
|
||||||
def check_all_network():
|
def check_all_network():
|
||||||
"""检测所有网站的网络可达性"""
|
"""检测所有网站的网络可达性"""
|
||||||
|
import urllib3
|
||||||
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||||
|
|
||||||
websites = Website.query.all()
|
websites = Website.query.all()
|
||||||
result = {}
|
result = {}
|
||||||
|
|
||||||
for website in websites:
|
for website in websites:
|
||||||
try:
|
try:
|
||||||
resp = http_requests.get(website.url, timeout=5, allow_redirects=True)
|
resp = http_requests.get(website.url, timeout=5, allow_redirects=True, verify=False)
|
||||||
result[website.id] = {
|
result[website.id] = {
|
||||||
'status': resp.status_code,
|
'status': resp.status_code,
|
||||||
'reachable': resp.status_code < 400,
|
'reachable': resp.status_code < 500,
|
||||||
'response_time': resp.elapsed.total_seconds() * 1000
|
'response_time': resp.elapsed.total_seconds() * 1000
|
||||||
}
|
}
|
||||||
|
except http_requests.exceptions.SSLError:
|
||||||
|
try:
|
||||||
|
resp = http_requests.get(website.url, timeout=5, allow_redirects=True, verify=False)
|
||||||
|
result[website.id] = {
|
||||||
|
'status': resp.status_code,
|
||||||
|
'reachable': resp.status_code < 500,
|
||||||
|
'response_time': resp.elapsed.total_seconds() * 1000
|
||||||
|
}
|
||||||
|
except Exception:
|
||||||
|
result[website.id] = {
|
||||||
|
'status': 0,
|
||||||
|
'reachable': False,
|
||||||
|
'response_time': 0
|
||||||
|
}
|
||||||
except Exception:
|
except Exception:
|
||||||
result[website.id] = {
|
result[website.id] = {
|
||||||
'status': 0,
|
'status': 0,
|
||||||
|
|||||||
@@ -73,6 +73,18 @@ body {
|
|||||||
background-clip: text;
|
background-clip: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header-stat {
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-stat b {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 18px;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.header-right {
|
.header-right {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -465,11 +477,36 @@ body {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 仪表板页脚 */
|
||||||
|
.dashboard-footer {
|
||||||
|
margin-top: 40px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
background: var(--card-bg);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-footer p {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 13px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
/* 统计数字卡片颜色 */
|
/* 统计数字卡片颜色 */
|
||||||
.stat-total .el-statistic__content {
|
.stat-total .el-statistic__content {
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.refresh-hint {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-light);
|
||||||
|
font-weight: 400;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.stat-online .el-statistic__content {
|
.stat-online .el-statistic__content {
|
||||||
color: var(--success-color);
|
color: var(--success-color);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,12 @@ createApp({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDropdownCommand = async (command) => {
|
||||||
|
if (command === 'login') {
|
||||||
|
showAdminLogin();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const showAdminLogin = () => {
|
const showAdminLogin = () => {
|
||||||
adminLoginForm.value = { password: '' };
|
adminLoginForm.value = { password: '' };
|
||||||
adminLoginVisible.value = true;
|
adminLoginVisible.value = true;
|
||||||
@@ -579,7 +585,7 @@ createApp({
|
|||||||
cookieDialogVisible, cookieDialogTitle, cookieForm,
|
cookieDialogVisible, cookieDialogTitle, cookieForm,
|
||||||
websiteForm, filterWebsiteUser,
|
websiteForm, filterWebsiteUser,
|
||||||
currentUserWebsites, filteredWebsites,
|
currentUserWebsites, filteredWebsites,
|
||||||
checkAdminStatus, showAdminLogin, adminLogin, handleAdminCommand,
|
checkAdminStatus, showAdminLogin, adminLogin, handleAdminCommand, handleDropdownCommand,
|
||||||
loadUsers, loadUsersWithWebsites, loadWebsites, loadDashboard, refreshDashboardStatus,
|
loadUsers, loadUsersWithWebsites, loadWebsites, loadDashboard, refreshDashboardStatus,
|
||||||
startAutoRefresh, stopAutoRefresh,
|
startAutoRefresh, stopAutoRefresh,
|
||||||
checkLogin, manageWebsite, manageUserWebsites,
|
checkLogin, manageWebsite, manageUserWebsites,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<el-container>
|
<el-container>
|
||||||
<el-header>
|
<el-header>
|
||||||
<div class="header-left">
|
<div class="header-left">
|
||||||
<h1>Cookie监控管理系统</h1>
|
<h1>网站监控仪表板</h1>
|
||||||
<el-button v-if="activeTab === 'settings'" @click="activeTab = 'dashboard'" type="primary" plain>返回监控首页</el-button>
|
<el-button v-if="activeTab === 'settings'" @click="activeTab = 'dashboard'" type="primary" plain>返回监控首页</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
@@ -24,8 +24,17 @@
|
|||||||
<el-icon class="rotating-icon"><Refresh /></el-icon>
|
<el-icon class="rotating-icon"><Refresh /></el-icon>
|
||||||
<span class="refresh-text">{{ countdown }}秒后自动刷新</span>
|
<span class="refresh-text">{{ countdown }}秒后自动刷新</span>
|
||||||
</div>
|
</div>
|
||||||
<el-button v-if="activeTab === 'dashboard'" @click="loadDashboard" type="primary" plain>刷新</el-button>
|
<span class="header-stat" v-if="activeTab === 'dashboard'">网站总数:<b>{{ stats.totalWebsites }}</b></span>
|
||||||
<el-button @click="showAdminLogin" type="warning" plain v-if="!isAdmin">登录后台</el-button>
|
<el-dropdown @command="handleDropdownCommand" v-if="!isAdmin">
|
||||||
|
<el-button link type="text" style="color: rgba(255,255,255,0.8); font-size: 18px">
|
||||||
|
<el-icon><arrow-down /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item command="login"><el-icon><Lock /></el-icon> 登录后台</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
<el-dropdown @command="handleAdminCommand" v-else>
|
<el-dropdown @command="handleAdminCommand" v-else>
|
||||||
<el-button type="success" plain>后台管理 <el-icon><arrow-down /></el-icon></el-button>
|
<el-button type="success" plain>后台管理 <el-icon><arrow-down /></el-icon></el-button>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
@@ -42,19 +51,6 @@
|
|||||||
<el-main>
|
<el-main>
|
||||||
<!-- 监控仪表板 -->
|
<!-- 监控仪表板 -->
|
||||||
<div v-if="activeTab === 'dashboard'">
|
<div v-if="activeTab === 'dashboard'">
|
||||||
<div class="dashboard-header">
|
|
||||||
<h2>网站监控仪表板</h2>
|
|
||||||
<div class="dashboard-stats">
|
|
||||||
<el-statistic title="网站总数" :value="stats.totalWebsites" />
|
|
||||||
<el-statistic title="在线" :value="stats.onlineCount">
|
|
||||||
<template #suffix><el-icon><circle-check /></el-icon></template>
|
|
||||||
</el-statistic>
|
|
||||||
<el-statistic title="离线" :value="stats.offlineCount">
|
|
||||||
<template #suffix><el-icon><circle-close /></el-icon></template>
|
|
||||||
</el-statistic>
|
|
||||||
<el-statistic title="未检测" :value="stats.unknownCount" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-for="user in dashboardData" :key="user.id" class="user-section">
|
<div v-for="user in dashboardData" :key="user.id" class="user-section">
|
||||||
<div class="user-header">
|
<div class="user-header">
|
||||||
@@ -65,6 +61,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-table :data="user.websites" style="width: 100%; margin-bottom: 20px">
|
<el-table :data="user.websites" style="width: 100%; margin-bottom: 20px">
|
||||||
|
<el-table-column label="启用状态" width="90">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag :type="scope.row.status === 1 ? 'success' : 'danger'" size="small">
|
||||||
|
{{ scope.row.status === 1 ? '启用' : '禁用' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="name" label="网站名称" width="150"></el-table-column>
|
<el-table-column prop="name" label="网站名称" width="150"></el-table-column>
|
||||||
<el-table-column prop="url" label="URL" width="250">
|
<el-table-column prop="url" label="URL" width="250">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
@@ -98,6 +101,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-empty v-if="dashboardData.length === 0" description="暂无网站数据"></el-empty>
|
<el-empty v-if="dashboardData.length === 0" description="暂无网站数据"></el-empty>
|
||||||
|
|
||||||
|
<div class="dashboard-footer">
|
||||||
|
<p>免责声明:本系统仅用于Cookie状态监控和自动化管理,不对任何网站数据承担责任。请确保您有权访问和管理相关网站账号。</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 网站管理 -->
|
<!-- 网站管理 -->
|
||||||
|
|||||||
-97
@@ -1,97 +0,0 @@
|
|||||||
{
|
|
||||||
"users": [
|
|
||||||
{
|
|
||||||
"name": "小余",
|
|
||||||
"cookie_cloud": {
|
|
||||||
"uuid": "hu6n2vcUmzpu7mqUN2rVCg",
|
|
||||||
"password": "jtDM5dV9AyqXkZdQVeA9f6",
|
|
||||||
"api_url": "https://movie-pilot.org/cookiecloud"
|
|
||||||
},
|
|
||||||
"notification": {
|
|
||||||
"iyuu_token": "IYUU37629Tc1d371c7ce99a49ff9778e196286b7e4592be191"
|
|
||||||
},
|
|
||||||
"browser": {
|
|
||||||
"type": "edge",
|
|
||||||
"headless": false
|
|
||||||
},
|
|
||||||
"websites": [
|
|
||||||
{
|
|
||||||
"name": "柴油联名卡",
|
|
||||||
"url": "https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll",
|
|
||||||
"login_check_selector": "",
|
|
||||||
"success_text": "彭峰"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "彭峰(个人)",
|
|
||||||
"cookie_cloud": {
|
|
||||||
"uuid": "qyZpTrgiP5mVwiRZwfBhjz",
|
|
||||||
"password": "iGn1B4FnWftp3oj4Ko3jxA",
|
|
||||||
"api_url": "http://192.168.1.100:3000/cookiecloud"
|
|
||||||
},
|
|
||||||
"notification": {
|
|
||||||
"iyuu_token": "IYUU37629Tc1d371c7ce99a49ff9778e196286b7e4592be191"
|
|
||||||
},
|
|
||||||
"browser": {
|
|
||||||
"type": "edge",
|
|
||||||
"headless": false
|
|
||||||
},
|
|
||||||
"websites": [
|
|
||||||
{
|
|
||||||
"name": "柴油联名卡",
|
|
||||||
"url": "https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll",
|
|
||||||
"login_check_selector": "",
|
|
||||||
"success_text": "彭峰"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "网站B",
|
|
||||||
"url": "https://192.168.1.200:8006/",
|
|
||||||
"login_check_selector": "",
|
|
||||||
"success_text": "root@pam"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "彭峰(公司)",
|
|
||||||
"cookie_cloud": {
|
|
||||||
"uuid": "aCgAWN5DsYhP88FnTmrr3H",
|
|
||||||
"password": "bK8dfh1a6ZZ79jWeeMedjN",
|
|
||||||
"api_url": "https://movie-pilot.org/cookiecloud"
|
|
||||||
},
|
|
||||||
"notification": {
|
|
||||||
"iyuu_token": "IYUU37629Tc1d371c7ce99a49ff9778e196286b7e4592be191"
|
|
||||||
},
|
|
||||||
"browser": {
|
|
||||||
"type": "edge",
|
|
||||||
"headless": false
|
|
||||||
},
|
|
||||||
"websites": [
|
|
||||||
{
|
|
||||||
"name": "柴油联名卡",
|
|
||||||
"url": "https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll",
|
|
||||||
"login_check_selector": "",
|
|
||||||
"success_text": "彭峰"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "加油卡交易",
|
|
||||||
"url": "https://cardweb.salecard.sinopec.com/card/index.jsp",
|
|
||||||
"login_check_selector": "",
|
|
||||||
"success_text": "彭峰"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "数字销售门户",
|
|
||||||
"url": "https://ewcc.sinopec.com/?authConfigs=37d5aed075525d4fa0fe635231cba447",
|
|
||||||
"login_check_selector": "",
|
|
||||||
"success_text": "彭峰"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "飞牛存储",
|
|
||||||
"url": "http://10.190.20.156:5666/",
|
|
||||||
"login_check_selector": "",
|
|
||||||
"success_text": "彭峰"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
{
|
|
||||||
"小余": {
|
|
||||||
"lmkbi.95155.com": {
|
|
||||||
"cookies": [
|
|
||||||
{
|
|
||||||
"name": "_qimei_i_1",
|
|
||||||
"value": "5bd854d4c10f0489c79eff300ad57ae0f1bba6f017520a84e6862c582493206c616336c03980ebdd829cd4f1",
|
|
||||||
"domain": ".95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "userType",
|
|
||||||
"value": "2",
|
|
||||||
"domain": "lmkbi.95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "_qimei_fingerprint",
|
|
||||||
"value": "46d124002cf7d99787d08337dcd33c84",
|
|
||||||
"domain": ".95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "LMKBIUSS",
|
|
||||||
"value": "eyJhY2NvdW50SWQiOjIzMzk0OTQ3NTAwMjA0OSwicGhvbmUiOiIxMzU0ODU2OTY2NiIsInRpbWVzdGFtcCI6MTc3Mjg4NzYxMjgwOCwidG9rZW4iOiI3YWM0YjZkMS1lYzc2LTQ3NDgtOTM4MS1kZDUwZGI4NjM1NTEifQ==",
|
|
||||||
"domain": "lmkbi.95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "edentoken",
|
|
||||||
"value": "13548569666",
|
|
||||||
"domain": "lmkbi.95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "_qimei_uuid42",
|
|
||||||
"value": "1991d0e1933100350aa906e215996b94a17042ee55",
|
|
||||||
"domain": ".95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "user",
|
|
||||||
"value": "13548569666",
|
|
||||||
"domain": "lmkbi.95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "_qimei_h38",
|
|
||||||
"value": "fdedb6910aa906e215996b9402000001e1991d",
|
|
||||||
"domain": ".95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "_qimei_i_3",
|
|
||||||
"value": "5be076d19c08548d939eff62098270e7f3e7a4f3145c0a8ab7dd2b0d24c5246b336337943c89e2aa8cb7",
|
|
||||||
"domain": ".95155.com"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"url": "https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll",
|
|
||||||
"website_name": "柴油联名卡"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"彭峰(个人)": {
|
|
||||||
"192.168.1.200:8006": {
|
|
||||||
"cookies": [
|
|
||||||
{
|
|
||||||
"name": "PVELangCookie",
|
|
||||||
"value": "zh_CN",
|
|
||||||
"domain": "192.168.1.200"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "PVEAuthCookie",
|
|
||||||
"value": "PVE%3Aroot@pam%3A69ACCBCF%3A%3AwZbqJgSmRXadHue3IxPXURT4YqLAH5XluGp6nedMrZDn01QLvg4yjk1P1Nf08FXzZoH75gxA1USwhZXRbgWn9azugDgWhmwTF5eL2y4xWmYBhYP5Gk+J64hb2OgIr4WoJvxXcUceAFYurDorboz7ILSgJ+Rbwua+rPnmUV2qzYBjSw8r1AyOYTjbdjVjoTM4Erls1JMz1zTCOJFLcEQNgsR0BnXa5VmIb5rp8inRUkA8hRkuDtMp5+HnaF2R+KOEf9CmqjO5nf/48mlGYtg3Bj0wktIO/oX66fRJ4xljIoByLYJhgz03XrarIXxh3o+Foh2yFvhbLpRiwO2QjHQqeA%3D%3D",
|
|
||||||
"domain": "192.168.1.200"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"url": "https://192.168.1.200:8006/",
|
|
||||||
"website_name": "网站B"
|
|
||||||
},
|
|
||||||
"lmkbi.95155.com": {
|
|
||||||
"cookies": [
|
|
||||||
{
|
|
||||||
"name": "_qimei_uuid42",
|
|
||||||
"value": "1a302130f16100ca18af370a47cb8afce807c4a076",
|
|
||||||
"domain": ".95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "_qimei_fingerprint",
|
|
||||||
"value": "50aa79f919511142818459f44ac38dee",
|
|
||||||
"domain": ".95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "edentoken",
|
|
||||||
"value": "13548569666",
|
|
||||||
"domain": "lmkbi.95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "LMKBIUSS",
|
|
||||||
"value": "eyJhY2NvdW50SWQiOjIzMzk0OTQ3NTAwMjA0OSwicGhvbmUiOiIxMzU0ODU2OTY2NiIsInRpbWVzdGFtcCI6MTc3Mjg4NzYxMjgwOCwidG9rZW4iOiI3YWM0YjZkMS1lYzc2LTQ3NDgtOTM4MS1kZDUwZGI4NjM1NTEifQ==",
|
|
||||||
"domain": "lmkbi.95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "userType",
|
|
||||||
"value": "2",
|
|
||||||
"domain": "lmkbi.95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "_qimei_i_1",
|
|
||||||
"value": "23ed70d49d0f50dcc497f83153d525e3f0eef5f51508518ae5d97b582493206c6163649c39d8e1dcd4b1e482",
|
|
||||||
"domain": ".95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "_qimei_i_3",
|
|
||||||
"value": "64c844d0c35e05dc9796fc355d8470e5a3eba5f0410e00d3e78c2d0e2f95293d306031943c89e29eb6a6",
|
|
||||||
"domain": ".95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "user",
|
|
||||||
"value": "13548569666",
|
|
||||||
"domain": "lmkbi.95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "_qimei_h38",
|
|
||||||
"value": "f8e0750618af370a47cb8afc0200000c91a302",
|
|
||||||
"domain": ".95155.com"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"url": "https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll",
|
|
||||||
"website_name": "柴油联名卡"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"彭峰(公司)": {
|
|
||||||
"lmkbi.95155.com": {
|
|
||||||
"cookies": [
|
|
||||||
{
|
|
||||||
"name": "_qimei_h38",
|
|
||||||
"value": "fdedb6910aa906e215996b9402000001e1991d",
|
|
||||||
"domain": ".95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "userType",
|
|
||||||
"value": "2",
|
|
||||||
"domain": "lmkbi.95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "LMKBIUSS",
|
|
||||||
"value": "eyJhY2NvdW50SWQiOjIzMzk0OTQ3NTAwMjA0OSwicGhvbmUiOiIxMzU0ODU2OTY2NiIsInRpbWVzdGFtcCI6MTc3Mjg4NzYxMjgwOCwidG9rZW4iOiI3YWM0YjZkMS1lYzc2LTQ3NDgtOTM4MS1kZDUwZGI4NjM1NTEifQ==",
|
|
||||||
"domain": "lmkbi.95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "edentoken",
|
|
||||||
"value": "13548569666",
|
|
||||||
"domain": "lmkbi.95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "_qimei_i_3",
|
|
||||||
"value": "5be076d19c08548d939eff62098270e7f3e7a4f3145c0a8ab7dd2b0d24c5246b336337943c89e2aa8cb7",
|
|
||||||
"domain": ".95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "_qimei_i_1",
|
|
||||||
"value": "5bd854d4c10f0489c79eff300ad57ae0f1bba6f017520a84e6862c582493206c616336c03980ebdd829cd4f1",
|
|
||||||
"domain": ".95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "user",
|
|
||||||
"value": "13548569666",
|
|
||||||
"domain": "lmkbi.95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "_qimei_fingerprint",
|
|
||||||
"value": "46d124002cf7d99787d08337dcd33c84",
|
|
||||||
"domain": ".95155.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "_qimei_uuid42",
|
|
||||||
"value": "1991d0e1933100350aa906e215996b94a17042ee55",
|
|
||||||
"domain": ".95155.com"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"url": "https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll",
|
|
||||||
"website_name": "柴油联名卡"
|
|
||||||
},
|
|
||||||
"cardweb.salecard.sinopec.com": {
|
|
||||||
"cookies": [],
|
|
||||||
"url": "https://cardweb.salecard.sinopec.com/card/index.jsp",
|
|
||||||
"website_name": "加油卡交易"
|
|
||||||
},
|
|
||||||
"ewcc.sinopec.com": {
|
|
||||||
"cookies": [],
|
|
||||||
"url": "https://ewcc.sinopec.com/?authConfigs=37d5aed075525d4fa0fe635231cba447",
|
|
||||||
"website_name": "数字销售门户"
|
|
||||||
},
|
|
||||||
"10.190.20.156:5666": {
|
|
||||||
"cookies": [],
|
|
||||||
"url": "http://10.190.20.156:5666/",
|
|
||||||
"website_name": "飞牛存储"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
"""Cookie监控管理系统 - 检测客户端"""
|
|
||||||
import time
|
|
||||||
import requests
|
|
||||||
from datetime import datetime
|
|
||||||
from typing import Dict, List
|
|
||||||
from DrissionPage import ChromiumPage, ChromiumOptions
|
|
||||||
from utils.config import BACKEND_URL, BROWSER_TYPE, HEADLESS_MODE
|
|
||||||
+117
-8
@@ -5,11 +5,20 @@ Cookie监控管理系统 - 检测客户端
|
|||||||
然后分用户、分网站登录。
|
然后分用户、分网站登录。
|
||||||
"""
|
"""
|
||||||
import time
|
import time
|
||||||
|
import logging
|
||||||
import requests
|
import requests
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Dict, List, Optional
|
from typing import Dict, List, Optional
|
||||||
from DrissionPage import ChromiumPage, ChromiumOptions
|
from DrissionPage import ChromiumPage, ChromiumOptions
|
||||||
from config.config import BACKEND_URL, BROWSER_TYPE, HEADLESS_MODE, PAGE_LOAD_TIMEOUT
|
from config.config import BACKEND_URL, BROWSER_TYPE, HEADLESS_MODE, PAGE_LOAD_TIMEOUT
|
||||||
|
from cookie_cloud_client import download_cookies, get_cookies_for_domain
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format='%(asctime)s [%(name)s] %(message)s',
|
||||||
|
datefmt='%Y-%m-%d %H:%M:%S'
|
||||||
|
)
|
||||||
|
logger = logging.getLogger('client')
|
||||||
|
|
||||||
|
|
||||||
class DetectionClient:
|
class DetectionClient:
|
||||||
@@ -239,13 +248,38 @@ class DetectionClient:
|
|||||||
# 获取网站的cookie
|
# 获取网站的cookie
|
||||||
cookies = self.get_website_cookies(website_id)
|
cookies = self.get_website_cookies(website_id)
|
||||||
if not cookies:
|
if not cookies:
|
||||||
print(f" 警告: 未找到网站 {website_name} 的cookie")
|
print(f" 警告: 未找到网站 {website_name} 的cookie,尝试从Cookie Cloud获取...")
|
||||||
|
login_success = self._try_cookie_cloud_and_retry(user, website, url, check_selector, success_text)
|
||||||
|
response_time = time.time() - start_time
|
||||||
|
|
||||||
|
if login_success:
|
||||||
|
print(f" [OK] 登录验证成功")
|
||||||
|
current_cookies = self.get_current_cookies()
|
||||||
|
if current_cookies:
|
||||||
|
self.update_website_cookies(website_id, current_cookies)
|
||||||
|
print(f" 已更新cookie ({len(current_cookies)} 个)")
|
||||||
|
|
||||||
|
self.save_detection_result(
|
||||||
|
website_id=website_id,
|
||||||
|
status=1,
|
||||||
|
response_time=response_time,
|
||||||
|
http_status=200,
|
||||||
|
message="登录验证成功(Cookie Cloud首次导入)"
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f" [FAIL] Cookie Cloud重试失败")
|
||||||
|
self.failed_websites.append({
|
||||||
|
'user': user,
|
||||||
|
'website': website,
|
||||||
|
'reason': '未找到cookie且Cookie Cloud重试失败'
|
||||||
|
})
|
||||||
self.save_detection_result(
|
self.save_detection_result(
|
||||||
website_id=website_id,
|
website_id=website_id,
|
||||||
status=0,
|
status=0,
|
||||||
response_time=time.time() - start_time,
|
response_time=response_time,
|
||||||
http_status=0,
|
http_status=0,
|
||||||
message="未找到cookie"
|
message="未找到cookie且Cookie Cloud重试失败"
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -264,8 +298,14 @@ class DetectionClient:
|
|||||||
login_success = self._check_login_with_retry(url, check_selector, success_text)
|
login_success = self._check_login_with_retry(url, check_selector, success_text)
|
||||||
response_time = time.time() - start_time
|
response_time = time.time() - start_time
|
||||||
|
|
||||||
|
# 如果仍然失败,尝试从Cookie Cloud下载新cookie并重试
|
||||||
|
if not login_success:
|
||||||
|
print(f" 常规检测全部失败,尝试从Cookie Cloud更新cookie...")
|
||||||
|
login_success = self._try_cookie_cloud_and_retry(user, website, url, check_selector, success_text)
|
||||||
|
response_time = time.time() - start_time
|
||||||
|
|
||||||
if login_success:
|
if login_success:
|
||||||
print(f" ✓ 登录验证成功")
|
print(f" [OK] 登录验证成功")
|
||||||
|
|
||||||
# 获取最新cookie并保存到后台
|
# 获取最新cookie并保存到后台
|
||||||
current_cookies = self.get_current_cookies()
|
current_cookies = self.get_current_cookies()
|
||||||
@@ -283,13 +323,13 @@ class DetectionClient:
|
|||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
print(f" ✗ 登录验证失败(连续6次检测未登录)")
|
print(f" [FAIL] 登录验证失败(含Cookie Cloud重试)")
|
||||||
|
|
||||||
# 记录失败信息
|
# 记录失败信息
|
||||||
self.failed_websites.append({
|
self.failed_websites.append({
|
||||||
'user': user,
|
'user': user,
|
||||||
'website': website,
|
'website': website,
|
||||||
'reason': '登录验证失败(连续6次检测未登录)'
|
'reason': '登录验证失败(含Cookie Cloud重试)'
|
||||||
})
|
})
|
||||||
|
|
||||||
# 保存检测结果
|
# 保存检测结果
|
||||||
@@ -298,13 +338,13 @@ class DetectionClient:
|
|||||||
status=0,
|
status=0,
|
||||||
response_time=response_time,
|
response_time=response_time,
|
||||||
http_status=200,
|
http_status=200,
|
||||||
message="登录验证失败(连续6次检测未登录)"
|
message="登录验证失败(含Cookie Cloud重试)"
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
response_time = time.time() - start_time
|
response_time = time.time() - start_time
|
||||||
print(f" ✗ 检测异常: {e}")
|
print(f" [FAIL] 检测异常: {e}")
|
||||||
|
|
||||||
# 记录失败信息
|
# 记录失败信息
|
||||||
self.failed_websites.append({
|
self.failed_websites.append({
|
||||||
@@ -323,6 +363,75 @@ class DetectionClient:
|
|||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def _try_cookie_cloud_and_retry(self, user: Dict, website: Dict, url: str,
|
||||||
|
check_selector: str, success_text: str) -> bool:
|
||||||
|
"""
|
||||||
|
尝试从Cookie Cloud下载新cookie并重新检测登录
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
是否登录成功
|
||||||
|
"""
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
parsed = urlparse(url)
|
||||||
|
domain = parsed.netloc
|
||||||
|
|
||||||
|
cc_uuid = user.get('cookie_cloud_uuid')
|
||||||
|
cc_password = user.get('cookie_cloud_password')
|
||||||
|
cc_api_url = user.get('cookie_cloud_api_url', 'https://movie-pilot.org/cookiecloud')
|
||||||
|
|
||||||
|
if not cc_uuid or not cc_password:
|
||||||
|
logger.info(f" 用户未配置Cookie Cloud,跳过 (UUID: {cc_uuid})")
|
||||||
|
return False
|
||||||
|
|
||||||
|
logger.info(f" ==================== Cookie Cloud 下载开始 ====================")
|
||||||
|
logger.info(f" 目标域名: {domain}")
|
||||||
|
logger.info(f" API地址: {cc_api_url}")
|
||||||
|
logger.info(f" UUID: {cc_uuid}")
|
||||||
|
logger.info(f" Password: {'*' * len(cc_password)}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
cookies_data = download_cookies(cc_api_url, cc_uuid, cc_password)
|
||||||
|
|
||||||
|
logger.info(f" 下载完成,总域名数: {len(cookies_data) if isinstance(cookies_data, dict) else 0}")
|
||||||
|
|
||||||
|
domain_cookies = get_cookies_for_domain(cookies_data, domain)
|
||||||
|
|
||||||
|
if not domain_cookies:
|
||||||
|
logger.info(f" Cookie Cloud中未找到 {domain} 的cookie")
|
||||||
|
logger.info(f" ==================== Cookie Cloud 下载结束 ====================")
|
||||||
|
return False
|
||||||
|
|
||||||
|
logger.info(f" 从Cookie Cloud获取到 {len(domain_cookies)} 个cookie")
|
||||||
|
logger.info(f" 导入并重试...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.browser.clear_cache()
|
||||||
|
logger.info(f" 已清除浏览器缓存")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f" 清除缓存失败: {e}")
|
||||||
|
|
||||||
|
imported = self.import_cookies_to_browser(domain_cookies, domain)
|
||||||
|
logger.info(f" 导入cookie: {imported}/{len(domain_cookies)} 个成功")
|
||||||
|
|
||||||
|
logger.info(f" 访问网站: {url}")
|
||||||
|
self.browser.get(url)
|
||||||
|
self.browser.wait.doc_loaded(timeout=PAGE_LOAD_TIMEOUT)
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
if self._is_logged_in(check_selector, success_text):
|
||||||
|
logger.info(f" Cookie Cloud cookie登录成功")
|
||||||
|
logger.info(f" ==================== Cookie Cloud 下载结束 ====================")
|
||||||
|
return True
|
||||||
|
|
||||||
|
logger.info(f" Cookie Cloud cookie登录失败")
|
||||||
|
logger.info(f" ==================== Cookie Cloud 下载结束 ====================")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f" Cookie Cloud异常: {e}")
|
||||||
|
logger.info(f" ==================== Cookie Cloud 下载结束 ====================")
|
||||||
|
return False
|
||||||
|
|
||||||
def _check_login_with_retry(self, url: str, check_selector: str, success_text: str,
|
def _check_login_with_retry(self, url: str, check_selector: str, success_text: str,
|
||||||
retry_count: int = 6, retry_interval: int = 30) -> bool:
|
retry_count: int = 6, retry_interval: int = 30) -> bool:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"backend_url": "http://localhost:5000",
|
||||||
|
"browser_type": "edge",
|
||||||
|
"headless_mode": false,
|
||||||
|
"page_load_timeout": 30
|
||||||
|
}
|
||||||
+31
-10
@@ -1,15 +1,36 @@
|
|||||||
"""
|
"""
|
||||||
配置文件
|
配置文件 - 从 config.json 读取配置,支持环境变量覆盖
|
||||||
"""
|
"""
|
||||||
# 后台服务地址
|
import json
|
||||||
BACKEND_URL = "http://localhost:5000"
|
import os
|
||||||
|
|
||||||
# 浏览器配置
|
_config = {}
|
||||||
BROWSER_TYPE = "edge" # edge 或 chrome
|
|
||||||
HEADLESS_MODE = False # 是否无头模式
|
|
||||||
|
|
||||||
# 检测间隔(秒)
|
def _load_config():
|
||||||
CHECK_INTERVAL = 30
|
global _config
|
||||||
|
config_path = os.path.join(os.path.dirname(__file__), 'config.json')
|
||||||
|
defaults = {
|
||||||
|
'backend_url': 'http://localhost:5000',
|
||||||
|
'browser_type': 'edge',
|
||||||
|
'headless_mode': False,
|
||||||
|
'page_load_timeout': 30
|
||||||
|
}
|
||||||
|
if os.path.exists(config_path):
|
||||||
|
with open(config_path, 'r', encoding='utf-8') as f:
|
||||||
|
_config = {**defaults, **json.load(f)}
|
||||||
|
else:
|
||||||
|
_config = defaults
|
||||||
|
|
||||||
# 页面加载超时时间(秒)
|
def get(key, default=None):
|
||||||
PAGE_LOAD_TIMEOUT = 30
|
if not _config:
|
||||||
|
_load_config()
|
||||||
|
return _config.get(key.upper(), _config.get(key, default))
|
||||||
|
|
||||||
|
# 兼容旧接口
|
||||||
|
BACKEND_URL = os.environ.get('BACKEND_URL') or get('backend_url', 'http://localhost:5000')
|
||||||
|
BROWSER_TYPE = os.environ.get('BROWSER_TYPE') or get('browser_type', 'edge')
|
||||||
|
HEADLESS_MODE = os.environ.get('HEADLESS_MODE') or get('headless_mode', False)
|
||||||
|
if isinstance(HEADLESS_MODE, str):
|
||||||
|
HEADLESS_MODE = HEADLESS_MODE.lower() in ('true', '1', 'yes')
|
||||||
|
CHECK_INTERVAL = int(os.environ.get('CHECK_INTERVAL') or get('check_interval', 30))
|
||||||
|
PAGE_LOAD_TIMEOUT = int(os.environ.get('PAGE_LOAD_TIMEOUT') or get('page_load_timeout', 30))
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
"""
|
||||||
|
Cookie Cloud 客户端(独立前端使用)
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import hashlib
|
||||||
|
import logging
|
||||||
|
import requests
|
||||||
|
from base64 import b64decode
|
||||||
|
|
||||||
|
logger = logging.getLogger('cookie_cloud')
|
||||||
|
|
||||||
|
try:
|
||||||
|
from Cryptodome.Cipher import AES
|
||||||
|
from Cryptodome.Util.Padding import unpad
|
||||||
|
except ImportError:
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
from Crypto.Util.Padding import unpad
|
||||||
|
|
||||||
|
|
||||||
|
def cookie_decrypt(uuid: str, encrypted_b64: str, password: str) -> dict:
|
||||||
|
"""解密Cookie Cloud数据"""
|
||||||
|
the_key = hashlib.md5(f"{uuid}-{password}".encode()).hexdigest()[:16].encode()
|
||||||
|
encrypted_data = b64decode(encrypted_b64)
|
||||||
|
|
||||||
|
logger.info("尝试AES-ECB解密...")
|
||||||
|
try:
|
||||||
|
cipher = AES.new(the_key, AES.MODE_ECB)
|
||||||
|
decrypted = cipher.decrypt(encrypted_data)
|
||||||
|
result = unpad(decrypted, AES.block_size)
|
||||||
|
data = json.loads(result.decode('utf-8'))
|
||||||
|
logger.info("AES-ECB解密成功")
|
||||||
|
return data
|
||||||
|
except Exception as e:
|
||||||
|
logger.info(f"AES-ECB解密失败: {e},尝试Salted__格式...")
|
||||||
|
pass
|
||||||
|
|
||||||
|
if encrypted_data[:8] == b'Salted__':
|
||||||
|
logger.info("检测到Salted__格式,尝试CBC解密...")
|
||||||
|
salt = encrypted_data[8:16]
|
||||||
|
ciphertext = encrypted_data[16:]
|
||||||
|
logger.info(f"Salt: {salt.hex()}")
|
||||||
|
d = [b'']
|
||||||
|
while len(b''.join(d)) < 48:
|
||||||
|
d.append(hashlib.md5(d[-1] + the_key + salt).digest())
|
||||||
|
key_iv = b''.join(d)
|
||||||
|
cipher = AES.new(key_iv[:32], AES.MODE_CBC, key_iv[32:48])
|
||||||
|
decrypted = unpad(cipher.decrypt(ciphertext), AES.block_size)
|
||||||
|
data = json.loads(decrypted.decode('utf-8'))
|
||||||
|
logger.info("CBC解密成功")
|
||||||
|
return data
|
||||||
|
|
||||||
|
logger.error("所有解密方式均失败")
|
||||||
|
raise ValueError('无法解密Cookie数据')
|
||||||
|
|
||||||
|
|
||||||
|
def download_cookies(api_url: str, uuid: str, password: str) -> dict:
|
||||||
|
"""从Cookie Cloud服务器下载并解密Cookie"""
|
||||||
|
api_url = api_url.rstrip('/')
|
||||||
|
url = f"{api_url}/get/{uuid}"
|
||||||
|
|
||||||
|
logger.info(f"[1/3] 请求Cookie Cloud: {url}")
|
||||||
|
logger.info(f"[1/3] UUID: {uuid}")
|
||||||
|
|
||||||
|
response = requests.get(url, params={'password': password}, timeout=10)
|
||||||
|
response.raise_for_status()
|
||||||
|
result = response.json()
|
||||||
|
|
||||||
|
logger.info(f"[1/3] HTTP状态码: {response.status_code}")
|
||||||
|
logger.info(f"[1/3] 返回数据keys: {list(result.keys())}")
|
||||||
|
logger.info(f"[1/3] 返回数据大小: {len(json.dumps(result))} bytes")
|
||||||
|
|
||||||
|
if isinstance(result, dict) and result.get('encrypted'):
|
||||||
|
logger.info("[2/3] 检测到加密数据,开始解密...")
|
||||||
|
result = cookie_decrypt(uuid, result['encrypted'], password)
|
||||||
|
logger.info(f"[2/3] 解密完成,数据类型: {type(result)}")
|
||||||
|
if isinstance(result, dict):
|
||||||
|
logger.info(f"[2/3] Cookie数据包含域名: {list(result.keys())}")
|
||||||
|
|
||||||
|
if isinstance(result, dict) and 'cookie_data' in result:
|
||||||
|
cookies_data = result.get('cookie_data', {})
|
||||||
|
logger.info(f"[3/3] 新版CookieCloud格式,提取cookie_data")
|
||||||
|
logger.info(f"[3/3] cookie_data包含域名数: {len(cookies_data)}")
|
||||||
|
return cookies_data
|
||||||
|
|
||||||
|
logger.info(f"[3/3] 返回数据已处理完成")
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def get_cookies_for_domain(cookies_data: dict, domain: str) -> list:
|
||||||
|
"""提取指定域名对应的Cookie列表"""
|
||||||
|
result = []
|
||||||
|
matched_hosts = []
|
||||||
|
|
||||||
|
domain_parts = domain.lower().split('.')
|
||||||
|
|
||||||
|
for host, cookie_list in cookies_data.items():
|
||||||
|
host_clean = host.lower().lstrip('.')
|
||||||
|
domain_clean = domain.lower()
|
||||||
|
|
||||||
|
is_match = False
|
||||||
|
if host_clean == domain_clean:
|
||||||
|
is_match = True
|
||||||
|
elif host_clean.endswith('.' + domain_clean):
|
||||||
|
is_match = True
|
||||||
|
elif domain_clean.endswith('.' + host_clean):
|
||||||
|
is_match = True
|
||||||
|
|
||||||
|
if is_match:
|
||||||
|
matched_hosts.append(host)
|
||||||
|
if isinstance(cookie_list, list):
|
||||||
|
for cookie in cookie_list:
|
||||||
|
if cookie.get('name') and cookie.get('value'):
|
||||||
|
result.append({
|
||||||
|
'name': cookie['name'],
|
||||||
|
'value': cookie['value'],
|
||||||
|
'domain': cookie.get('domain', domain),
|
||||||
|
'path': cookie.get('path', '/')
|
||||||
|
})
|
||||||
|
|
||||||
|
logger.info(f"域名匹配结果: 目标={domain}, 匹配hosts={matched_hosts}")
|
||||||
|
logger.info(f"提取Cookie数量: {len(result)}")
|
||||||
|
if result:
|
||||||
|
cookie_names = [c['name'] for c in result[:5]]
|
||||||
|
logger.info(f"前5个Cookie名称: {cookie_names}")
|
||||||
|
|
||||||
|
return result
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
"""
|
|
||||||
更新用户Cookie Cloud参数
|
|
||||||
"""
|
|
||||||
import json
|
|
||||||
import sqlite3
|
|
||||||
import os
|
|
||||||
|
|
||||||
DB_PATH = os.path.join(os.path.dirname(__file__), 'backend', 'instance', 'cookie_monitor.db')
|
|
||||||
|
|
||||||
def update_user_cookie_cloud():
|
|
||||||
"""更新用户Cookie Cloud参数"""
|
|
||||||
with open('config.json', 'r', encoding='utf-8') as f:
|
|
||||||
config = json.load(f)
|
|
||||||
|
|
||||||
conn = sqlite3.connect(DB_PATH)
|
|
||||||
cursor = conn.cursor()
|
|
||||||
|
|
||||||
# 添加新列(如果不存在)
|
|
||||||
columns_to_add = [
|
|
||||||
('cookie_cloud_uuid', 'VARCHAR(255)'),
|
|
||||||
('cookie_cloud_password', 'VARCHAR(255)'),
|
|
||||||
('cookie_cloud_api_url', 'VARCHAR(255)')
|
|
||||||
]
|
|
||||||
|
|
||||||
for col_name, col_type in columns_to_add:
|
|
||||||
try:
|
|
||||||
cursor.execute(f"ALTER TABLE users ADD COLUMN {col_name} {col_type}")
|
|
||||||
print(f"添加列: {col_name}")
|
|
||||||
except sqlite3.OperationalError as e:
|
|
||||||
if 'duplicate column name' in str(e).lower():
|
|
||||||
print(f"列已存在: {col_name}")
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
|
|
||||||
for user_config in config['users']:
|
|
||||||
user_name = user_config['name']
|
|
||||||
cc = user_config.get('cookie_cloud', {})
|
|
||||||
|
|
||||||
cursor.execute(
|
|
||||||
"UPDATE users SET cookie_cloud_uuid = ?, cookie_cloud_password = ?, cookie_cloud_api_url = ? WHERE name = ?",
|
|
||||||
(
|
|
||||||
cc.get('uuid', ''),
|
|
||||||
cc.get('password', ''),
|
|
||||||
cc.get('api_url', ''),
|
|
||||||
user_name
|
|
||||||
)
|
|
||||||
)
|
|
||||||
print(f"更新用户 {user_name}: UUID={cc.get('uuid', '')}, API={cc.get('api_url', '')}")
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
print("\n更新完成!")
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
update_user_cookie_cloud()
|
|
||||||
Reference in New Issue
Block a user