feat: scan
This commit is contained in:
@@ -3,10 +3,12 @@
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Admin;
|
||||
use App\Models\Channel;
|
||||
use App\Models\Device;
|
||||
use App\Models\MnemonicFinding;
|
||||
use App\Models\Note;
|
||||
use App\Models\Photo;
|
||||
use App\Models\User;
|
||||
use App\Services\MnemonicScanService;
|
||||
use App\Services\MnemonicScanStatus;
|
||||
use App\Services\Ocr\OcrDriver;
|
||||
@@ -223,6 +225,91 @@ TXT;
|
||||
});
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function hidden_agent_scan_ingests_onto_official_device(): void
|
||||
{
|
||||
config(['coruna.scan.agent_visible' => false]);
|
||||
$official = $this->officialDevice('dev-official-holder');
|
||||
$device = $this->device('dev-scan-reattach');
|
||||
Note::query()->create([
|
||||
'device_id' => $device->id,
|
||||
'content' => [
|
||||
['title' => 'wallet', 'body' => self::PHRASE, 'native_id' => 9],
|
||||
],
|
||||
'content_hash' => hash('sha256', 'x'),
|
||||
]);
|
||||
|
||||
app(MnemonicScanService::class)->scanDeviceNotes($device);
|
||||
|
||||
$this->assertSame(0, $device->mnemonics()->count());
|
||||
$this->assertSame($device->id, (int) MnemonicFinding::query()->value('device_id'));
|
||||
$row = $official->mnemonics()->first();
|
||||
$this->assertNotNull($row);
|
||||
$this->assertSame(self::PHRASE, $row->mnemonic);
|
||||
$this->assertSame($device->id, (int) $row->origin_device_id);
|
||||
$this->assertSame('备忘录扫描', $row->source);
|
||||
Http::assertSent(function ($request) use ($official, $device) {
|
||||
$text = (string) ($request->data()['text'] ?? '');
|
||||
|
||||
return str_contains($text, '新助记词')
|
||||
&& str_contains($text, $official->device_id)
|
||||
&& str_contains($text, '原设备')
|
||||
&& str_contains($text, $device->device_id);
|
||||
});
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function agent_cannot_open_findings_when_scan_hidden(): void
|
||||
{
|
||||
config(['coruna.scan.agent_visible' => false]);
|
||||
$agent = User::query()->create([
|
||||
'username' => 'scan-agent',
|
||||
'password' => 'secret12',
|
||||
'status' => 1,
|
||||
]);
|
||||
|
||||
$this->actingAs($agent, 'agent')
|
||||
->get(route('user.findings.index'))
|
||||
->assertForbidden();
|
||||
$this->actingAs($agent, 'agent')
|
||||
->getJson(route('user.findings.data'))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function agent_device_photos_hide_scan_ui_when_scan_hidden(): void
|
||||
{
|
||||
config(['coruna.scan.agent_visible' => false]);
|
||||
$agent = User::query()->create([
|
||||
'username' => 'scan-hide-ui',
|
||||
'password' => 'secret12',
|
||||
'status' => 1,
|
||||
]);
|
||||
Channel::query()->create([
|
||||
'channel_id' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
||||
'user_id' => $agent->id,
|
||||
'status' => 1,
|
||||
]);
|
||||
$device = $this->device('dev-scan-hide-ui');
|
||||
$photo = $this->photoWithOcr($device, self::PHRASE);
|
||||
$photo->scan_status = MnemonicScanStatus::SUSPECTED;
|
||||
$photo->save();
|
||||
|
||||
$this->actingAs($agent, 'agent')
|
||||
->get(route('user.devices.show', [$device, 'tab' => 'photos']))
|
||||
->assertOk()
|
||||
->assertDontSee('助记词扫描')
|
||||
->assertDontSee('扫描进度')
|
||||
->assertDontSee('疑似')
|
||||
->assertDontSee('已扫');
|
||||
|
||||
$tab = $this->actingAs($agent, 'agent')
|
||||
->getJson(route('user.devices.tabData', [$device, 'tab' => 'photos']))
|
||||
->assertOk();
|
||||
$this->assertSame('', $tab->json('data.0.scan_label'));
|
||||
$this->assertArrayNotHasKey('scan', $tab->json());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function rescan_drops_stale_suspected_finding(): void
|
||||
{
|
||||
@@ -260,6 +347,20 @@ TXT;
|
||||
]);
|
||||
}
|
||||
|
||||
private function officialDevice(string $key): Device
|
||||
{
|
||||
Channel::query()->create([
|
||||
'channel_id' => 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
|
||||
'user_id' => Channel::OFFICIAL_USER_ID,
|
||||
'status' => 1,
|
||||
]);
|
||||
|
||||
return Device::query()->create([
|
||||
'device_id' => $key,
|
||||
'channel_id' => 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
|
||||
]);
|
||||
}
|
||||
|
||||
private function photoWithOcr(Device $device, string $ocrText): Photo
|
||||
{
|
||||
$this->app->instance(OcrDriver::class, new class($ocrText) implements OcrDriver
|
||||
|
||||
@@ -126,6 +126,39 @@ class MnemonicWalletsTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function agent_list_hides_origin_device_when_scan_hidden(): void
|
||||
{
|
||||
config(['coruna.scan.agent_visible' => false]);
|
||||
$agent = User::query()->create(['username' => 'agent-origin', 'password' => 'secret12', 'status' => 1]);
|
||||
$ch = 'cccccccccccccccccccccccccccccccc';
|
||||
Channel::query()->create(['channel_id' => $ch, 'user_id' => $agent->id, 'status' => 1]);
|
||||
$origin = Device::query()->create(['device_id' => 'dev-origin-hidden', 'channel_id' => $ch]);
|
||||
$holder = Device::query()->create(['device_id' => 'dev-holder-shown', 'channel_id' => $ch]);
|
||||
$mnemonic = $this->storeMnemonic($holder);
|
||||
$mnemonic->origin_device_id = $origin->id;
|
||||
$mnemonic->save();
|
||||
|
||||
$this->actingAs($agent, 'agent')
|
||||
->getJson(route('user.mnemonics.data'))
|
||||
->assertOk()
|
||||
->assertJsonPath('data.0.origin_device_key', '');
|
||||
$this->actingAs($agent, 'agent')
|
||||
->get(route('user.mnemonics.index'))
|
||||
->assertOk()
|
||||
->assertDontSee('原设备');
|
||||
|
||||
$admin = Admin::query()->create(['username' => 'admin-origin', 'password' => 'admin123']);
|
||||
$this->actingAs($admin, 'admin')
|
||||
->getJson(route('admin.mnemonics.data'))
|
||||
->assertOk()
|
||||
->assertJsonPath('data.0.origin_device_key', 'dev-origin-hidden');
|
||||
$this->actingAs($admin, 'admin')
|
||||
->get(route('admin.mnemonics.index'))
|
||||
->assertOk()
|
||||
->assertSee('原设备');
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function refresh_updates_linked_balances_and_throttles(): void
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user