From 8b3ab331d09239f73534fcdff5cfa5cb63bea445 Mon Sep 17 00:00:00 2001 From: Icyoung <337884991@qq.com> Date: Sat, 8 Nov 2025 11:28:51 +0800 Subject: [PATCH] =?UTF-8?q?Dev=20api=20bugfix=20(#740)=20*=20feat:=20remov?= =?UTF-8?q?e=20admin=20mode=20*=20feat:=20bugfix=20*=20feat(crypto):=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0RSA-OAEP=20+=20AES-GCM=E6=B7=B7=E5=90=88?= =?UTF-8?q?=E5=8A=A0=E5=AF=86=E6=9C=8D=E5=8A=A1=20-=20=E5=AE=9E=E7=8E=B0Cr?= =?UTF-8?q?yptoService=E5=8A=A0=E5=AF=86=E6=9C=8D=E5=8A=A1=EF=BC=8C?= =?UTF-8?q?=E6=94=AF=E6=8C=81RSA-OAEP-2048=20+=20AES-256-GCM=E6=B7=B7?= =?UTF-8?q?=E5=90=88=E5=8A=A0=E5=AF=86=20-=20=E9=9B=86=E6=88=90=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E5=B1=82=E5=8A=A0=E5=AF=86=EF=BC=8C=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=8A=A0=E5=AF=86=E5=AD=98=E5=82=A8=E6=95=8F=E6=84=9F?= =?UTF-8?q?=E5=AD=97=E6=AE=B5(API=E5=AF=86=E9=92=A5=E3=80=81=E7=A7=81?= =?UTF-8?q?=E9=92=A5=E7=AD=89)=20-=20=E6=94=AF=E6=8C=81=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E5=8F=98=E9=87=8FDATA=5FENCRYPTION=5FKEY=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=8A=A0=E5=AF=86=E5=AF=86=E9=92=A5=20-=20?= =?UTF-8?q?=E9=80=82=E9=85=8DSQLite=E6=95=B0=E6=8D=AE=E5=BA=93=E5=8A=A0?= =?UTF-8?q?=E5=AF=86=E5=AD=98=E5=82=A8(=E4=BB=8EPostgreSQL=E7=A7=BB?= =?UTF-8?q?=E6=A4=8D)=20-=20=E4=BF=9D=E6=8C=81Hyperliquid=E4=BB=A3?= =?UTF-8?q?=E7=90=86=E9=92=B1=E5=8C=85=E5=A4=84=E7=90=86=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E6=80=A7=20-=20=E6=9B=B4=E6=96=B0.gitignore=E4=BB=A5=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE=E5=A4=84=E7=90=86crypto=E6=A8=A1=E5=9D=97=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=20=F0=9F=A4=96=20Generated=20with=20[Claude=20Code](h?= =?UTF-8?q?ttps://claude.ai/code)=20Co-Authored-By:=20tinkle-community=20=20*=20feat(scripts):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=8A=A0=E5=AF=86=E7=8E=AF=E5=A2=83=E4=B8=80=E9=94=AE=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E8=84=9A=E6=9C=AC=20-=20setup=5Fencryption.sh:=20?= =?UTF-8?q?=E4=B8=80=E9=94=AE=E7=94=9F=E6=88=90RSA=E5=AF=86=E9=92=A5?= =?UTF-8?q?=E5=AF=B9+=E6=95=B0=E6=8D=AE=E5=8A=A0=E5=AF=86=E5=AF=86?= =?UTF-8?q?=E9=92=A5+JWT=E5=AF=86=E9=92=A5=20-=20generate=5Frsa=5Fkeys.sh:?= =?UTF-8?q?=20=E4=B8=93=E4=B8=9A=E7=9A=84RSA-2048=E5=AF=86=E9=92=A5?= =?UTF-8?q?=E5=AF=B9=E7=94=9F=E6=88=90=E5=B7=A5=E5=85=B7=20-=20generate=5F?= =?UTF-8?q?data=5Fkey.sh:=20=E7=94=9F=E6=88=90AES-256=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=8A=A0=E5=AF=86=E5=AF=86=E9=92=A5=E5=92=8CJWT=E8=AE=A4?= =?UTF-8?q?=E8=AF=81=E5=AF=86=E9=92=A5=20-=20ENCRYPTION=5FREADME.md:=20?= =?UTF-8?q?=E8=AF=A6=E7=BB=86=E7=9A=84=E5=8A=A0=E5=AF=86=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E8=AF=B4=E6=98=8E=E6=96=87=E6=A1=A3=20-=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E6=A3=80=E6=B5=8B=E7=8E=B0=E6=9C=89=E5=AF=86?= =?UTF-8?q?=E9=92=A5=E5=B9=B6=E5=8F=AA=E7=94=9F=E6=88=90=E7=BC=BA=E5=A4=B1?= =?UTF-8?q?=E7=9A=84=E5=AF=86=E9=92=A5=20-=20=E5=AE=8C=E5=96=84=E7=9A=84?= =?UTF-8?q?=E6=9D=83=E9=99=90=E7=AE=A1=E7=90=86=E5=92=8C=E5=AE=89=E5=85=A8?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=20-=20=E5=85=BC=E5=AE=B9macOS=E5=92=8CLinux?= =?UTF-8?q?=E7=9A=84=E8=B7=A8=E5=B9=B3=E5=8F=B0=E6=94=AF=E6=8C=81=20?= =?UTF-8?q?=F0=9F=A4=96=20Generated=20with=20[Claude=20Code](https://claud?= =?UTF-8?q?e.ai/code)=20Co-Authored-By:=20tinkle-community=20=20*=20feat(api):=20=E6=B7=BB=E5=8A=A0=E5=8A=A0?= =?UTF-8?q?=E5=AF=86API=E7=AB=AF=E7=82=B9=E5=92=8CGin=E6=A1=86=E6=9E=B6?= =?UTF-8?q?=E9=9B=86=E6=88=90=20-=20=E6=96=B0=E5=A2=9ECryptoHandler?= =?UTF-8?q?=E5=A4=84=E7=90=86=E5=8A=A0=E5=AF=86=E7=9B=B8=E5=85=B3API?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=20-=20=E6=8F=90=E4=BE=9B/api/crypto/public-k?= =?UTF-8?q?ey=E7=AB=AF=E7=82=B9=E8=8E=B7=E5=8F=96RSA=E5=85=AC=E9=92=A5=20-?= =?UTF-8?q?=20=E6=8F=90=E4=BE=9B/api/crypto/decrypt=E7=AB=AF=E7=82=B9?= =?UTF-8?q?=E8=A7=A3=E5=AF=86=E6=95=8F=E6=84=9F=E6=95=B0=E6=8D=AE=20-=20?= =?UTF-8?q?=E9=80=82=E9=85=8DGin=E6=A1=86=E6=9E=B6=E7=9A=84HTTP=E5=A4=84?= =?UTF-8?q?=E7=90=86=E5=99=A8=E6=A0=BC=E5=BC=8F=20-=20=E9=9B=86=E6=88=90Cr?= =?UTF-8?q?yptoService=E5=88=B0API=E6=9C=8D=E5=8A=A1=E5=99=A8=20-=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=89=8D=E7=AB=AF=E5=8A=A0=E5=AF=86=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E4=BC=A0=E8=BE=93=E5=92=8C=E8=A7=A3=E5=AF=86=20?= =?UTF-8?q?=F0=9F=A4=96=20Generated=20with=20[Claude=20Code](https://claud?= =?UTF-8?q?e.ai/code)=20Co-Authored-By:=20tinkle-community=20=20*=20feat(web):=20=E6=B7=BB=E5=8A=A0=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E5=8A=A0=E5=AF=86=E6=9C=8D=E5=8A=A1=E5=92=8C=E4=B8=A4?= =?UTF-8?q?=E9=98=B6=E6=AE=B5=E5=AF=86=E9=92=A5=E8=BE=93=E5=85=A5=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=20-=20CryptoService:=20Web=20Crypto=20API=E9=9B=86?= =?UTF-8?q?=E6=88=90=EF=BC=8C=E6=94=AF=E6=8C=81RSA-OAEP=E5=8A=A0=E5=AF=86?= =?UTF-8?q?=20-=20TwoStageKeyModal:=20=E5=AE=89=E5=85=A8=E7=9A=84=E4=B8=A4?= =?UTF-8?q?=E9=98=B6=E6=AE=B5=E7=A7=81=E9=92=A5=E8=BE=93=E5=85=A5=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=EF=BC=8C=E6=94=AF=E6=8C=81=E5=89=AA=E8=B4=B4=E6=9D=BF?= =?UTF-8?q?=E6=B7=B7=E6=B7=86=20-=20=E5=AE=8C=E5=96=84=E5=9B=BD=E9=99=85?= =?UTF-8?q?=E5=8C=96=E7=BF=BB=E8=AF=91=E6=94=AF=E6=8C=81=E5=8A=A0=E5=AF=86?= =?UTF-8?q?=E7=9B=B8=E5=85=B3UI=E6=96=87=E6=9C=AC=20-=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?TypeScript=E7=B1=BB=E5=9E=8B=E9=94=99=E8=AF=AF=E5=92=8C?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E9=97=AE=E9=A2=98=20-=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=89=8D=E7=AB=AF=E6=95=8F=E6=84=9F=E6=95=B0=E6=8D=AE=E5=8A=A0?= =?UTF-8?q?=E5=AF=86=E4=BC=A0=E8=BE=93=E5=88=B0=E5=90=8E=E7=AB=AF=20-=20?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E7=94=A8=E6=88=B7=E9=9A=90=E7=A7=81=E4=BF=9D?= =?UTF-8?q?=E6=8A=A4=E5=92=8C=E6=95=B0=E6=8D=AE=E5=AE=89=E5=85=A8=20?= =?UTF-8?q?=F0=9F=A4=96=20Generated=20with=20[Claude=20Code](https://claud?= =?UTF-8?q?e.ai/code)=20Co-Authored-By:=20tinkle-community=20=20*=20feat(auth):=20=E5=A2=9E=E5=BC=BAJWT=E8=AE=A4?= =?UTF-8?q?=E8=AF=81=E5=AE=89=E5=85=A8=E6=80=A7=20-=20=E4=BC=98=E5=85=88?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8FJWT=5FSEC?= =?UTF-8?q?RET=E8=80=8C=E4=B8=8D=E6=98=AF=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=20-=20=E6=94=AF=E6=8C=81=E9=80=9A=E8=BF=87.e?= =?UTF-8?q?nv=E6=96=87=E4=BB=B6=E5=AE=89=E5=85=A8=E9=85=8D=E7=BD=AEJWT?= =?UTF-8?q?=E8=AE=A4=E8=AF=81=E5=AF=86=E9=92=A5=20-=20=E4=BF=9D=E7=95=99?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E9=85=8D=E7=BD=AE=E4=BD=9C=E4=B8=BA?= =?UTF-8?q?=E5=9B=9E=E9=80=80=E6=9C=BA=E5=88=B6=20-=20=E6=94=B9=E8=BF=9BJW?= =?UTF-8?q?T=E5=AF=86=E9=92=A5=E6=9D=A5=E6=BA=90=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=20-=20=E5=A2=9E=E5=BC=BA=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=E6=97=B6=E7=9A=84=E5=AE=89=E5=85=A8=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=A3=80=E6=9F=A5=20-=20=E6=94=AF=E6=8C=81=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E6=97=B6=E5=8A=A8=E6=80=81JWT=E5=AF=86=E9=92=A5?= =?UTF-8?q?=E5=88=87=E6=8D=A2=20=F0=9F=A4=96=20Generated=20with=20[Claude?= =?UTF-8?q?=20Code](https://claude.ai/code)=20Co-Authored-By:=20tinkle-com?= =?UTF-8?q?munity=20=20*=20feat(docker):=20=E9=9B=86?= =?UTF-8?q?=E6=88=90=E5=8A=A0=E5=AF=86=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E5=88=B0Docker=E9=83=A8=E7=BD=B2=20-=20=E6=B7=BB=E5=8A=A0DATA?= =?UTF-8?q?=5FENCRYPTION=5FKEY=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E4=BC=A0=E9=80=92=E5=88=B0=E5=AE=B9=E5=99=A8=20-=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0JWT=5FSECRET=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E6=94=AF=E6=8C=81=20-=20=E6=8C=82=E8=BD=BDsecrets=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E4=BD=BF=E5=AE=B9=E5=99=A8=E5=8F=AF=E8=AE=BF=E9=97=AE?= =?UTF-8?q?RSA=E5=AF=86=E9=92=A5=E6=96=87=E4=BB=B6=20-=20=E7=A1=AE?= =?UTF-8?q?=E4=BF=9D=E5=AE=B9=E5=99=A8=E5=86=85=E5=8A=A0=E5=AF=86=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E6=AD=A3=E5=B8=B8=E5=B7=A5=E4=BD=9C=20-=20=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E5=AE=B9=E5=99=A8=E5=90=AF=E5=8A=A8=E5=A4=B1=E8=B4=A5?= =?UTF-8?q?=E5=92=8C=E5=8A=A0=E5=AF=86=E5=88=9D=E5=A7=8B=E5=8C=96=E9=97=AE?= =?UTF-8?q?=E9=A2=98=20-=20=E5=AE=8C=E5=96=84Docker=20Compose=E5=8A=A0?= =?UTF-8?q?=E5=AF=86=E7=8E=AF=E5=A2=83=E9=85=8D=E7=BD=AE=20=F0=9F=A4=96=20?= =?UTF-8?q?Generated=20with=20[Claude=20Code](https://claude.ai/code)=20Co?= =?UTF-8?q?-Authored-By:=20tinkle-community=20=20*?= =?UTF-8?q?=20feat(start):=20=E9=9B=86=E6=88=90=E8=87=AA=E5=8A=A8=E5=8A=A0?= =?UTF-8?q?=E5=AF=86=E7=8E=AF=E5=A2=83=E6=A3=80=E6=B5=8B=E5=92=8C=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=20-=20=E5=A2=9E=E5=BC=BAcheck=5Fencryption()=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E6=A3=80=E6=B5=8BJWT=5FSECRET=E5=92=8CDATA=5FENCRYPTI?= =?UTF-8?q?ON=5FKEY=20-=20=E8=87=AA=E5=8A=A8=E8=BF=90=E8=A1=8Csetup=5Fencr?= =?UTF-8?q?yption.sh=E5=BD=93=E6=A3=80=E6=B5=8B=E5=88=B0=E7=BC=BA=E5=A4=B1?= =?UTF-8?q?=E5=AF=86=E9=92=A5=E6=97=B6=20-=20=E6=94=B9=E8=BF=9B=E5=8A=A0?= =?UTF-8?q?=E5=AF=86=E7=8A=B6=E6=80=81=E6=98=BE=E7=A4=BA=EF=BC=8C=E5=8C=85?= =?UTF-8?q?=E5=90=ABRSA+AES+JWT=E5=85=A8=E5=A5=97=E5=8A=A0=E5=AF=86?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=20-=20=E4=BC=98=E5=8C=96=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E4=BD=93=E9=AA=8C=EF=BC=8C=E6=8F=90=E4=BE=9B=E6=B8=85=E6=99=B0?= =?UTF-8?q?=E7=9A=84=E5=8A=A0=E5=AF=86=E9=85=8D=E7=BD=AE=E5=8F=8D=E9=A6=88?= =?UTF-8?q?=20-=20=E6=94=AF=E6=8C=81=E4=B8=80=E9=94=AE=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E5=AE=8C=E6=95=B4=E5=8A=A0=E5=AF=86=E7=8E=AF=E5=A2=83=20-=20?= =?UTF-8?q?=E7=A1=AE=E4=BF=9D=E5=AE=B9=E5=99=A8=E5=90=AF=E5=8A=A8=E5=89=8D?= =?UTF-8?q?=E5=8A=A0=E5=AF=86=E7=8E=AF=E5=A2=83=E5=B0=B1=E7=BB=AA=20?= =?UTF-8?q?=F0=9F=A4=96=20Generated=20with=20[Claude=20Code](https://claud?= =?UTF-8?q?e.ai/code)=20Co-Authored-By:=20tinkle-community=20=20*=20feat:=20format=20fix=20*=20fix(security):=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=89=8D=E7=AB=AF=E6=A8=A1=E5=9E=8B=E5=92=8C?= =?UTF-8?q?=E4=BA=A4=E6=98=93=E6=89=80=E9=85=8D=E7=BD=AE=E6=95=8F=E6=84=9F?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=98=8E=E6=96=87=E4=BC=A0=E8=BE=93=20-=20?= =?UTF-8?q?=E5=9C=A8handleSaveModelConfig=E4=B8=AD=E5=AF=B9API=E5=AF=86?= =?UTF-8?q?=E9=92=A5=E8=BF=9B=E8=A1=8CRSA-OAEP=E5=8A=A0=E5=AF=86=20-=20?= =?UTF-8?q?=E5=9C=A8handleSaveExchangeConfig=E4=B8=AD=E5=AF=B9API=E5=AF=86?= =?UTF-8?q?=E9=92=A5=E3=80=81Secret=E5=AF=86=E9=92=A5=E5=92=8CAster?= =?UTF-8?q?=E7=A7=81=E9=92=A5=E8=BF=9B=E8=A1=8C=E5=8A=A0=E5=AF=86=20-=20?= =?UTF-8?q?=E5=8F=AA=E6=9C=89=E9=9D=9E=E7=A9=BA=E6=95=8F=E6=84=9F=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=89=8D=E8=BF=9B=E8=A1=8C=E5=8A=A0=E5=AF=86=E5=A4=84?= =?UTF-8?q?=E7=90=86=20-=20=E6=B7=BB=E5=8A=A0=E5=8A=A0=E5=AF=86=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86=E5=92=8C=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=8F=8B=E5=A5=BD=E6=8F=90=E7=A4=BA=20-=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0encryptionFailed=E7=BF=BB=E8=AF=91=E9=94=AE=E7=9A=84?= =?UTF-8?q?=E4=B8=AD=E8=8B=B1=E6=96=87=E6=94=AF=E6=8C=81=20-=20=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E7=94=A8=E6=88=B7ID=E5=92=8C=E4=BC=9A=E8=AF=9DID?= =?UTF-8?q?=E4=BD=9C=E4=B8=BA=E5=8A=A0=E5=AF=86=E4=B8=8A=E4=B8=8B=E6=96=87?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E5=AE=89=E5=85=A8=E6=80=A7=20=E8=BF=99?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E4=B9=8B=E5=89=8D=E6=95=8F=E6=84=9F?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=9C=A8=E7=BD=91=E7=BB=9C=E4=BC=A0=E8=BE=93?= =?UTF-8?q?=E4=B8=AD=E4=BB=A5=E6=98=8E=E6=96=87=E5=BD=A2=E5=BC=8F=E5=8F=91?= =?UTF-8?q?=E9=80=81=E7=9A=84=E5=AE=89=E5=85=A8=E6=BC=8F=E6=B4=9E=E3=80=82?= =?UTF-8?q?=20=F0=9F=A4=96=20Generated=20with=20[Claude=20Code](https://cl?= =?UTF-8?q?aude.ai/code)=20Co-Authored-By:=20tinkle-community=20=20*=20fix(crypto):=20=E4=BF=AE=E5=A4=8D=E5=90=8E?= =?UTF-8?q?=E7=AB=AF=E5=8A=A0=E5=AF=86=E6=9C=8D=E5=8A=A1=E9=9B=86=E6=88=90?= =?UTF-8?q?=E5=92=8C=E7=BC=BA=E5=A4=B1=E7=9A=84=E5=8A=A0=E5=AF=86=E7=AB=AF?= =?UTF-8?q?=E7=82=B9=20-=20=E6=B7=BB=E5=8A=A0Server=E7=BB=93=E6=9E=84?= =?UTF-8?q?=E4=BD=93=E7=BC=BA=E5=B0=91=E7=9A=84cryptoService=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=20-=20=E5=AE=9E=E7=8E=B0handleUpdateModelConfigsEncry?= =?UTF-8?q?pted=E5=A4=84=E7=90=86=E5=99=A8=E7=94=A8=E4=BA=8E=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E9=85=8D=E7=BD=AE=E5=8A=A0=E5=AF=86=E4=BC=A0=E8=BE=93?= =?UTF-8?q?=20-=20=E4=BF=AE=E5=A4=8DhandleUpdateExchangeConfigsEncrypted?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=87=BD=E6=95=B0=E8=B0=83=E7=94=A8=20-=20?= =?UTF-8?q?=E5=9C=A8=E5=89=8D=E7=AB=AFAPI=E4=B8=AD=E6=B7=BB=E5=8A=A0update?= =?UTF-8?q?ModelConfigsEncrypted=E6=96=B9=E6=B3=95=20-=20=E7=BB=9F?= =?UTF-8?q?=E4=B8=80RSA=E5=AF=86=E9=92=A5=E8=B7=AF=E5=BE=84=E4=BB=8Esecret?= =?UTF-8?q?s/rsa=5Fkey=E6=94=B9=E4=B8=BAkeys/rsa=5Fprivate.key=20-=20?= =?UTF-8?q?=E7=A1=AE=E4=BF=9D=E5=89=8D=E7=AB=AF=E5=8F=AF=E4=BB=A5=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E5=8A=A0=E5=AF=86=E7=AB=AF=E7=82=B9=E5=AE=89=E5=85=A8?= =?UTF-8?q?=E4=BC=A0=E8=BE=93=E6=95=8F=E6=84=9F=E6=95=B0=E6=8D=AE=20-=20?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=E5=8E=9F=E6=9C=89=E5=8A=A0=E5=AF=86=E9=80=9A?= =?UTF-8?q?=E4=BF=A1=E6=A8=A1=E5=BC=8F=E5=92=8C=E4=BA=8C=E6=AE=B5=E8=BE=93?= =?UTF-8?q?=E5=85=A5=E7=A7=81=E9=92=A5=E5=8A=9F=E8=83=BD=20=F0=9F=A4=96=20?= =?UTF-8?q?Generated=20with=20[Claude=20Code](https://claude.ai/code)=20Co?= =?UTF-8?q?-Authored-By:=20tinkle-community=20=20*?= =?UTF-8?q?=20fix(crypto):=20=E5=AE=8C=E5=96=84=E5=8A=A0=E5=AF=86=E7=AB=AF?= =?UTF-8?q?=E7=82=B9=E9=85=8D=E7=BD=AE=EF=BC=8C=E7=AE=80=E5=8C=96API?= =?UTF-8?q?=E7=BB=93=E6=9E=84=20-=20=E7=A7=BB=E9=99=A4=E5=A4=9A=E4=BD=99?= =?UTF-8?q?=E7=9A=84/models/encrypted=E7=AB=AF=E7=82=B9=EF=BC=8C=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E9=85=8D=E7=BD=AE=E6=9A=82=E4=B8=8D=E5=8A=A0=E5=AF=86?= =?UTF-8?q?=20-=20=E7=A1=AE=E8=AE=A4/exchanges=E7=AB=AF=E7=82=B9=E5=B7=B2?= =?UTF-8?q?=E5=BC=BA=E5=88=B6=E8=A6=81=E6=B1=82=E5=8A=A0=E5=AF=86=E4=BC=A0?= =?UTF-8?q?=E8=BE=93=20-=20=E7=BB=9F=E4=B8=80=E5=89=8D=E7=AB=AF=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E6=A0=87=E5=87=86=E7=AB=AF=E7=82=B9=EF=BC=8C=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E4=BD=BF=E7=94=A8=E5=8A=A0=E5=AF=86=E4=BC=A0=E8=BE=93?= =?UTF-8?q?=20-=20=E4=BF=AE=E5=A4=8D=E5=89=8D=E7=AB=AFAPI=E8=B0=83?= =?UTF-8?q?=E7=94=A8=EF=BC=8C=E7=A7=BB=E9=99=A4=E4=B8=8D=E5=AD=98=E5=9C=A8?= =?UTF-8?q?=E7=9A=84updateModelConfigsEncrypted=E5=BC=95=E7=94=A8=20-=20?= =?UTF-8?q?=E7=A1=AE=E4=BF=9D=E5=90=8E=E7=AB=AF=E5=92=8C=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E6=88=90=E5=8A=9F=EF=BC=8C=E5=8A=A0=E5=AF=86?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E6=AD=A3=E5=B8=B8=E5=B7=A5=E4=BD=9C=20?= =?UTF-8?q?=F0=9F=A4=96=20Generated=20with=20[Claude=20Code](https://claud?= =?UTF-8?q?e.ai/code)=20Co-Authored-By:=20tinkle-community=20=20*=20fix(crypto):=20=E4=B8=BA=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=AB=AF=E7=82=B9=E6=B7=BB=E5=8A=A0=E5=8A=A0?= =?UTF-8?q?=E5=AF=86=E4=BC=A0=E8=BE=93=E6=94=AF=E6=8C=81=20-=20=E5=89=8D?= =?UTF-8?q?=E7=AB=AFupdateModelConfigs=E6=96=B9=E6=B3=95=E7=8E=B0=E5=9C=A8?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E5=8A=A0=E5=AF=86=E4=BC=A0=E8=BE=93=20-=20?= =?UTF-8?q?=E5=90=8E=E7=AB=AF/api/models=E7=AB=AF=E7=82=B9=E5=B7=B2?= =?UTF-8?q?=E5=BC=BA=E5=88=B6=E8=A6=81=E6=B1=82=E5=8A=A0=E5=AF=86=E8=BD=BD?= =?UTF-8?q?=E8=8D=B7=20-=20=E6=A8=A1=E5=9E=8B=E9=85=8D=E7=BD=AE=E7=95=8C?= =?UTF-8?q?=E9=9D=A2=E4=BF=9D=E6=8C=81=E6=99=AE=E9=80=9A=E8=BE=93=E5=85=A5?= =?UTF-8?q?=EF=BC=8C=E5=9C=A8=E6=8F=90=E4=BA=A4=E6=97=B6=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=8A=A0=E5=AF=86=20-=20=E7=A1=AE=E4=BF=9DAPI=E5=AF=86?= =?UTF-8?q?=E9=92=A5=E7=AD=89=E6=95=8F=E6=84=9F=E6=95=B0=E6=8D=AE=E9=80=9A?= =?UTF-8?q?=E8=BF=87RSA+AES=E6=B7=B7=E5=90=88=E5=8A=A0=E5=AF=86=E4=BC=A0?= =?UTF-8?q?=E8=BE=93=20-=20=E5=89=8D=E7=AB=AF=E5=90=8E=E7=AB=AF=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E6=B5=8B=E8=AF=95=E9=80=9A=E8=BF=87=EF=BC=8C=E5=8A=A0?= =?UTF-8?q?=E5=AF=86=E5=8A=9F=E8=83=BD=E6=AD=A3=E5=B8=B8=E5=B7=A5=E4=BD=9C?= =?UTF-8?q?=20=F0=9F=A4=96=20Generated=20with=20[Claude=20Code](https://cl?= =?UTF-8?q?aude.ai/code)=20Co-Authored-By:=20tinkle-community=20=20---------=20Co-authored-by:=20icy=20=20Co-authored-by:=20tinkle-community=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/setup_encryption.sh | 127 +++++++++++++++++++-------- start.sh | 56 +++++++----- web/src/components/AITradersPage.tsx | 4 +- web/src/lib/api.ts | 16 +--- 4 files changed, 129 insertions(+), 74 deletions(-) diff --git a/scripts/setup_encryption.sh b/scripts/setup_encryption.sh index 35b22c87..506c7b95 100755 --- a/scripts/setup_encryption.sh +++ b/scripts/setup_encryption.sh @@ -58,16 +58,16 @@ echo -e " • 私钥文件: ${YELLOW}$PRIVATE_KEY_FILE${NC}" echo -e " • 公钥文件: ${YELLOW}$PUBLIC_KEY_FILE${NC}" echo -e " • AES密钥: ${YELLOW}256 bits (自动生成)${NC}" -# 显示必要性说明 +# 询问用户确认 echo -echo -e "${YELLOW}⚠️ 加密环境是系统运行的必需条件(不可跳过)${NC}" -echo -e "${BLUE}ℹ️ 将自动检查并生成以下密钥:${NC}" -echo -e " • RSA-2048 密钥对 (用于传输加密)" -echo -e " • AES-256 数据加密密钥 (用于数据库加密)" -echo -e " • JWT 认证密钥 (用于用户认证)" -echo -e "${BLUE}ℹ️ 如果密钥已存在,将保持现有密钥;如果缺失,将自动生成${NC}" +read -p "是否继续设置加密环境? [Y/n]: " -n 1 -r echo +if [[ $REPLY =~ ^[Nn]$ ]]; then + echo -e "${BLUE}ℹ️ 操作已取消${NC}" + exit 0 +fi +echo echo -e "${CYAN}🚀 开始设置加密环境...${NC}" # ============= 步骤1: 创建目录 ============= @@ -94,20 +94,20 @@ echo echo -e "${YELLOW}🔐 步骤 2/4: 生成 RSA-$RSA_KEY_SIZE 密钥对...${NC}" # 检查现有RSA密钥 -if [ -f "$PRIVATE_KEY_FILE" ] && [ -f "$PUBLIC_KEY_FILE" ]; then - echo -e "${BLUE}ℹ️ 检测到现有的RSA密钥文件,保持现有密钥${NC}" - # 验证现有密钥 - echo -e " ${CYAN}验证现有密钥对...${NC}" - if openssl rsa -in "$PRIVATE_KEY_FILE" -check -noout 2>/dev/null; then - echo -e "${GREEN} ✓ 现有密钥验证通过${NC}" - else - echo -e "${RED} ❌ 现有密钥验证失败,将重新生成${NC}" +if [ -f "$PRIVATE_KEY_FILE" ] || [ -f "$PUBLIC_KEY_FILE" ]; then + echo -e "${YELLOW}⚠️ 检测到现有的RSA密钥文件${NC}" + read -p "是否重新生成RSA密钥? [y/N]: " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then rm -f "$PRIVATE_KEY_FILE" "$PUBLIC_KEY_FILE" + echo -e "${YELLOW}🗑️ 删除旧密钥${NC}" + else + echo -e "${BLUE}ℹ️ 保持现有RSA密钥${NC}" + RSA_SKIPPED=true fi fi -# 如果密钥不存在或验证失败,生成新密钥 -if [ ! -f "$PRIVATE_KEY_FILE" ] || [ ! -f "$PUBLIC_KEY_FILE" ]; then +if [ "$RSA_SKIPPED" != "true" ]; then # 生成私钥 echo -e " ${CYAN}生成RSA私钥...${NC}" openssl genrsa -out "$PRIVATE_KEY_FILE" $RSA_KEY_SIZE 2>/dev/null @@ -143,33 +143,88 @@ if [ -f ".env" ]; then fi fi -# 确保 .env 文件存在 -if [ ! -f ".env" ]; then - touch .env +if [ "$DATA_KEY_EXISTS" = "true" ] || [ "$JWT_KEY_EXISTS" = "true" ]; then + echo -e "${YELLOW}⚠️ 检测到现有的密钥配置${NC}" + if [ "$DATA_KEY_EXISTS" = "true" ]; then + echo -e " • 数据加密密钥已存在" + fi + if [ "$JWT_KEY_EXISTS" = "true" ]; then + echo -e " • JWT认证密钥已存在" + fi + read -p "是否重新生成所有密钥? [y/N]: " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo -e "${BLUE}ℹ️ 保持现有密钥${NC}" + KEY_SKIPPED=true + # 读取现有密钥 + if [ "$DATA_KEY_EXISTS" = "true" ]; then + DATA_KEY=$(grep "^DATA_ENCRYPTION_KEY=" .env | cut -d'=' -f2) + fi + if [ "$JWT_KEY_EXISTS" = "true" ]; then + JWT_KEY=$(grep "^JWT_SECRET=" .env | cut -d'=' -f2) + fi + fi fi -# 生成缺失的密钥(必需,不允许跳过) -if [ "$DATA_KEY_EXISTS" != "true" ]; then +if [ "$KEY_SKIPPED" != "true" ]; then + # 生成新的密钥 echo -e " ${CYAN}生成AES-256数据加密密钥...${NC}" - DATA_KEY=$(openssl rand -base64 32 | tr -d '\n') - echo "DATA_ENCRYPTION_KEY=$DATA_KEY" >> .env + DATA_KEY=$(openssl rand -base64 32) echo -e "${GREEN} ✓ 数据加密密钥生成完成${NC}" -else - echo -e "${BLUE} ℹ️ 数据加密密钥已存在,保持现有密钥${NC}" -fi - -if [ "$JWT_KEY_EXISTS" != "true" ]; then + echo -e " ${CYAN}生成JWT认证密钥...${NC}" - JWT_KEY=$(openssl rand -base64 64 | tr -d '\n') - echo "JWT_SECRET=$JWT_KEY" >> .env + JWT_KEY=$(openssl rand -base64 64) echo -e "${GREEN} ✓ JWT认证密钥生成完成${NC}" -else - echo -e "${BLUE} ℹ️ JWT认证密钥已存在,保持现有密钥${NC}" + + # 保存到.env文件 + if [ -f ".env" ]; then + # 更新现有文件 + if grep -q "^DATA_ENCRYPTION_KEY=" .env; then + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "s/^DATA_ENCRYPTION_KEY=.*/DATA_ENCRYPTION_KEY=$DATA_KEY/" .env + else + sed -i "s/^DATA_ENCRYPTION_KEY=.*/DATA_ENCRYPTION_KEY=$DATA_KEY/" .env + fi + else + echo "DATA_ENCRYPTION_KEY=$DATA_KEY" >> .env + fi + + if grep -q "^JWT_SECRET=" .env; then + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "s/^JWT_SECRET=.*/JWT_SECRET=$JWT_KEY/" .env + else + sed -i "s/^JWT_SECRET=.*/JWT_SECRET=$JWT_KEY/" .env + fi + else + echo "JWT_SECRET=$JWT_KEY" >> .env + fi + else + # 创建新文件 + echo "DATA_ENCRYPTION_KEY=$DATA_KEY" > .env + echo "JWT_SECRET=$JWT_KEY" >> .env + fi + chmod 600 .env + echo -e "${GREEN} ✓ 密钥已保存到 .env 文件${NC}" +elif [ "$DATA_KEY_EXISTS" != "true" ] || [ "$JWT_KEY_EXISTS" != "true" ]; then + # 生成缺失的密钥 + if [ "$DATA_KEY_EXISTS" != "true" ]; then + echo -e " ${CYAN}生成缺失的AES-256数据加密密钥...${NC}" + DATA_KEY=$(openssl rand -base64 32) + echo "DATA_ENCRYPTION_KEY=$DATA_KEY" >> .env + echo -e "${GREEN} ✓ 数据加密密钥生成完成${NC}" + fi + + if [ "$JWT_KEY_EXISTS" != "true" ]; then + echo -e " ${CYAN}生成缺失的JWT认证密钥...${NC}" + JWT_KEY=$(openssl rand -base64 64) + echo "JWT_SECRET=$JWT_KEY" >> .env + echo -e "${GREEN} ✓ JWT认证密钥生成完成${NC}" + fi + + chmod 600 .env + echo -e "${GREEN} ✓ 密钥已保存到 .env 文件${NC}" fi -chmod 600 .env -echo -e "${GREEN} ✓ 密钥配置已保存到 .env 文件${NC}" - # ============= 步骤4: 验证和总结 ============= echo echo -e "${YELLOW}✅ 步骤 4/4: 环境验证和总结...${NC}" diff --git a/start.sh b/start.sh index ef59b772..2f7eb452 100755 --- a/start.sh +++ b/start.sh @@ -104,37 +104,47 @@ check_encryption() { # 如果需要设置加密环境 if [ "$need_setup" = "true" ]; then - print_info "🔐 需要设置加密环境(必需)" + print_info "🔐 需要设置加密环境" print_info "加密环境用于保护敏感数据(API密钥、私钥等)" - print_info "系统将自动配置加密环境..." echo "" - - # 检查加密设置脚本是否存在 - if [ -f "scripts/setup_encryption.sh" ]; then - print_info "正在自动设置加密环境..." - print_info "加密系统将保护: API密钥、私钥、Hyperliquid代理钱包" - echo "" - - # 自动运行加密设置脚本 - # n: 保持现有RSA密钥(如果存在)| n: 保持现有数据密钥(如果存在) - echo -e "n\nn" | bash scripts/setup_encryption.sh - if [ $? -eq 0 ]; then - echo "" - print_success "🔐 加密环境设置完成!" - print_info " • RSA-2048密钥对已生成" - print_info " • AES-256数据加密密钥已配置" - print_info " • JWT认证密钥已配置" - print_info " • 所有敏感数据现在都受加密保护" + + # 询问用户是否自动设置 + read -p "是否自动设置加密环境?[Y/n]: " auto_setup + auto_setup=${auto_setup:-Y} + + if [[ "$auto_setup" =~ ^[Yy]$ ]]; then + print_info "正在设置加密环境..." + + # 检查加密设置脚本是否存在 + if [ -f "scripts/setup_encryption.sh" ]; then + print_info "正在自动设置加密环境..." + print_info "加密系统将保护: API密钥、私钥、Hyperliquid代理钱包" echo "" + + # 自动运行加密设置脚本 + # Y: 继续设置加密环境 | n: 保持现有RSA密钥 | n: 保持现有密钥配置 + echo -e "Y\nn\nn" | bash scripts/setup_encryption.sh + if [ $? -eq 0 ]; then + echo "" + print_success "🔐 加密环境设置完成!" + print_info " • RSA-2048密钥对已生成" + print_info " • AES-256数据加密密钥已配置" + print_info " • JWT认证密钥已配置" + print_info " • 所有敏感数据现在都受加密保护" + echo "" + else + print_error "加密环境设置失败" + exit 1 + fi else - print_error "加密环境设置失败" + print_error "加密设置脚本不存在: scripts/setup_encryption.sh" print_info "请手动运行: ./scripts/setup_encryption.sh" exit 1 fi else - print_error "加密设置脚本不存在: scripts/setup_encryption.sh" - print_info "请手动运行: ./scripts/setup_encryption.sh" - exit 1 + print_warning "跳过加密环境设置" + print_info "手动设置命令: ./scripts/setup_encryption.sh" + print_info "系统将使用未加密模式运行(不推荐)" fi else print_success "🔐 加密环境已配置" diff --git a/web/src/components/AITradersPage.tsx b/web/src/components/AITradersPage.tsx index 1e55bc9a..322d66b3 100644 --- a/web/src/components/AITradersPage.tsx +++ b/web/src/components/AITradersPage.tsx @@ -415,7 +415,7 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { ]) ), }), - updateApi: api.updateModelConfigsEncrypted, + updateApi: api.updateModelConfigs, refreshApi: api.getModelConfigs, setItems: (items) => { // 使用函数式更新确保状态正确更新 @@ -488,7 +488,7 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { ), } - await api.updateModelConfigsEncrypted(request) + await api.updateModelConfigs(request) // 重新获取用户配置以确保数据同步 const refreshedModels = await api.getModelConfigs() diff --git a/web/src/lib/api.ts b/web/src/lib/api.ts index 0bd79d8f..3d3eda69 100644 --- a/web/src/lib/api.ts +++ b/web/src/lib/api.ts @@ -131,18 +131,6 @@ export const api = { }, async updateModelConfigs(request: UpdateModelConfigRequest): Promise { - const res = await fetch(`${API_BASE}/models`, { - method: 'PUT', - headers: getAuthHeaders(), - body: JSON.stringify(request), - }) - if (!res.ok) throw new Error('更新模型配置失败') - }, - - // 使用加密传输更新模型配置 - async updateModelConfigsEncrypted( - request: UpdateModelConfigRequest - ): Promise { // 获取RSA公钥 const publicKey = await CryptoService.fetchPublicKey() @@ -160,6 +148,7 @@ export const api = { sessionId ) + // 发送加密数据 const res = await fetch(`${API_BASE}/models`, { method: 'PUT', headers: getAuthHeaders(), @@ -168,6 +157,7 @@ export const api = { if (!res.ok) throw new Error('更新模型配置失败') }, + // 交易所配置接口 async getExchangeConfigs(): Promise { const res = await fetch(`${API_BASE}/exchanges`, { @@ -216,7 +206,7 @@ export const api = { sessionId ) - // 发送加密数据到普通端点 + // 发送加密数据 const res = await fetch(`${API_BASE}/exchanges`, { method: 'PUT', headers: getAuthHeaders(),