Fixed some security issues and added daemon boot

This commit is contained in:
RiceRound
2024-12-27 22:30:17 +08:00
parent b4be661341
commit aefe44abc6
8 changed files with 92 additions and 78 deletions
+39 -40
View File
@@ -1,33 +1,32 @@
_e='RiceRoundTempTokenNode'
_d='RiceRoundOutputImageNode'
_c='RiceRoundEncryptNode'
_b='RiceRoundOutputTextNode'
_a='RiceRoundOutputBooleanNode'
_Z='RiceRoundOutputFloatNode'
_Y='RiceRoundOutputIntNode'
_X='RiceRoundOutputMaskBridgeNode'
_W='RiceRoundUploadImageNode'
_V='RiceRoundImageUrlNode'
_U='RiceRoundOutputImageBridgeNode'
_T='RiceRoundDecryptNode'
_S='RiceRoundStrToBooleanNode'
_R='RiceRoundStrToFloatNode'
_Q='RiceRoundStrToIntNode'
_P='RiceRoundBooleanNode'
_O='RiceRoundFloatNode'
_N='RiceRoundIntNode'
_M='RiceRoundDownloadMaskNode'
_L='RiceRoundMaskBridgeNode'
_K='RiceRoundInputTextNode'
_J='RiceRoundRandomSeedNode'
_I='RiceRoundDownloadImageNode'
_H='RiceRoundSimpleImageNode'
_G='RiceRoundImageBridgeNode'
_F='RiceRoundDebugNode'
_E='RiceRoundAdvancedChoiceNode'
_D='RiceRoundSimpleChoiceNode'
_C='dynamic_class'
_B='error'
_d='RiceRoundTempTokenNode'
_c='RiceRoundOutputImageNode'
_b='RiceRoundEncryptNode'
_a='RiceRoundOutputTextNode'
_Z='RiceRoundOutputBooleanNode'
_Y='RiceRoundOutputFloatNode'
_X='RiceRoundOutputIntNode'
_W='RiceRoundOutputMaskBridgeNode'
_V='RiceRoundUploadImageNode'
_U='RiceRoundImageUrlNode'
_T='RiceRoundOutputImageBridgeNode'
_S='RiceRoundDecryptNode'
_R='RiceRoundStrToBooleanNode'
_Q='RiceRoundStrToFloatNode'
_P='RiceRoundStrToIntNode'
_O='RiceRoundBooleanNode'
_N='RiceRoundFloatNode'
_M='RiceRoundIntNode'
_L='RiceRoundDownloadMaskNode'
_K='RiceRoundMaskBridgeNode'
_J='RiceRoundInputTextNode'
_I='RiceRoundRandomSeedNode'
_H='RiceRoundDownloadImageNode'
_G='RiceRoundSimpleImageNode'
_F='RiceRoundImageBridgeNode'
_E='RiceRoundDebugNode'
_D='RiceRoundAdvancedChoiceNode'
_C='RiceRoundSimpleChoiceNode'
_B='dynamic_class'
_A='display_name'
import platform,random
from urllib.parse import unquote
@@ -41,14 +40,14 @@ from aiohttp import web
from functools import partial
from.rice_prompt_handler import RiceRoundPromptHandler
from.rice_url_config import RiceUrlConfig
from.rice_prompt_info import RicePromptInfo
from.rice_prompt_info import RiceEnvConfig,RicePromptInfo
def create_dynamic_nodes(base_class):
rice_prompt_info=RicePromptInfo();dynamic_classes={}
for(node_name,info)in rice_prompt_info.choice_classname_map.items():class_name=node_name;category='RiceRound/Advanced/Choice';dynamic_class=type(class_name,(base_class,),{'__node_name__':node_name,'CATEGORY':category});dynamic_classes[class_name]={_C:dynamic_class,_A:info.get(_A,class_name)}
for(node_name,info)in rice_prompt_info.choice_classname_map.items():class_name=node_name;category='RiceRound/Advanced/Choice';dynamic_class=type(class_name,(base_class,),{'__node_name__':node_name,'CATEGORY':category});dynamic_classes[class_name]={_B:dynamic_class,_A:info.get(_A,class_name)}
return dynamic_classes
dynamic_choice_nodes=create_dynamic_nodes(RiceRoundBaseChoiceNode)
NODE_CLASS_MAPPINGS={_D:RiceRoundSimpleChoiceNode,_E:RiceRoundAdvancedChoiceNode,_F:RiceRoundDebugNode,_G:RiceRoundImageBridgeNode,_H:RiceRoundSimpleImageNode,_I:RiceRoundDownloadImageNode,_J:RiceRoundRandomSeedNode,_K:RiceRoundInputTextNode,_L:RiceRoundMaskBridgeNode,_M:RiceRoundDownloadMaskNode,_N:RiceRoundIntNode,_O:RiceRoundFloatNode,_P:RiceRoundBooleanNode,_Q:RiceRoundStrToIntNode,_R:RiceRoundStrToFloatNode,_S:RiceRoundStrToBooleanNode,_T:RiceRoundDecryptNode,_U:RiceRoundOutputImageBridgeNode,_V:RiceRoundImageUrlNode,_W:RiceRoundUploadImageNode,_X:RiceRoundOutputMaskBridgeNode,_Y:RiceRoundOutputIntNode,_Z:RiceRoundOutputFloatNode,_a:RiceRoundOutputBooleanNode,_b:RiceRoundOutputTextNode,_c:RiceRoundEncryptNode,_d:RiceRoundOutputImageNode,_e:RiceRoundTempTokenNode,**{name:cls[_C]for(name,cls)in dynamic_choice_nodes.items()}}
NODE_DISPLAY_NAME_MAPPINGS={_D:'Simple Choice',_E:'Advanced Choice',_F:'Debug',_G:'Image Bridge',_H:'Simple Image',_I:'Download Image',_J:'Random Seed',_K:'Input Text',_L:'Mask Bridge',_M:'Download Mask',_N:'RiceRound Int',_O:'RiceRound Float',_P:'RiceRound Boolean',_Q:'RiceRound Str To Int',_R:'RiceRound Str To Float',_S:'RiceRound Str To Boolean',_T:'Decrypt',_U:'Output Image Bridge',_V:'Image URL',_W:'Upload Image',_X:'Output Mask Bridge',_Y:'Output Int',_Z:'Output Float',_a:'Output Boolean',_b:'Output Text',_c:'Encrypt',_d:'Output Image',_e:'Temp Token',**{name:cls[_A]for(name,cls)in dynamic_choice_nodes.items()}}
NODE_CLASS_MAPPINGS={_C:RiceRoundSimpleChoiceNode,_D:RiceRoundAdvancedChoiceNode,_E:RiceRoundDebugNode,_F:RiceRoundImageBridgeNode,_G:RiceRoundSimpleImageNode,_H:RiceRoundDownloadImageNode,_I:RiceRoundRandomSeedNode,_J:RiceRoundInputTextNode,_K:RiceRoundMaskBridgeNode,_L:RiceRoundDownloadMaskNode,_M:RiceRoundIntNode,_N:RiceRoundFloatNode,_O:RiceRoundBooleanNode,_P:RiceRoundStrToIntNode,_Q:RiceRoundStrToFloatNode,_R:RiceRoundStrToBooleanNode,_S:RiceRoundDecryptNode,_T:RiceRoundOutputImageBridgeNode,_U:RiceRoundImageUrlNode,_V:RiceRoundUploadImageNode,_W:RiceRoundOutputMaskBridgeNode,_X:RiceRoundOutputIntNode,_Y:RiceRoundOutputFloatNode,_Z:RiceRoundOutputBooleanNode,_a:RiceRoundOutputTextNode,_b:RiceRoundEncryptNode,_c:RiceRoundOutputImageNode,_d:RiceRoundTempTokenNode,**{name:cls[_B]for(name,cls)in dynamic_choice_nodes.items()}}
NODE_DISPLAY_NAME_MAPPINGS={_C:'Simple Choice',_D:'Advanced Choice',_E:'Debug',_F:'Image Bridge',_G:'Simple Image',_H:'Download Image',_I:'Random Seed',_J:'Input Text',_K:'Mask Bridge',_L:'Download Mask',_M:'RiceRound Int',_N:'RiceRound Float',_O:'RiceRound Boolean',_P:'RiceRound Str To Int',_Q:'RiceRound Str To Float',_R:'RiceRound Str To Boolean',_S:'Decrypt',_T:'Output Image Bridge',_U:'Image URL',_V:'Upload Image',_W:'Output Mask Bridge',_X:'Output Int',_Y:'Output Float',_Z:'Output Boolean',_a:'Output Text',_b:'Encrypt',_c:'Output Image',_d:'Temp Token',**{name:cls[_A]for(name,cls)in dynamic_choice_nodes.items()}}
WEB_DIRECTORY='./js'
__all__=['NODE_CLASS_MAPPINGS','NODE_DISPLAY_NAMES_MAPPINGS','WEB_DIRECTORY']
handler_instance=RiceRoundPromptHandler()
@@ -67,16 +66,16 @@ async def auth_callback(request):
async def set_node_additional_info(request):additional_info=await request.json();RicePromptInfo().set_node_additional_info(additional_info);return web.json_response({},status=200)
@routes.get('/riceround/open_selector_list_folder')
async def open_selector_list_folder(request):
A='error'
if request.remote not in('127.0.0.1','::1'):return web.json_response({A:'Unauthorized access'},status=403)
choice_server_folder=RicePromptInfo().get_choice_server_folder()
if not choice_server_folder.exists():return web.json_response({_B:'Folder does not exist'},status=404)
if not choice_server_folder.exists():return web.json_response({A:'Folder does not exist'},status=404)
system=platform.system()
try:
if system=='Windows':os.startfile(choice_server_folder)
elif system=='Darwin':subprocess.run(['open',choice_server_folder])
else:subprocess.run(['xdg-open',choice_server_folder])
return web.json_response({'status':'success'},status=200)
except Exception as e:return web.json_response({_B:str(e)},status=500)
@routes.post('/riceround/set_long_token')
async def set_long_token(request):
try:request_data=await request.json();long_token=request_data.get('long_token','');AuthUnit().set_user_long_token(long_token);return web.json_response({},status=200)
except Exception as e:return web.json_response({_B:str(e)},status=500)
except Exception as e:return web.json_response({A:str(e)},status=500)
@routes.get('/riceround/save_current_env_config')
async def save_current_env_config(request):RiceEnvConfig().save_env_config();return web.json_response({},status=200)
+3 -9
View File
@@ -6,7 +6,7 @@ import base64,json,os
from pathlib import Path
import time
from urllib.parse import urljoin
from.utils import get_local_app_path,get_machine_id
from.utils import get_local_app_setting_path,get_machine_id
from.rice_url_config import RiceUrlConfig
from server import PromptServer
import urllib.request,urllib.error,configparser
@@ -17,17 +17,11 @@ class AuthUnit:
return A._instance
def __init__(A):
B=True
if not hasattr(A,'initialized'):A.machine_id=get_machine_id();A.url_config=RiceUrlConfig();A.callback_path='/riceround/auth_callback';A.shift_key=sum(ord(A)for A in A.machine_id[:8])%20+1;C=get_local_app_path();C.mkdir(parents=B,exist_ok=B);A.config_path=C/'config.ini';A.auto_login=False;A.load_config();A.last_check_time=0;A.temp_token='';A.long_token='';A.initialized=B
if not hasattr(A,'initialized'):A.machine_id=get_machine_id();A.url_config=RiceUrlConfig();A.callback_path='/riceround/auth_callback';A.shift_key=sum(ord(A)for A in A.machine_id[:8])%20+1;C=get_local_app_setting_path();C.mkdir(parents=B,exist_ok=B);A.config_path=C/'config.ini';A.auto_login=False;A.load_config();A.last_check_time=0;A.temp_token='';A.initialized=B
def load_config(A):B=configparser.ConfigParser();B.read(A.config_path,encoding=_A);A.auto_login=B.get(_B,'auto_login',fallback=False)
def set_temp_token(A,temp_token):A.temp_token=temp_token
def set_user_long_token(A,long_token):
B=long_token
if not B:A.long_token=''
elif len(B)==64:A.long_token=B;A.clear_user_token()
def get_user_token(B):
A=''
if B.long_token:A=B.long_token
else:A=B.read_user_token()
A='';A=B.read_user_token()
if not A and B.temp_token:A=B.temp_token
if A and time.time()-B.last_check_time>120:
try:
+1 -1
View File
@@ -1 +1 @@
import{api}from"../../../scripts/api.js";import{ComfyApp,app}from"../../../scripts/app.js";app.registerExtension({name:"riceround.config",async setup(){const e=localStorage.getItem("RiceRound.Setting.user.long_token");e&&64==e.length&&api.fetchApi("/riceround/set_long_token",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({long_token:e})}),app.ui.settings.addSetting({id:"RiceRound.Setting.name",name:"模型列表存放位置,可以制造需要的ChoiceNode",type:()=>{const e=document.createElement("tr"),t=document.createElement("td"),o=document.createElement("input");return o.type="button",o.value="打开文件夹",o.style.borderRadius="8px",o.style.padding="8px 16px",o.style.fontSize="14px",o.style.cursor="pointer",o.style.border="1px solid #666",o.style.backgroundColor="#444",o.style.color="#fff",o.onmouseover=()=>{o.style.backgroundColor="#555"},o.onmouseout=()=>{o.style.backgroundColor="#444"},o.onclick=()=>{api.fetchApi("/riceround/open_selector_list_folder",{method:"GET",headers:{"Content-Type":"application/json"}})},t.appendChild(o),e.appendChild(t),e}}),app.ui.settings.addSetting({id:"RiceRound.User.long_token",name:"设置用户token,从www.riceround.online获取",type:"text",defaultValue:"",tooltip:"用于非本机授权登录情况,请勿泄露!提倡使用本机登录授权更安全!",onChange:function(e){let t=!1;64==e.length?(localStorage.setItem("RiceRound.Setting.user.long_token",e),t=!0):e||(localStorage.removeItem("RiceRound.Setting.user.long_token"),t=!0),t&&api.fetchApi("/riceround/set_long_token",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({long_token:e})})}})}});
import{api}from"../../../scripts/api.js";import{ComfyApp,app}from"../../../scripts/app.js";import{showToast,showHtmlMessageBox}from"./riceround.js";app.registerExtension({name:"riceround.config",async setup(){app.ui.settings.addSetting({id:"RiceRound.Setting.name",name:"模型列表存放位置,可以制造需要的ChoiceNode",type:()=>{const e=document.createElement("tr"),t=document.createElement("td"),o=document.createElement("input");return o.type="button",o.value="打开文件夹",o.style.borderRadius="8px",o.style.padding="8px 16px",o.style.fontSize="14px",o.style.cursor="pointer",o.style.border="1px solid #666",o.style.backgroundColor="#444",o.style.color="#fff",o.onmouseover=()=>{o.style.backgroundColor="#555"},o.onmouseout=()=>{o.style.backgroundColor="#444"},o.onclick=()=>{api.fetchApi("/riceround/open_selector_list_folder",{method:"GET",headers:{"Content-Type":"application/json"}})},t.appendChild(o),e.appendChild(t),e}}),app.ui.settings.addSetting({id:"RiceRound.User.env_config",name:"获取ComfyUI环境配置,用于share_client启动",tooltip:"使用conda等虚拟环境的情况下自动获取可能出错,建议手动设置client.toml",type:()=>{const e=document.createElement("tr"),t=document.createElement("td"),o=document.createElement("input");return o.type="button",o.value="获取参数(自动分析)",o.style.borderRadius="8px",o.style.padding="8px 16px",o.style.fontSize="14px",o.style.cursor="pointer",o.style.border="1px solid #666",o.style.backgroundColor="#444",o.style.color="#fff",o.onmouseover=()=>{o.style.backgroundColor="#555"},o.onmouseout=()=>{o.style.backgroundColor="#444"},o.onclick=async()=>{200==(await api.fetchApi("/riceround/save_current_env_config",{method:"GET",headers:{"Content-Type":"application/json"}})).status?showToast("获取参数成功!如果启动后异常,建议手动设置client.toml","info",3e3):showToast("获取参数失败!请手动设置client.toml","error",3e3)},t.appendChild(o),e.appendChild(t),e}})}});
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -3,7 +3,7 @@ _B='class_type'
_A='prompt'
import json,os,random,tempfile,time
from.auth_unit import AuthUnit
from.utils import get_local_app_path
from.utils import get_local_app_setting_path
from.rice_prompt_info import RicePromptInfo
class RiceRoundPromptHandler:
_instance=None;_initialized=False
+40 -19
View File
@@ -1,46 +1,49 @@
_E='file_name'
_D='options_value'
_C='choice_node'
_B='python_class_name'
_G='file_name'
_F='options_value'
_E='choice_node'
_D='python_class_name'
_C='utf-8'
_B=False
_A=True
import hashlib,json
import configparser,hashlib,json,os
from pathlib import Path
import sys
from server import PromptServer
import re
from.utils import get_local_app_path
from.utils import get_local_app_setting_path
class RicePromptInfo:
_instance=None;_initialized=False
_instance=None;_initialized=_B
def __new__(A):
if A._instance is None:A._instance=super(RicePromptInfo,A).__new__(A)
return A._instance
def __init__(A):
if RicePromptInfo._initialized:return
A.task_info_folder=get_local_app_path()/'tasks'
A.task_info_folder=get_local_app_setting_path()/'tasks'
if not A.task_info_folder.exists():A.task_info_folder.mkdir(parents=_A)
A.choice_node_map={};A.new_choice_file_map={};A.choice_classname_map={};A.load_choice_node_map();RicePromptInfo._initialized=_A
def clear(A):A.choice_node_map.clear();A.new_choice_file_map.clear()
def get_choice_server_folder(B):
A=B.task_info_folder/_C
A=B.task_info_folder/_E
if not A.exists():A.mkdir(parents=_A)
return A
def load_choice_node_map(A):
E=A.get_choice_server_folder()
for B in E.glob('*.json'):
try:
with open(B,'r',encoding='utf-8')as F:
C=json.load(F);D=C.get(_B)
with open(B,'r',encoding=_C)as F:
C=json.load(F);D=C.get(_D)
if D:A.choice_classname_map[D]=C
except json.JSONDecodeError:print(f"Error parsing JSON from server file: {B}");continue
def get_choice_node_options(A,node_class_name):return A.choice_classname_map.get(node_class_name,{}).get(_D,[])
def get_choice_classname(A,node_id):return A.choice_node_map.get(node_id,{}).get(_B,'')
def get_choice_value(A,node_id):return A.choice_node_map.get(node_id,{}).get(_D,[])
def get_choice_node_options(A,node_class_name):return A.choice_classname_map.get(node_class_name,{}).get(_F,[])
def get_choice_classname(A,node_id):return A.choice_node_map.get(node_id,{}).get(_D,'')
def get_choice_value(A,node_id):return A.choice_node_map.get(node_id,{}).get(_F,[])
def save_choice_classname(D,save_folder):
A=Path(save_folder)/_C
A=Path(save_folder)/_E
if not A.exists():A.mkdir(parents=_A)
for(F,B)in D.new_choice_file_map.items():
C=B.get(_E,'')
C=B.get(_G,'')
if C:
with open(A/f"{C}.json",'w',encoding='utf-8')as E:json.dump(B,E,ensure_ascii=False,indent=4)
with open(A/f"{C}.json",'w',encoding=_C)as E:json.dump(B,E,ensure_ascii=_B,indent=4)
def set_node_additional_info(B,node_additional_info):
H='template_id';C=node_additional_info
if C and isinstance(C,dict):
@@ -50,5 +53,23 @@ class RicePromptInfo:
if J=='RiceRoundAdvancedChoiceNode':
E=re.sub('[<>:"/\\\\|?*]','',G);F='RiceRoundAdvancedChoiceNode_'+hashlib.md5(E.lower().encode()).hexdigest()
if F in B.choice_classname_map:print(f"Error RicePromptInfo set_node_additional_info python_class_name {F} already exists");PromptServer.instance.send_sync('rice_round_toast',{'content':'选择名称重复,如果本身是同一类型的节点,可以忽略提示','type':'info','duration':5000})
A[_B]=F;A[_E]=E;B.new_choice_file_map[E]=A
B.choice_node_map[D]=A
A[_D]=F;A[_G]=E;B.new_choice_file_map[E]=A
B.choice_node_map[D]=A
class RiceEnvConfig:
def __init__(A):A.local_app_path=get_local_app_setting_path();A.config_path=A.local_app_path/'config.ini'
def filter_add_cmd(F,add_cmd):
B=add_cmd;C=[];A=_B
if not B:return''
try:
for D in B.split():
if A:A=_B;continue
if D in['--listen','--port']:A=_A;continue
C.append(D)
except Exception as E:print(f"Error processing add_cmd: {E}");return''
return' '.join(C)
def save_env_config(B):
C='ComfyUI';D=sys.executable;E=os.getcwd();F=' '.join(sys.argv[1:]);B.local_app_path.mkdir(parents=_A,exist_ok=_A);A=configparser.ConfigParser()
if B.config_path.exists():A.read(B.config_path,encoding=_C)
if not A.has_section(C):A.add_section(C)
G=B.filter_add_cmd(F).strip();A.set(C,'PythonPath',D);A.set(C,'WorkingDirectory',E);A.set(C,'AddCmd',G)
with open(B.config_path,'w',encoding=_C)as H:A.write(H)
+5 -5
View File
@@ -13,7 +13,7 @@ from PIL import Image
from io import BytesIO
import numpy as np,requests
from urllib.parse import urljoin
from.utils import get_local_app_path
from.utils import get_local_app_setting_path
DEFAULT_SUBDOMAIN='api'if os.getenv('DEBUG')!='true'else'test'
DEFAULT_URL_PREFIX=f"https://{DEFAULT_SUBDOMAIN}.riceround.online"
DEFAULT_WS_PREFIX=f"wss://{DEFAULT_SUBDOMAIN}.riceround.online"
@@ -28,10 +28,10 @@ class RiceUrlConfig:
def __init__(A):
if not A._initialized:A.comfyui_local_web_server_info={};A.load_comfyui_local_web_server_info();A.server_info={};A.load_server_info();A._initialized=True
def set_comfyui_local_web_server_info(B,local_server_info):
A=local_server_info;B.comfyui_local_web_server_info=A;C=get_local_app_path();D=C/_C
A=local_server_info;B.comfyui_local_web_server_info=A;C=get_local_app_setting_path();D=C/_C
with open(D,'w')as E:json.dump(A,E)
def load_comfyui_local_web_server_info(A):
C=get_local_app_path();B=C/_C
C=get_local_app_setting_path();B=C/_C
if B.exists():
with open(B,'r')as D:A.comfyui_local_web_server_info=json.load(D)
else:A.comfyui_local_web_server_info={}
@@ -44,10 +44,10 @@ class RiceUrlConfig:
if B and isinstance(B,dict):
A=B.get(_A)
if A and isinstance(A,dict):
C.server_info=A;D=get_local_app_path()
C.server_info=A;D=get_local_app_setting_path()
with open(D/_D,'w')as E:json.dump(A,E)
def load_server_info(B):
C=get_local_app_path();A=C/_D
C=get_local_app_setting_path();A=C/_D
if A.exists():
with open(A,'r')as D:B.server_info=json.load(D)
def get_server_url(A,url_path):return urljoin(A.url_prefix,url_path)
+2 -2
View File
@@ -39,9 +39,9 @@ def calculate_machine_id():
except Exception:pass
return str(uuid.getnode())
def normalize_machine_id(machine_id):'\n 接受一个机器标识符,并返回经过 MD5 哈希处理的规范化标识符\n ';A=_B;B=machine_id.strip();C=B.lower();D=C+A;E=hashlib.md5(D.encode(_A));return E.hexdigest()
def get_local_app_path():A=Path.home();B=A/_B;return B
def get_local_app_setting_path():A=Path.home();B=A/_B;return B
def get_machine_id():
'\n 返回机器ID,为了兼容各个平台,各个语言,需要统一读写这个值\n ';F='machine_id';B='Machine';D=get_local_app_path();C=D/'machine.ini'
'\n 返回机器ID,为了兼容各个平台,各个语言,需要统一读写这个值\n ';F='machine_id';B='Machine';D=get_local_app_setting_path();C=D/'machine.ini'
try:D.mkdir(parents=True,exist_ok=True)
except Exception as E:print(f"Error creating directory '{D}': {E}");return''
A=configparser.ConfigParser()