mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-03-25 07:16:51 +00:00
feat: update welcome page and fix handle error
This commit is contained in:
@@ -146,10 +146,11 @@ export class KeyService {
|
|||||||
this.koffi = require('koffi')
|
this.koffi = require('koffi')
|
||||||
this.kernel32 = this.koffi.load('kernel32.dll')
|
this.kernel32 = this.koffi.load('kernel32.dll')
|
||||||
|
|
||||||
this.OpenProcess = this.kernel32.func('OpenProcess', 'HANDLE', ['uint32', 'bool', 'uint32'])
|
// 直接使用原生支持的 'void*' 替换 'HANDLE',绝对不会再报类型错误
|
||||||
this.CloseHandle = this.kernel32.func('CloseHandle', 'bool', ['HANDLE'])
|
this.OpenProcess = this.kernel32.func('OpenProcess', 'void*', ['uint32', 'bool', 'uint32'])
|
||||||
this.TerminateProcess = this.kernel32.func('TerminateProcess', 'bool', ['HANDLE', 'uint32'])
|
this.CloseHandle = this.kernel32.func('CloseHandle', 'bool', ['void*'])
|
||||||
this.QueryFullProcessImageNameW = this.kernel32.func('QueryFullProcessImageNameW', 'bool', ['HANDLE', 'uint32', this.koffi.out('uint16*'), this.koffi.out('uint32*')])
|
this.TerminateProcess = this.kernel32.func('TerminateProcess', 'bool', ['void*', 'uint32'])
|
||||||
|
this.QueryFullProcessImageNameW = this.kernel32.func('QueryFullProcessImageNameW', 'bool', ['void*', 'uint32', this.koffi.out('uint16*'), this.koffi.out('uint32*')])
|
||||||
|
|
||||||
return true
|
return true
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -803,3 +803,79 @@
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.brute-force-progress {
|
||||||
|
margin-top: 16px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
background: var(--bg-tertiary);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 12px;
|
||||||
|
animation: slideUp 0.3s ease;
|
||||||
|
|
||||||
|
.status-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
.status-text {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-weight: 500;
|
||||||
|
margin: 0;
|
||||||
|
animation: pulse 2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.percent {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--primary);
|
||||||
|
font-weight: 700;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 8px;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||||
|
|
||||||
|
.fill {
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, var(--primary) 0%, color-mix(in srgb, var(--primary) 60%, white) 100%);
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
transparent,
|
||||||
|
rgba(255, 255, 255, 0.3),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
animation: progress-shimmer 1.5s infinite linear;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0%, 100% { opacity: 1; }
|
||||||
|
50% { opacity: 0.7; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes progress-shimmer {
|
||||||
|
0% { transform: translateX(-100%); }
|
||||||
|
100% { transform: translateX(100%); }
|
||||||
|
}
|
||||||
@@ -48,6 +48,7 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
|
|||||||
const [dbKeyStatus, setDbKeyStatus] = useState('')
|
const [dbKeyStatus, setDbKeyStatus] = useState('')
|
||||||
const [imageKeyStatus, setImageKeyStatus] = useState('')
|
const [imageKeyStatus, setImageKeyStatus] = useState('')
|
||||||
const [isManualStartPrompt, setIsManualStartPrompt] = useState(false)
|
const [isManualStartPrompt, setIsManualStartPrompt] = useState(false)
|
||||||
|
const [imageKeyPercent, setImageKeyPercent] = useState<number | null>(null)
|
||||||
|
|
||||||
// 安全相关 state
|
// 安全相关 state
|
||||||
const [enableAuth, setEnableAuth] = useState(false)
|
const [enableAuth, setEnableAuth] = useState(false)
|
||||||
@@ -111,8 +112,25 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
|
|||||||
const removeDb = window.electronAPI.key.onDbKeyStatus((payload: { message: string; level: number }) => {
|
const removeDb = window.electronAPI.key.onDbKeyStatus((payload: { message: string; level: number }) => {
|
||||||
setDbKeyStatus(payload.message)
|
setDbKeyStatus(payload.message)
|
||||||
})
|
})
|
||||||
const removeImage = window.electronAPI.key.onImageKeyStatus((payload: { message: string }) => {
|
const removeImage = window.electronAPI.key.onImageKeyStatus((payload: { message: string, percent?: number }) => {
|
||||||
setImageKeyStatus(payload.message)
|
let msg = payload.message;
|
||||||
|
let pct = payload.percent;
|
||||||
|
|
||||||
|
// 解析文本中的百分比
|
||||||
|
if (pct === undefined) {
|
||||||
|
const match = msg.match(/\(([\d.]+)%\)/);
|
||||||
|
if (match) {
|
||||||
|
pct = parseFloat(match[1]);
|
||||||
|
msg = msg.replace(/\s*\([\d.]+%\)/, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setImageKeyStatus(msg);
|
||||||
|
if (pct !== undefined) {
|
||||||
|
setImageKeyPercent(pct);
|
||||||
|
} else if (msg.includes('启动多核') || msg.includes('定位') || msg.includes('准备')) {
|
||||||
|
setImageKeyPercent(0);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
return () => {
|
return () => {
|
||||||
removeDb?.()
|
removeDb?.()
|
||||||
@@ -297,6 +315,7 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
|
|||||||
}
|
}
|
||||||
setIsFetchingImageKey(true)
|
setIsFetchingImageKey(true)
|
||||||
setError('')
|
setError('')
|
||||||
|
setImageKeyPercent(0)
|
||||||
setImageKeyStatus('正在准备获取图片密钥...')
|
setImageKeyStatus('正在准备获取图片密钥...')
|
||||||
try {
|
try {
|
||||||
// 拼接完整的账号目录,确保 KeyService 能准确找到模板文件
|
// 拼接完整的账号目录,确保 KeyService 能准确找到模板文件
|
||||||
@@ -727,37 +746,52 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{currentStep.id === 'image' && (
|
{currentStep.id === 'image' && (
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<div className="grid-2">
|
<div className="grid-2">
|
||||||
<div>
|
<div>
|
||||||
<label className="field-label">图片 XOR 密钥</label>
|
<label className="field-label">图片 XOR 密钥</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="field-input"
|
className="field-input"
|
||||||
placeholder="0x..."
|
placeholder="0x..."
|
||||||
value={imageXorKey}
|
value={imageXorKey}
|
||||||
onChange={(e) => setImageXorKey(e.target.value)}
|
onChange={(e) => setImageXorKey(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="field-label">图片 AES 密钥</label>
|
<label className="field-label">图片 AES 密钥</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="field-input"
|
className="field-input"
|
||||||
placeholder="16位密钥"
|
placeholder="16位密钥"
|
||||||
value={imageAesKey}
|
value={imageAesKey}
|
||||||
onChange={(e) => setImageAesKey(e.target.value)}
|
onChange={(e) => setImageAesKey(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<button className="btn btn-secondary btn-block mt-4" onClick={handleAutoGetImageKey} disabled={isFetchingImageKey}>
|
||||||
|
{isFetchingImageKey ? '获取中...' : '自动获取图片密钥'}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{isFetchingImageKey ? (
|
||||||
|
<div className="brute-force-progress">
|
||||||
|
<div className="status-header">
|
||||||
|
<span className="status-text">{imageKeyStatus || '正在启动多核爆破引擎...'}</span>
|
||||||
|
{imageKeyPercent !== null && <span className="percent">{imageKeyPercent.toFixed(1)}%</span>}
|
||||||
|
</div>
|
||||||
|
{imageKeyPercent !== null && (
|
||||||
|
<div className="progress-bar-container">
|
||||||
|
<div className="fill" style={{ width: `${imageKeyPercent}%` }}></div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
imageKeyStatus && <div className="status-message" style={{ marginTop: '12px' }}>{imageKeyStatus}</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="field-hint">请在微信中打开几张图片后再点击获取</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button className="btn btn-secondary btn-block mt-4" onClick={handleAutoGetImageKey} disabled={isFetchingImageKey}>
|
|
||||||
{isFetchingImageKey ? '扫描中...' : '自动获取图片密钥'}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
{imageKeyStatus && <div className="status-message">{imageKeyStatus}</div>}
|
|
||||||
<div className="field-hint">请在微信中打开几张图片后再点击获取</div>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user