mirror of
https://github.com/SECTL/SecScore.git
synced 2026-07-19 12:34:22 +08:00
fix: 修复登录持久化问题
删除了json-rules-engine
This commit is contained in:
@@ -26,7 +26,6 @@
|
|||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dayjs": "^1.11.20",
|
"dayjs": "^1.11.20",
|
||||||
"i18next": "^25.8.14",
|
"i18next": "^25.8.14",
|
||||||
"json-rules-engine": "^7.3.1",
|
|
||||||
"pinyin-pro": "^3.27.0",
|
"pinyin-pro": "^3.27.0",
|
||||||
"react": "^19.2.1",
|
"react": "^19.2.1",
|
||||||
"react-dom": "^19.2.1",
|
"react-dom": "^19.2.1",
|
||||||
|
|||||||
Generated
+18
-61
@@ -35,9 +35,6 @@ importers:
|
|||||||
i18next:
|
i18next:
|
||||||
specifier: ^25.8.14
|
specifier: ^25.8.14
|
||||||
version: 25.8.18(typescript@5.9.3)
|
version: 25.8.18(typescript@5.9.3)
|
||||||
json-rules-engine:
|
|
||||||
specifier: ^7.3.1
|
|
||||||
version: 7.3.1
|
|
||||||
pinyin-pro:
|
pinyin-pro:
|
||||||
specifier: ^3.27.0
|
specifier: ^3.27.0
|
||||||
version: 3.28.0
|
version: 3.28.0
|
||||||
@@ -462,18 +459,6 @@ packages:
|
|||||||
'@jridgewell/trace-mapping@0.3.31':
|
'@jridgewell/trace-mapping@0.3.31':
|
||||||
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
||||||
|
|
||||||
'@jsep-plugin/assignment@1.3.0':
|
|
||||||
resolution: {integrity: sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==}
|
|
||||||
engines: {node: '>= 10.16.0'}
|
|
||||||
peerDependencies:
|
|
||||||
jsep: ^0.4.0||^1.0.0
|
|
||||||
|
|
||||||
'@jsep-plugin/regex@1.0.4':
|
|
||||||
resolution: {integrity: sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==}
|
|
||||||
engines: {node: '>= 10.16.0'}
|
|
||||||
peerDependencies:
|
|
||||||
jsep: ^0.4.0||^1.0.0
|
|
||||||
|
|
||||||
'@rc-component/async-validator@5.1.0':
|
'@rc-component/async-validator@5.1.0':
|
||||||
resolution: {integrity: sha512-n4HcR5siNUXRX23nDizbZBQPO0ZM/5oTtmKZ6/eqL0L2bo747cklFdZGRN2f+c9qWGICwDzrhW0H7tE9PptdcA==}
|
resolution: {integrity: sha512-n4HcR5siNUXRX23nDizbZBQPO0ZM/5oTtmKZ6/eqL0L2bo747cklFdZGRN2f+c9qWGICwDzrhW0H7tE9PptdcA==}
|
||||||
engines: {node: '>=14.x'}
|
engines: {node: '>=14.x'}
|
||||||
@@ -854,66 +839,79 @@ packages:
|
|||||||
resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==}
|
resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm-musleabihf@4.59.0':
|
'@rollup/rollup-linux-arm-musleabihf@4.59.0':
|
||||||
resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==}
|
resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-gnu@4.59.0':
|
'@rollup/rollup-linux-arm64-gnu@4.59.0':
|
||||||
resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==}
|
resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-musl@4.59.0':
|
'@rollup/rollup-linux-arm64-musl@4.59.0':
|
||||||
resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==}
|
resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-linux-loong64-gnu@4.59.0':
|
'@rollup/rollup-linux-loong64-gnu@4.59.0':
|
||||||
resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==}
|
resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==}
|
||||||
cpu: [loong64]
|
cpu: [loong64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-loong64-musl@4.59.0':
|
'@rollup/rollup-linux-loong64-musl@4.59.0':
|
||||||
resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==}
|
resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==}
|
||||||
cpu: [loong64]
|
cpu: [loong64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-linux-ppc64-gnu@4.59.0':
|
'@rollup/rollup-linux-ppc64-gnu@4.59.0':
|
||||||
resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==}
|
resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-ppc64-musl@4.59.0':
|
'@rollup/rollup-linux-ppc64-musl@4.59.0':
|
||||||
resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==}
|
resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-gnu@4.59.0':
|
'@rollup/rollup-linux-riscv64-gnu@4.59.0':
|
||||||
resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==}
|
resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-musl@4.59.0':
|
'@rollup/rollup-linux-riscv64-musl@4.59.0':
|
||||||
resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==}
|
resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-linux-s390x-gnu@4.59.0':
|
'@rollup/rollup-linux-s390x-gnu@4.59.0':
|
||||||
resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==}
|
resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-gnu@4.59.0':
|
'@rollup/rollup-linux-x64-gnu@4.59.0':
|
||||||
resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==}
|
resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-musl@4.59.0':
|
'@rollup/rollup-linux-x64-musl@4.59.0':
|
||||||
resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==}
|
resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-openbsd-x64@4.59.0':
|
'@rollup/rollup-openbsd-x64@4.59.0':
|
||||||
resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==}
|
resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==}
|
||||||
@@ -977,30 +975,35 @@ packages:
|
|||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@tauri-apps/cli-linux-arm64-musl@2.10.1':
|
'@tauri-apps/cli-linux-arm64-musl@2.10.1':
|
||||||
resolution: {integrity: sha512-MIj78PDDGjkg3NqGptDOGgfXks7SYJwhiMh8SBoZS+vfdz7yP5jN18bNaLnDhsVIPARcAhE1TlsZe/8Yxo2zqg==}
|
resolution: {integrity: sha512-MIj78PDDGjkg3NqGptDOGgfXks7SYJwhiMh8SBoZS+vfdz7yP5jN18bNaLnDhsVIPARcAhE1TlsZe/8Yxo2zqg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@tauri-apps/cli-linux-riscv64-gnu@2.10.1':
|
'@tauri-apps/cli-linux-riscv64-gnu@2.10.1':
|
||||||
resolution: {integrity: sha512-X0lvOVUg8PCVaoEtEAnpxmnkwlE1gcMDTqfhbefICKDnOTJ5Est3qL0SrWxizDackIOKBcvtpejrSiVpuJI1kw==}
|
resolution: {integrity: sha512-X0lvOVUg8PCVaoEtEAnpxmnkwlE1gcMDTqfhbefICKDnOTJ5Est3qL0SrWxizDackIOKBcvtpejrSiVpuJI1kw==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@tauri-apps/cli-linux-x64-gnu@2.10.1':
|
'@tauri-apps/cli-linux-x64-gnu@2.10.1':
|
||||||
resolution: {integrity: sha512-2/12bEzsJS9fAKybxgicCDFxYD1WEI9kO+tlDwX5znWG2GwMBaiWcmhGlZ8fi+DMe9CXlcVarMTYc0L3REIRxw==}
|
resolution: {integrity: sha512-2/12bEzsJS9fAKybxgicCDFxYD1WEI9kO+tlDwX5znWG2GwMBaiWcmhGlZ8fi+DMe9CXlcVarMTYc0L3REIRxw==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@tauri-apps/cli-linux-x64-musl@2.10.1':
|
'@tauri-apps/cli-linux-x64-musl@2.10.1':
|
||||||
resolution: {integrity: sha512-Y8J0ZzswPz50UcGOFuXGEMrxbjwKSPgXftx5qnkuMs2rmwQB5ssvLb6tn54wDSYxe7S6vlLob9vt0VKuNOaCIQ==}
|
resolution: {integrity: sha512-Y8J0ZzswPz50UcGOFuXGEMrxbjwKSPgXftx5qnkuMs2rmwQB5ssvLb6tn54wDSYxe7S6vlLob9vt0VKuNOaCIQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@tauri-apps/cli-win32-arm64-msvc@2.10.1':
|
'@tauri-apps/cli-win32-arm64-msvc@2.10.1':
|
||||||
resolution: {integrity: sha512-iSt5B86jHYAPJa/IlYw++SXtFPGnWtFJriHn7X0NFBVunF6zu9+/zOn8OgqIWSl8RgzhLGXQEEtGBdR4wzpVgg==}
|
resolution: {integrity: sha512-iSt5B86jHYAPJa/IlYw++SXtFPGnWtFJriHn7X0NFBVunF6zu9+/zOn8OgqIWSl8RgzhLGXQEEtGBdR4wzpVgg==}
|
||||||
@@ -1477,9 +1480,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
eventemitter2@6.4.9:
|
|
||||||
resolution: {integrity: sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==}
|
|
||||||
|
|
||||||
fast-deep-equal@3.1.3:
|
fast-deep-equal@3.1.3:
|
||||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||||
|
|
||||||
@@ -1595,9 +1595,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
|
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
hash-it@6.0.1:
|
|
||||||
resolution: {integrity: sha512-qhl8+l4Zwi1eLlL3lja5ywmDQnBzLEJxd0QJoAVIgZpgQbdtVZrN5ypB0y3VHwBlvAalpcbM2/A6x7oUks5zNg==}
|
|
||||||
|
|
||||||
hasown@2.0.2:
|
hasown@2.0.2:
|
||||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -1767,10 +1764,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
|
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
jsep@1.4.0:
|
|
||||||
resolution: {integrity: sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==}
|
|
||||||
engines: {node: '>= 10.16.0'}
|
|
||||||
|
|
||||||
jsesc@3.1.0:
|
jsesc@3.1.0:
|
||||||
resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
|
resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -1785,10 +1778,6 @@ packages:
|
|||||||
json-logic-js@2.0.5:
|
json-logic-js@2.0.5:
|
||||||
resolution: {integrity: sha512-rTT2+lqcuUmj4DgWfmzupZqQDA64AdmYqizzMPWj3DxGdfFNsxPpcNVSaTj4l8W2tG/+hg7/mQhxjU3aPacO6g==}
|
resolution: {integrity: sha512-rTT2+lqcuUmj4DgWfmzupZqQDA64AdmYqizzMPWj3DxGdfFNsxPpcNVSaTj4l8W2tG/+hg7/mQhxjU3aPacO6g==}
|
||||||
|
|
||||||
json-rules-engine@7.3.1:
|
|
||||||
resolution: {integrity: sha512-NyRTQZllvAt7AQ3g9P7/t4nIwlEB+EyZV7y8/WgXfZWSlpcDryt1UH9CsoU+Z+MDvj8umN9qqEcbE6qnk9JAHw==}
|
|
||||||
engines: {node: '>=18.0.0'}
|
|
||||||
|
|
||||||
json-schema-traverse@0.4.1:
|
json-schema-traverse@0.4.1:
|
||||||
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
|
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
|
||||||
|
|
||||||
@@ -1803,11 +1792,6 @@ packages:
|
|||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
jsonpath-plus@10.4.0:
|
|
||||||
resolution: {integrity: sha512-T92WWatJXmhBbKsgH/0hl+jxjdXrifi5IKeMY02DWggRxX0UElcbVzPlmgLTbvsPeW1PasQ6xE2Q75stkhGbsA==}
|
|
||||||
engines: {node: '>=18.0.0'}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
jsx-ast-utils@3.3.5:
|
jsx-ast-utils@3.3.5:
|
||||||
resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
|
resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
|
||||||
engines: {node: '>=4.0'}
|
engines: {node: '>=4.0'}
|
||||||
@@ -2745,14 +2729,6 @@ snapshots:
|
|||||||
'@jridgewell/resolve-uri': 3.1.2
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
'@jsep-plugin/assignment@1.3.0(jsep@1.4.0)':
|
|
||||||
dependencies:
|
|
||||||
jsep: 1.4.0
|
|
||||||
|
|
||||||
'@jsep-plugin/regex@1.0.4(jsep@1.4.0)':
|
|
||||||
dependencies:
|
|
||||||
jsep: 1.4.0
|
|
||||||
|
|
||||||
'@rc-component/async-validator@5.1.0':
|
'@rc-component/async-validator@5.1.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.28.6
|
'@babel/runtime': 7.28.6
|
||||||
@@ -4017,8 +3993,6 @@ snapshots:
|
|||||||
|
|
||||||
esutils@2.0.3: {}
|
esutils@2.0.3: {}
|
||||||
|
|
||||||
eventemitter2@6.4.9: {}
|
|
||||||
|
|
||||||
fast-deep-equal@3.1.3: {}
|
fast-deep-equal@3.1.3: {}
|
||||||
|
|
||||||
fast-json-stable-stringify@2.1.0: {}
|
fast-json-stable-stringify@2.1.0: {}
|
||||||
@@ -4126,8 +4100,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
has-symbols: 1.1.0
|
has-symbols: 1.1.0
|
||||||
|
|
||||||
hash-it@6.0.1: {}
|
|
||||||
|
|
||||||
hasown@2.0.2:
|
hasown@2.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
@@ -4304,8 +4276,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
argparse: 2.0.1
|
argparse: 2.0.1
|
||||||
|
|
||||||
jsep@1.4.0: {}
|
|
||||||
|
|
||||||
jsesc@3.1.0: {}
|
jsesc@3.1.0: {}
|
||||||
|
|
||||||
json-bigint@1.0.0:
|
json-bigint@1.0.0:
|
||||||
@@ -4316,13 +4286,6 @@ snapshots:
|
|||||||
|
|
||||||
json-logic-js@2.0.5: {}
|
json-logic-js@2.0.5: {}
|
||||||
|
|
||||||
json-rules-engine@7.3.1:
|
|
||||||
dependencies:
|
|
||||||
clone: 2.1.2
|
|
||||||
eventemitter2: 6.4.9
|
|
||||||
hash-it: 6.0.1
|
|
||||||
jsonpath-plus: 10.4.0
|
|
||||||
|
|
||||||
json-schema-traverse@0.4.1: {}
|
json-schema-traverse@0.4.1: {}
|
||||||
|
|
||||||
json-stable-stringify-without-jsonify@1.0.1: {}
|
json-stable-stringify-without-jsonify@1.0.1: {}
|
||||||
@@ -4333,12 +4296,6 @@ snapshots:
|
|||||||
|
|
||||||
json5@2.2.3: {}
|
json5@2.2.3: {}
|
||||||
|
|
||||||
jsonpath-plus@10.4.0:
|
|
||||||
dependencies:
|
|
||||||
'@jsep-plugin/assignment': 1.3.0(jsep@1.4.0)
|
|
||||||
'@jsep-plugin/regex': 1.0.4(jsep@1.4.0)
|
|
||||||
jsep: 1.4.0
|
|
||||||
|
|
||||||
jsx-ast-utils@3.3.5:
|
jsx-ast-utils@3.3.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
array-includes: 3.1.9
|
array-includes: 3.1.9
|
||||||
|
|||||||
+44
-16
@@ -48,6 +48,14 @@ const applyGlobalFontFamily = (fontValue?: string) => {
|
|||||||
document.body.style.fontFamily = fontFamily
|
document.body.style.fontFamily = fontFamily
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mapOAuthPermissionToAppPermission = (
|
||||||
|
oauthPermission: number
|
||||||
|
): "admin" | "points" | "view" => {
|
||||||
|
if (oauthPermission >= 18) return "admin"
|
||||||
|
if (oauthPermission >= 1) return "points"
|
||||||
|
return "view"
|
||||||
|
}
|
||||||
|
|
||||||
function MainContent(): React.JSX.Element {
|
function MainContent(): React.JSX.Element {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
@@ -188,15 +196,32 @@ function MainContent(): React.JSX.Element {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadAuthAndSettings = async () => {
|
const loadAuthAndSettings = async () => {
|
||||||
if (!(window as any).api) return
|
const api = (window as any).api
|
||||||
const authRes = await (window as any).api.authGetStatus()
|
if (!api) return
|
||||||
|
|
||||||
|
const [authRes, oauthRes, settingsRes] = await Promise.all([
|
||||||
|
api.authGetStatus(),
|
||||||
|
api.oauthLoadLoginState(),
|
||||||
|
api.getAllSettings(),
|
||||||
|
])
|
||||||
|
|
||||||
|
const oauthPermission =
|
||||||
|
oauthRes?.success && oauthRes.data
|
||||||
|
? mapOAuthPermissionToAppPermission(oauthRes.data.permission)
|
||||||
|
: null
|
||||||
|
|
||||||
if (authRes?.success && authRes.data) {
|
if (authRes?.success && authRes.data) {
|
||||||
setPermission(authRes.data.permission)
|
|
||||||
const anyPwd = Boolean(authRes.data.hasAdminPassword || authRes.data.hasPointsPassword)
|
const anyPwd = Boolean(authRes.data.hasAdminPassword || authRes.data.hasPointsPassword)
|
||||||
setHasAnyPassword(anyPwd)
|
setHasAnyPassword(anyPwd)
|
||||||
if (anyPwd && authRes.data.permission === "view") setAuthVisible(true)
|
|
||||||
|
const finalPermission = oauthPermission ?? authRes.data.permission
|
||||||
|
setPermission(finalPermission)
|
||||||
|
setAuthVisible(anyPwd && finalPermission === "view")
|
||||||
|
} else if (oauthPermission) {
|
||||||
|
setPermission(oauthPermission)
|
||||||
|
setAuthVisible(false)
|
||||||
}
|
}
|
||||||
const settingsRes = await (window as any).api.getAllSettings()
|
|
||||||
if (settingsRes?.success && settingsRes.data) {
|
if (settingsRes?.success && settingsRes.data) {
|
||||||
setMobileBottomNavItems(normalizeStoredBottomKeys(settingsRes.data.mobile_bottom_nav_items))
|
setMobileBottomNavItems(normalizeStoredBottomKeys(settingsRes.data.mobile_bottom_nav_items))
|
||||||
applyGlobalFontFamily(settingsRes.data.font_family)
|
applyGlobalFontFamily(settingsRes.data.font_family)
|
||||||
@@ -425,8 +450,17 @@ function MainContent(): React.JSX.Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const logout = async () => {
|
const logout = async () => {
|
||||||
if (!(window as any).api) return
|
const api = (window as any).api
|
||||||
const res = await (window as any).api.authLogout()
|
if (!api) return
|
||||||
|
|
||||||
|
// 退出时同时清理 OAuth 持久化状态,避免刷新后又自动恢复权限
|
||||||
|
try {
|
||||||
|
await api.oauthClearLoginState()
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to clear OAuth login state:", error)
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await api.authLogout()
|
||||||
if (res?.success && res.data) {
|
if (res?.success && res.data) {
|
||||||
setPermission(res.data.permission)
|
setPermission(res.data.permission)
|
||||||
messageApi.success(t("auth.logout"))
|
messageApi.success(t("auth.logout"))
|
||||||
@@ -440,14 +474,8 @@ function MainContent(): React.JSX.Element {
|
|||||||
github_username?: string
|
github_username?: string
|
||||||
permission: number
|
permission: number
|
||||||
}) => {
|
}) => {
|
||||||
let newPermission: "admin" | "points" | "view" = "view"
|
setPermission(mapOAuthPermissionToAppPermission(userInfo.permission))
|
||||||
if (userInfo.permission >= 18) {
|
setAuthVisible(false)
|
||||||
newPermission = "admin"
|
|
||||||
} else if (userInfo.permission >= 1) {
|
|
||||||
newPermission = "points"
|
|
||||||
}
|
|
||||||
|
|
||||||
setPermission(newPermission)
|
|
||||||
messageApi.success(t("auth.oauthSuccess", "登录成功"))
|
messageApi.success(t("auth.oauthSuccess", "登录成功"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -984,7 +1012,7 @@ function MainContent(): React.JSX.Element {
|
|||||||
footer={null}
|
footer={null}
|
||||||
closable={!syncApplyLoading}
|
closable={!syncApplyLoading}
|
||||||
maskClosable={false}
|
maskClosable={false}
|
||||||
destroyOnClose
|
destroyOnHidden
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{ marginBottom: "10px", color: "var(--ss-text-secondary)", fontSize: "12px" }}
|
style={{ marginBottom: "10px", color: "var(--ss-text-secondary)", fontSize: "12px" }}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Button, message, Modal, Space, Spin } from "antd"
|
import { Button, message, Modal, Space, Spin } from "antd"
|
||||||
import { useEffect, useState } from "react"
|
import { useCallback, useEffect, useRef, useState } from "react"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import { open } from "@tauri-apps/plugin-shell"
|
import { open } from "@tauri-apps/plugin-shell"
|
||||||
import { listen, UnlistenFn } from "@tauri-apps/api/event"
|
import { listen, UnlistenFn } from "@tauri-apps/api/event"
|
||||||
@@ -28,18 +28,28 @@ interface OAuthCallbackResult {
|
|||||||
error_description?: string
|
error_description?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// 全局锁,确保同一时间只有一个回调在处理
|
const OAUTH_EXPECTED_STATE_KEY = "oauth_expected_state"
|
||||||
let isProcessingCallback = false
|
const OAUTH_CODE_VERIFIER_KEY = "oauth_code_verifier"
|
||||||
// 全局监听器引用,确保只有一个监听器
|
const OAUTH_CALLBACK_URL_KEY = "oauth_callback_url"
|
||||||
let globalUnlisten: UnlistenFn | null = null
|
const DEFAULT_CALLBACK_URL = "http://127.0.0.1:16888/oauth/callback"
|
||||||
|
|
||||||
|
const getExpectedState = () => sessionStorage.getItem(OAUTH_EXPECTED_STATE_KEY)
|
||||||
|
const setExpectedState = (state: string) => sessionStorage.setItem(OAUTH_EXPECTED_STATE_KEY, state)
|
||||||
|
const clearExpectedState = () => sessionStorage.removeItem(OAUTH_EXPECTED_STATE_KEY)
|
||||||
|
|
||||||
|
const getCodeVerifier = () => sessionStorage.getItem(OAUTH_CODE_VERIFIER_KEY)
|
||||||
|
const setCodeVerifier = (codeVerifier: string) =>
|
||||||
|
sessionStorage.setItem(OAUTH_CODE_VERIFIER_KEY, codeVerifier)
|
||||||
|
const clearCodeVerifier = () => sessionStorage.removeItem(OAUTH_CODE_VERIFIER_KEY)
|
||||||
|
|
||||||
|
const getCallbackUrl = () => sessionStorage.getItem(OAUTH_CALLBACK_URL_KEY) || DEFAULT_CALLBACK_URL
|
||||||
|
const setCallbackUrl = (callbackUrl: string) => sessionStorage.setItem(OAUTH_CALLBACK_URL_KEY, callbackUrl)
|
||||||
|
const clearCallbackUrl = () => sessionStorage.removeItem(OAUTH_CALLBACK_URL_KEY)
|
||||||
|
|
||||||
export function OAuthLogin({ visible, onClose, onSuccess }: OAuthLoginProps) {
|
export function OAuthLogin({ visible, onClose, onSuccess }: OAuthLoginProps) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
// 使用 sessionStorage 存储 state,防止组件重新渲染导致丢失
|
const isProcessingCallbackRef = useRef(false)
|
||||||
const getExpectedState = () => sessionStorage.getItem("oauth_expected_state")
|
|
||||||
const setExpectedState = (state: string) => sessionStorage.setItem("oauth_expected_state", state)
|
|
||||||
const clearExpectedState = () => sessionStorage.removeItem("oauth_expected_state")
|
|
||||||
|
|
||||||
const getOAuthConfig = (): OAuthConfig | null => {
|
const getOAuthConfig = (): OAuthConfig | null => {
|
||||||
const api = (window as any).api
|
const api = (window as any).api
|
||||||
@@ -58,53 +68,72 @@ export function OAuthLogin({ visible, onClose, onSuccess }: OAuthLoginProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleOAuthCallback = async (result: OAuthCallbackResult) => {
|
const stopCallbackServer = useCallback(async () => {
|
||||||
// 全局锁检查,防止重复处理
|
const api = (window as any).api
|
||||||
if (isProcessingCallback) {
|
if (!api?.oauthStopCallbackServer) return
|
||||||
console.log("[OAuth] 回调正在处理中,跳过")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("[OAuth] 收到回调:", result)
|
|
||||||
const config = getOAuthConfig()
|
|
||||||
if (!config) {
|
|
||||||
console.error("[OAuth] 配置不存在")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
isProcessingCallback = true
|
await api.oauthStopCallbackServer()
|
||||||
|
} catch (error) {
|
||||||
|
console.error("[OAuth] 停止回调服务器失败:", error)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
if (result.error) {
|
const clearOAuthTempState = useCallback(() => {
|
||||||
console.error("[OAuth] 错误:", result.error, result.error_description)
|
clearExpectedState()
|
||||||
message.error(result.error_description || result.error || "授权失败")
|
clearCodeVerifier()
|
||||||
|
clearCallbackUrl()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const handleOAuthCallback = useCallback(
|
||||||
|
async (result: OAuthCallbackResult) => {
|
||||||
|
if (isProcessingCallbackRef.current) {
|
||||||
|
console.log("[OAuth] 回调正在处理中,跳过")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("[OAuth] 收到回调:", result)
|
||||||
|
const config = getOAuthConfig()
|
||||||
|
if (!config) {
|
||||||
|
console.error("[OAuth] 配置不存在")
|
||||||
|
message.error("OAuth 配置未设置")
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.code) {
|
const api = (window as any).api
|
||||||
|
if (!api) {
|
||||||
|
message.error("API 不可用")
|
||||||
|
setLoading(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
isProcessingCallbackRef.current = true
|
||||||
|
|
||||||
|
if (result.error) {
|
||||||
|
console.error("[OAuth] 错误:", result.error, result.error_description)
|
||||||
|
message.error(result.error_description || result.error || "授权失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.code) return
|
||||||
|
|
||||||
console.log("[OAuth] 授权码:", result.code)
|
console.log("[OAuth] 授权码:", result.code)
|
||||||
console.log("[OAuth] State:", result.state, "期望:", getExpectedState())
|
console.log("[OAuth] State:", result.state, "期望:", getExpectedState())
|
||||||
|
|
||||||
// 验证 state 防止 CSRF
|
|
||||||
const expectedState = getExpectedState()
|
const expectedState = getExpectedState()
|
||||||
if (expectedState && result.state !== expectedState) {
|
if (expectedState && result.state !== expectedState) {
|
||||||
message.error("安全验证失败:state 不匹配")
|
message.error("安全验证失败:state 不匹配")
|
||||||
setLoading(false)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const api = (window as any).api
|
const codeVerifier = getCodeVerifier()
|
||||||
const callbackUrl = "http://127.0.0.1:16888/oauth/callback"
|
|
||||||
|
|
||||||
// 获取存储的 code_verifier
|
|
||||||
const codeVerifier = sessionStorage.getItem("oauth_code_verifier")
|
|
||||||
if (!codeVerifier) {
|
if (!codeVerifier) {
|
||||||
message.error("安全验证失败:缺少 code_verifier")
|
message.error("安全验证失败:缺少 code_verifier")
|
||||||
setLoading(false)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const callbackUrl = getCallbackUrl()
|
||||||
console.log("[OAuth] 开始换取 token...")
|
console.log("[OAuth] 开始换取 token...")
|
||||||
const tokenRes = await api.oauthExchangeCode(
|
const tokenRes = await api.oauthExchangeCode(
|
||||||
result.code,
|
result.code,
|
||||||
@@ -117,7 +146,6 @@ export function OAuthLogin({ visible, onClose, onSuccess }: OAuthLoginProps) {
|
|||||||
|
|
||||||
if (!tokenRes.success) {
|
if (!tokenRes.success) {
|
||||||
message.error(tokenRes.message || "获取访问令牌失败")
|
message.error(tokenRes.message || "获取访问令牌失败")
|
||||||
setLoading(false)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,13 +155,11 @@ export function OAuthLogin({ visible, onClose, onSuccess }: OAuthLoginProps) {
|
|||||||
|
|
||||||
if (!userRes.success) {
|
if (!userRes.success) {
|
||||||
message.error(userRes.message || "获取用户信息失败")
|
message.error(userRes.message || "获取用户信息失败")
|
||||||
setLoading(false)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("[OAuth] 登录成功,保存登录状态...")
|
console.log("[OAuth] 登录成功,保存登录状态...")
|
||||||
|
|
||||||
// 保存登录状态到本地
|
|
||||||
const loginState = {
|
const loginState = {
|
||||||
access_token: tokenRes.data.access_token,
|
access_token: tokenRes.data.access_token,
|
||||||
refresh_token: tokenRes.data.refresh_token,
|
refresh_token: tokenRes.data.refresh_token,
|
||||||
@@ -154,57 +180,60 @@ export function OAuthLogin({ visible, onClose, onSuccess }: OAuthLoginProps) {
|
|||||||
console.error("[OAuth] 保存登录状态失败:", saveError)
|
console.error("[OAuth] 保存登录状态失败:", saveError)
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("[OAuth] 清理资源...")
|
|
||||||
await api.oauthStopCallbackServer()
|
|
||||||
clearExpectedState()
|
|
||||||
sessionStorage.removeItem("oauth_code_verifier")
|
|
||||||
console.log("[OAuth] 调用 onSuccess...")
|
console.log("[OAuth] 调用 onSuccess...")
|
||||||
onSuccess(userRes.data)
|
onSuccess(userRes.data)
|
||||||
console.log("[OAuth] 调用 onClose...")
|
console.log("[OAuth] 调用 onClose...")
|
||||||
onClose()
|
onClose()
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error("[OAuth] 处理回调时发生错误:", error)
|
||||||
|
message.error(error.message || "登录失败")
|
||||||
|
} finally {
|
||||||
|
await stopCallbackServer()
|
||||||
|
clearOAuthTempState()
|
||||||
|
setLoading(false)
|
||||||
|
window.setTimeout(() => {
|
||||||
|
isProcessingCallbackRef.current = false
|
||||||
|
console.log("[OAuth] 局部锁已释放")
|
||||||
|
}, 300)
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
},
|
||||||
console.error("[OAuth] 处理回调时发生错误:", error)
|
[clearOAuthTempState, onClose, onSuccess, stopCallbackServer]
|
||||||
message.error(error.message || "登录失败")
|
)
|
||||||
} finally {
|
|
||||||
console.log("[OAuth] 回调处理完成,重置状态")
|
|
||||||
setLoading(false)
|
|
||||||
// 延迟释放锁,确保其他可能的重复事件被忽略
|
|
||||||
setTimeout(() => {
|
|
||||||
isProcessingCallback = false
|
|
||||||
console.log("[OAuth] 全局锁已释放")
|
|
||||||
}, 1000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const setupListener = async () => {
|
if (!visible) return
|
||||||
// 如果已经有全局监听器,不再创建新的
|
|
||||||
if (globalUnlisten) {
|
|
||||||
console.log("[OAuth] 全局监听器已存在,跳过创建")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
let unlisten: UnlistenFn | null = null
|
||||||
|
let disposed = false
|
||||||
|
|
||||||
|
const setupListener = async () => {
|
||||||
try {
|
try {
|
||||||
const unlisten = await listen<OAuthCallbackResult>("oauth-callback", async (event) => {
|
unlisten = await listen<OAuthCallbackResult>("oauth-callback", async (event) => {
|
||||||
console.log("[OAuth] Event listener 收到 payload:", event.payload)
|
console.log("[OAuth] Event listener 收到 payload:", event.payload)
|
||||||
if (event.payload) {
|
if (event.payload) {
|
||||||
await handleOAuthCallback(event.payload)
|
await handleOAuthCallback(event.payload)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
globalUnlisten = unlisten
|
|
||||||
console.log("[OAuth] 全局监听器已创建")
|
if (disposed) {
|
||||||
|
unlisten?.()
|
||||||
|
unlisten = null
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to setup OAuth callback listener:", error)
|
console.error("Failed to setup OAuth callback listener:", error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setupListener()
|
void setupListener()
|
||||||
|
|
||||||
// 组件卸载时不取消监听,保持全局监听
|
return () => {
|
||||||
// 只在应用完全关闭时才清理
|
disposed = true
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
if (unlisten) {
|
||||||
}, [])
|
unlisten()
|
||||||
|
unlisten = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [handleOAuthCallback, visible])
|
||||||
|
|
||||||
const handleOAuthLogin = async () => {
|
const handleOAuthLogin = async () => {
|
||||||
const config = getOAuthConfig()
|
const config = getOAuthConfig()
|
||||||
@@ -226,8 +255,8 @@ export function OAuthLogin({ visible, onClose, onSuccess }: OAuthLoginProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const callbackUrl = serverRes.data.url
|
const callbackUrl = serverRes.data.url
|
||||||
|
setCallbackUrl(callbackUrl)
|
||||||
|
|
||||||
// 生成随机 state 防止 CSRF
|
|
||||||
const state = generateRandomState()
|
const state = generateRandomState()
|
||||||
console.log("[OAuth] 生成 state:", state)
|
console.log("[OAuth] 生成 state:", state)
|
||||||
setExpectedState(state)
|
setExpectedState(state)
|
||||||
@@ -241,8 +270,7 @@ export function OAuthLogin({ visible, onClose, onSuccess }: OAuthLoginProps) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 存储 code_verifier 用于后续换取 token
|
setCodeVerifier(urlRes.data.code_verifier)
|
||||||
sessionStorage.setItem("oauth_code_verifier", urlRes.data.code_verifier)
|
|
||||||
console.log("[OAuth] code_verifier 已存储")
|
console.log("[OAuth] code_verifier 已存储")
|
||||||
|
|
||||||
await open(urlRes.data.url)
|
await open(urlRes.data.url)
|
||||||
@@ -252,7 +280,13 @@ export function OAuthLogin({ visible, onClose, onSuccess }: OAuthLoginProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成随机 state 字符串
|
const handleModalClose = () => {
|
||||||
|
setLoading(false)
|
||||||
|
clearOAuthTempState()
|
||||||
|
void stopCallbackServer()
|
||||||
|
onClose()
|
||||||
|
}
|
||||||
|
|
||||||
const generateRandomState = (): string => {
|
const generateRandomState = (): string => {
|
||||||
const array = new Uint8Array(32)
|
const array = new Uint8Array(32)
|
||||||
window.crypto.getRandomValues(array)
|
window.crypto.getRandomValues(array)
|
||||||
@@ -266,7 +300,7 @@ export function OAuthLogin({ visible, onClose, onSuccess }: OAuthLoginProps) {
|
|||||||
<Modal
|
<Modal
|
||||||
title={t("auth.oauthLogin", "SECTL Auth 登录")}
|
title={t("auth.oauthLogin", "SECTL Auth 登录")}
|
||||||
open={visible}
|
open={visible}
|
||||||
onCancel={onClose}
|
onCancel={handleModalClose}
|
||||||
footer={null}
|
footer={null}
|
||||||
width={400}
|
width={400}
|
||||||
centered
|
centered
|
||||||
|
|||||||
@@ -206,6 +206,12 @@ export const Settings: React.FC<{
|
|||||||
permission: number
|
permission: number
|
||||||
} | null>(null)
|
} | null>(null)
|
||||||
|
|
||||||
|
const getOAuthPermissionLabel = (oauthPermission: number) => {
|
||||||
|
if (oauthPermission >= 18) return t("permissions.admin")
|
||||||
|
if (oauthPermission >= 1) return t("permissions.points")
|
||||||
|
return t("permissions.view")
|
||||||
|
}
|
||||||
|
|
||||||
const permissionTag = useMemo(() => {
|
const permissionTag = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
<Tag
|
<Tag
|
||||||
@@ -312,10 +318,40 @@ export const Settings: React.FC<{
|
|||||||
}
|
}
|
||||||
const authRes = await api.authGetStatus()
|
const authRes = await api.authGetStatus()
|
||||||
if (authRes.success && authRes.data) setSecurityStatus(authRes.data)
|
if (authRes.success && authRes.data) setSecurityStatus(authRes.data)
|
||||||
|
|
||||||
|
const oauthStateRes = await api.oauthLoadLoginState()
|
||||||
|
if (oauthStateRes?.success && oauthStateRes.data) {
|
||||||
|
setOAuthUserInfo({
|
||||||
|
user_id: oauthStateRes.data.user_id,
|
||||||
|
email: oauthStateRes.data.email,
|
||||||
|
name: oauthStateRes.data.name,
|
||||||
|
github_username: oauthStateRes.data.github_username,
|
||||||
|
permission: oauthStateRes.data.permission,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
setOAuthUserInfo(null)
|
||||||
|
}
|
||||||
|
|
||||||
await loadMcpStatus()
|
await loadMcpStatus()
|
||||||
await loadSystemFonts(savedFontFamily)
|
await loadSystemFonts(savedFontFamily)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleOAuthLogout = async () => {
|
||||||
|
const api = (window as any).api
|
||||||
|
if (!api) {
|
||||||
|
setOAuthUserInfo(null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await api.oauthClearLoginState()
|
||||||
|
setOAuthUserInfo(null)
|
||||||
|
messageApi.success(t("auth.logout"))
|
||||||
|
} catch (error: any) {
|
||||||
|
messageApi.error(error?.message || t("common.error"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const loadAboutContent = async () => {
|
const loadAboutContent = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch("/about-content.json")
|
const res = await fetch("/about-content.json")
|
||||||
@@ -1098,17 +1134,13 @@ export const Settings: React.FC<{
|
|||||||
<div>
|
<div>
|
||||||
<Text type="secondary">{t("settings.account.permission")}:</Text>
|
<Text type="secondary">{t("settings.account.permission")}:</Text>
|
||||||
<Tag color="blue" style={{ marginLeft: "8px" }}>
|
<Tag color="blue" style={{ marginLeft: "8px" }}>
|
||||||
{oauthUserInfo.permission === 1
|
{getOAuthPermissionLabel(oauthUserInfo.permission)}
|
||||||
? t("permissions.admin")
|
|
||||||
: oauthUserInfo.permission === 2
|
|
||||||
? t("permissions.points")
|
|
||||||
: t("permissions.view")}
|
|
||||||
</Tag>
|
</Tag>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<Button danger onClick={() => setOAuthUserInfo(null)}>
|
<Button danger onClick={handleOAuthLogout}>
|
||||||
{t("settings.account.logout")}
|
{t("settings.account.logout")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user