diff --git a/__init__.py b/__init__.py
index 4a469ab..eea4b4a 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1,6 +1,8 @@
from functools import partial, wraps
import logging
import os
+import shutil
+from custom_nodes.ComfyUI_CryptoCat.utils import get_local_app_setting_path
from .trim_workflow import WorkflowTrimHandler
from .crypto_node import (
SaveCryptoNode,
@@ -84,9 +86,11 @@ async def keygen(request):
return aiohttp.web.json_response({"serial_number": serial_number}, status=200)
-@routes.get("/cryptocat/logout")
+@routes.get("/cryptocat/clear")
async def logout(request):
AuthUnit().clear_user_token()
+ local_app_setting_path = get_local_app_setting_path()
+ shutil.rmtree(local_app_setting_path, ignore_errors=True)
return aiohttp.web.json_response({"status": "success"}, status=200)
diff --git a/js/catconfig.js b/js/catconfig.js
index 7cac586..71003cb 100644
--- a/js/catconfig.js
+++ b/js/catconfig.js
@@ -1 +1 @@
-import{api}from"../../../scripts/api.js";import{ComfyApp,app}from"../../../scripts/app.js";import{showToast}from"./mycat.js";export const UserTokenKey="cryptocat_user_token";async function showKeygenMessageBox(e){const t=document.createElement("div");document.body.appendChild(t);const{createApp:n,ref:o}=Vue,a=n({template:'\n \n \n \n \n \n \n \n \n \n \n \n 0表示永久有效\n \n \n \n \n \n \n \n \n 生成序列号\n \n
\n \n ',setup(){const n=o(!0),r=o({templateId:"",expireDate:"",useDays:0}),l=o(""),i=o(!1);return{title:e,dialogVisible:n,form:r,result:l,loading:i,generateSerial:async function(){if(r.value.templateId.trim()){i.value=!0;try{const e=await async function(e,t,n){try{const o={template_id:e};t&&(o.expire_date=t),n&&(o.use_days=n);const a=await api.fetchApi("/cryptocat/keygen",{method:"POST",body:JSON.stringify(o)}),r=await a.json();if(!a.ok)throw new Error(r.error_msg||`HTTP error! status: ${a.status}`);return r.serial_number||r.error_msg||"获取失败:服务器返回数据格式错误"}catch(e){throw new Error(`获取序列号失败: ${e.message}`)}}(r.value.templateId.trim(),r.value.expireDate,r.value.useDays);l.value=e}catch(e){ElementPlus.ElMessage.error(e.message||"未知错误")}finally{i.value=!1}}else ElementPlus.ElMessage.warning("请输入template_id")},handleClose:function(){a.unmount(),t.remove()},handleClear:function(){l.value="",r.value={templateId:"",expireDate:"",useDays:0}},copyToClipboard:async function(){try{await navigator.clipboard.writeText(l.value),ElementPlus.ElMessage.success("序列号已复制到剪贴板")}catch(e){ElementPlus.ElMessage.error("复制失败")}},disabledDate:e=>e.getTime()e.length>0&&n.test(e)))}app.registerExtension({name:"CryptoCat.config",async setup(){app.ui.settings.addSetting({id:"CryptoCat.Keygen.name",name:"输入template_id,计算序列号",type:()=>{const e=document.createElement("tr"),t=document.createElement("td"),n=document.createElement("input");return n.type="button",n.value="算号器",n.style.borderRadius="8px",n.style.padding="8px 16px",n.style.fontSize="14px",n.style.cursor="pointer",n.style.border="1px solid #666",n.style.backgroundColor="#444",n.style.color="#fff",n.onmouseover=()=>{n.style.backgroundColor="#555"},n.onmouseout=()=>{n.style.backgroundColor="#444"},n.onclick=()=>{showKeygenMessageBox("算号器","算号器","question")},t.appendChild(n),e.appendChild(t),e}}),app.ui.settings.addSetting({id:"CryptoCat.User.logout",name:"登出当前用户",type:()=>{const e=document.createElement("tr"),t=document.createElement("td"),n=document.createElement("input");return n.type="button",n.value="登出",n.style.borderRadius="8px",n.style.padding="8px 16px",n.style.fontSize="14px",n.style.cursor="pointer",n.style.border="1px solid #666",n.style.backgroundColor="#444",n.style.color="#fff",n.onclick=async()=>{localStorage.removeItem(UserTokenKey),localStorage.removeItem("Comfy.Settings.CryptoCat.User.long_token"),app.ui.settings.setSettingValue("CryptoCat.User.long_token",""),await api.fetchApi("/cryptocat/logout"),showToast("登出成功")},t.appendChild(n),e.appendChild(t),e}}),app.ui.settings.addSetting({id:"CryptoCat.User.long_token",name:"设置长效token",type:"text",textType:"password",defaultValue:"",tooltip:"用于非本机授权登录情况,请勿泄露!提倡使用本机登录授权更安全!",onChange:async function(e){isValidJWTFormat(e)&&await api.fetchApi("/cryptocat/set_long_token",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({long_token:e})})}}),app.ui.settings.addSetting({id:"CryptoCat.User.login",name:"登录RiceRound账户",type:()=>{const e=document.createElement("tr"),t=document.createElement("td"),n=document.createElement("input");return n.type="button",n.value="登录RiceRound账户",n.style.borderRadius="8px",n.style.padding="8px 16px",n.style.fontSize="14px",n.style.cursor="pointer",n.style.border="1px solid #3498db",n.style.backgroundColor="#3498db",n.style.color="#fff",n.onmouseover=()=>{n.style.backgroundColor="#2980b9"},n.onmouseout=()=>{n.style.backgroundColor="#3498db"},n.onclick=async()=>{try{const e=await api.fetchApi("/cryptocat/login",{method:"POST"}),t=await e.json();showToast(t.error_msg||"登录中...")}catch(e){showToast("登录请求失败","error")}},t.appendChild(n),e.appendChild(t),e}}),app.ui.settings.addSetting({id:"CryptoCat.Setting.auto_overwrite",name:"自动覆盖更新同id工作流",type:"boolean",defaultValue:!1,tooltip:"设置为true时,会自动覆盖已有的template_id的数据",onChange:function(e){api.fetchApi("/cryptocat/set_auto_overwrite",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({auto_overwrite:e})})}})}});
\ No newline at end of file
+import{api}from"../../../scripts/api.js";import{ComfyApp,app}from"../../../scripts/app.js";import{showToast}from"./mycat.js";export const UserTokenKey="cryptocat_user_token";async function showKeygenMessageBox(e){const t=document.createElement("div");document.body.appendChild(t);const{createApp:n,ref:o}=Vue,a=n({template:'\n \n \n \n \n \n \n \n \n \n \n \n 0表示永久有效\n \n \n \n \n \n \n \n \n 生成序列号\n \n
\n \n ',setup(){const n=o(!0),r=o({templateId:"",expireDate:"",useDays:0}),l=o(""),i=o(!1);return{title:e,dialogVisible:n,form:r,result:l,loading:i,generateSerial:async function(){if(r.value.templateId.trim()){i.value=!0;try{const e=await async function(e,t,n){try{const o={template_id:e};t&&(o.expire_date=t),n&&(o.use_days=n);const a=await api.fetchApi("/cryptocat/keygen",{method:"POST",body:JSON.stringify(o)}),r=await a.json();if(!a.ok)throw new Error(r.error_msg||`HTTP error! status: ${a.status}`);return r.serial_number||r.error_msg||"获取失败:服务器返回数据格式错误"}catch(e){throw new Error(`获取序列号失败: ${e.message}`)}}(r.value.templateId.trim(),r.value.expireDate,r.value.useDays);l.value=e}catch(e){ElementPlus.ElMessage.error(e.message||"未知错误")}finally{i.value=!1}}else ElementPlus.ElMessage.warning("请输入template_id")},handleClose:function(){a.unmount(),t.remove()},handleClear:function(){l.value="",r.value={templateId:"",expireDate:"",useDays:0}},copyToClipboard:async function(){try{await navigator.clipboard.writeText(l.value),ElementPlus.ElMessage.success("序列号已复制到剪贴板")}catch(e){ElementPlus.ElMessage.error("复制失败")}},disabledDate:e=>e.getTime()e.length>0&&n.test(e)))}app.registerExtension({name:"CryptoCat.config",async setup(){app.ui.settings.addSetting({id:"CryptoCat.Keygen.name",name:"输入template_id,计算序列号",type:()=>{const e=document.createElement("tr"),t=document.createElement("td"),n=document.createElement("input");return n.type="button",n.value="算号器",n.style.borderRadius="8px",n.style.padding="8px 16px",n.style.fontSize="14px",n.style.cursor="pointer",n.style.border="1px solid #666",n.style.backgroundColor="#444",n.style.color="#fff",n.onmouseover=()=>{n.style.backgroundColor="#555"},n.onmouseout=()=>{n.style.backgroundColor="#444"},n.onclick=()=>{showKeygenMessageBox("算号器","算号器","question")},t.appendChild(n),e.appendChild(t),e}}),app.ui.settings.addSetting({id:"CryptoCat.User.clear",name:"清理所有数据",tooltip:"完成镜像部署前最后一步,清理所有数据",type:()=>{const e=document.createElement("tr"),t=document.createElement("td"),n=document.createElement("input");return n.type="button",n.value="清理",n.style.borderRadius="8px",n.style.padding="8px 16px",n.style.fontSize="14px",n.style.cursor="pointer",n.style.border="1px solid #666",n.style.backgroundColor="#444",n.style.color="#fff",n.onclick=async()=>{localStorage.removeItem(UserTokenKey),localStorage.removeItem("Comfy.Settings.CryptoCat.User.long_token"),app.ui.settings.setSettingValue("CryptoCat.User.long_token",""),await api.fetchApi("/cryptocat/clear"),showToast("清理成功")},t.appendChild(n),e.appendChild(t),e}}),app.ui.settings.addSetting({id:"CryptoCat.User.long_token",name:"设置长效token",type:"text",textType:"password",defaultValue:"",tooltip:"用于非本机授权登录情况,请勿泄露!提倡使用本机登录授权更安全!",onChange:async function(e){isValidJWTFormat(e)&&await api.fetchApi("/cryptocat/set_long_token",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({long_token:e})})}}),app.ui.settings.addSetting({id:"CryptoCat.User.login",name:"登录RiceRound账户",type:()=>{const e=document.createElement("tr"),t=document.createElement("td"),n=document.createElement("input");return n.type="button",n.value="登录RiceRound账户",n.style.borderRadius="8px",n.style.padding="8px 16px",n.style.fontSize="14px",n.style.cursor="pointer",n.style.border="1px solid #3498db",n.style.backgroundColor="#3498db",n.style.color="#fff",n.onmouseover=()=>{n.style.backgroundColor="#2980b9"},n.onmouseout=()=>{n.style.backgroundColor="#3498db"},n.onclick=async()=>{try{const e=await api.fetchApi("/cryptocat/login",{method:"POST"}),t=await e.json();showToast(t.error_msg||"登录中...")}catch(e){showToast("登录请求失败","error")}},t.appendChild(n),e.appendChild(t),e}}),app.ui.settings.addSetting({id:"CryptoCat.Setting.auto_overwrite",name:"自动覆盖更新同id工作流",type:"boolean",defaultValue:!1,tooltip:"设置为true时,会自动覆盖已有的template_id的数据",onChange:function(e){api.fetchApi("/cryptocat/set_auto_overwrite",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({auto_overwrite:e})})}})}});
\ No newline at end of file
diff --git a/url_config.py b/url_config.py
index d18b225..3ddf93a 100644
--- a/url_config.py
+++ b/url_config.py
@@ -50,7 +50,7 @@ class CatUrlConfig:
@property
def login_api_url(self):
- return self.get_server_url("/api/workflow/get_info")
+ return self.get_server_url("/api/cryptocat/get_info")
@property
def workflow_url(self):
diff --git a/utils.py b/utils.py
index 7594c64..938ba6f 100644
--- a/utils.py
+++ b/utils.py
@@ -11,6 +11,7 @@ import platform
import subprocess
import random
import string
+import socket
def pil2tensor(images: Image.Image | list[Image.Image]) -> torch.Tensor:
@@ -29,45 +30,40 @@ def pil2tensor(images: Image.Image | list[Image.Image]) -> torch.Tensor:
return torch.cat([single_pil2tensor(img) for img in images], dim=0)
-def calculate_machine_id():
- "\n 获取跨平台的机器唯一标识符,类似于 gopsutil 的 HostID\n"
- system = platform.system()
- if system == "Linux":
- try:
- with open("/etc/machine-id", "r") as f:
- return f.read().strip()
- except FileNotFoundError:
- try:
- with open("/var/lib/dbus/machine-id", "r") as f:
- return f.read().strip()
- except FileNotFoundError:
- pass
- try:
- output = subprocess.check_output(["cat", "/sys/class/dmi/id/product_uuid"])
- return output.decode().strip()
- except Exception:
- pass
- elif system == "Windows":
- try:
- import winreg
+def _calculate_machine_id():
+ "\n 获取跨平台的机器唯一标识码,优化对云平台和虚拟机的支持。\n 主要通过CPU信息、MAC地址等硬件特征来区分不同机器。\n 在Linux平台上额外添加随机数以区分相同硬件的云主机。\n"
+ import platform
+ import socket
+ import uuid
+ import hashlib
- reg_key = "SOFTWARE\\Microsoft\\Cryptography"
- with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, reg_key) as key:
- machine_guid, _ = winreg.QueryValueEx(key, "MachineGuid")
- return machine_guid
- except Exception:
- pass
- elif system == "Darwin":
+ def get_cpu_info():
+ "获取CPU信息"
try:
- output = subprocess.check_output(
- ["ioreg", "-rd1", "-c", "IOPlatformExpertDevice"]
- )
- for line in output.decode().splitlines():
- if "IOPlatformUUID" in line:
- return line.split("=")[-1].strip().strip('"')
- except Exception:
- pass
- return str(uuid.getnode())
+ if platform.system() == "Windows":
+ return platform.processor()
+ else:
+ return platform.machine()
+ except:
+ return ""
+
+ def get_mac_addresses():
+ "获取所有网卡的MAC地址"
+ try:
+ from uuid import getnode
+
+ mac = getnode()
+ return str(mac) if mac != 0 else ""
+ except:
+ return ""
+
+ system_info = [get_cpu_info(), get_mac_addresses(), platform.machine()]
+ if platform.system() == "Linux":
+ system_info.append(str(uuid.uuid4()))
+ valid_info = list(filter(None, system_info))
+ if not valid_info:
+ return str(uuid.uuid4())
+ return "".join(valid_info)
def normalize_machine_id(machine_id: str) -> str:
@@ -101,7 +97,7 @@ def get_machine_id() -> str:
config.read(config_file, encoding="utf-8")
if "Machine" in config and "machine_id" in config["Machine"]:
return config["Machine"]["machine_id"]
- original_host_id = calculate_machine_id()
+ original_host_id = _calculate_machine_id()
machine_id = normalize_machine_id(original_host_id)
if "Machine" not in config:
config.add_section("Machine")