Skip to content

Commit

Permalink
wip button and debugging
Browse files Browse the repository at this point in the history
  • Loading branch information
Thomas Kerin committed Apr 8, 2018
1 parent 45e2ec7 commit 0770d8a
Show file tree
Hide file tree
Showing 26 changed files with 652 additions and 86 deletions.
36 changes: 36 additions & 0 deletions debug.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);

require "vendor/autoload.php";

use BitWasp\Trezor\Bridge\Client;
use BitWasp\Trezor\Bridge\Http\HttpClient;
use BitWasp\Trezor\Device\Button\DebugButtonAck;
use BitWasp\Trezor\Device\Command\LoadDeviceService;
use BitWasp\Trezor\Device\RequestFactory;

$depth = 0;
$fingerprint = 0;
$numChild = 0;
$chainCode = \Protobuf\Stream::fromString(hex2bin('a86d0945bd342199a130b65255df75199fe09e539d60053003cc1c0e999982a5'));
$privateKey = \Protobuf\Stream::fromString(hex2bin('874c62f2c98f7c94f1a691492825a71e8e9b9251f03c208f37d1ec9c9cda2b24'));
$language = "EN";

$reqFactory = new RequestFactory();
$hdNode = $reqFactory->privateHdNode($depth, $fingerprint, $numChild, $chainCode, $privateKey);
$loadDevice = $reqFactory->loadDeviceWithHdNode($hdNode, $language);

$httpClient = HttpClient::forUri("http://localhost:21325");
$client = new Client($httpClient);
$devices = $client->listDevices()->devices();
if (empty($devices)) {
throw new \RuntimeException("No devices returned");
}

$session = $client->acquire($devices[0]);
$dbgSession = $client->acquire($devices[1]);

$dbgBtnAck = new DebugButtonAck($dbgSession);
$loadService = new LoadDeviceService($dbgBtnAck);
$loaded = $loadService->call($session, $loadDevice);
var_dump($loaded);
10 changes: 8 additions & 2 deletions src/Bridge/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
use BitWasp\Trezor\Bridge\Message\VersionResponse;
use BitWasp\Trezor\Bridge\Schema\ValidatorFactory;
use BitWasp\Trezor\Bridge\Http\HttpClient;
use BitWasp\Trezor\Device\Message;
use BitWasp\Trezor\Device\MessageBase;
use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\ResponseInterface;

class Client
Expand Down Expand Up @@ -147,8 +148,13 @@ public function release(string $sessionId): bool
return true;
}

public function call(string $sessionId, Message $message): Message
public function call(string $sessionId, MessageBase $message): MessageBase
{
return $this->client->call($sessionId, $message);
}

public function callAsync(string $sessionId, MessageBase $message, array $headers): PromiseInterface
{
return $this->client->callAsync($sessionId, $message, $headers);
}
}
37 changes: 24 additions & 13 deletions src/Bridge/Http/HttpClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
use BitWasp\Trezor\Bridge\Codec\CallMessage;
use BitWasp\Trezor\Bridge\Message\Device;
use BitWasp\Trezor\Device\Message;
use BitWasp\Trezor\Device\MessageBase;
use BitWasp\TrezorProto\MessageType;
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\ResponseInterface;

class HttpClient
Expand Down Expand Up @@ -100,25 +102,34 @@ public function release(string $sessionId): ResponseInterface
]);
}

public function call(string $sessionId, Message $message): Message
public function call(string $sessionId, MessageBase $message): Message
{
$responsePromise = $this->callAsync($sessionId, $message);
return $responsePromise->wait(true);
}

public function callAsync(string $sessionId, MessageBase $message, array $headers = [])
{
static $prefixLen;
if (null === $prefixLen) {
$prefixLen = strlen("MessageType_");
}

$response = $this->client->post("/call/{$sessionId}", [
return $this->client->postAsync("/call/{$sessionId}", [
'headers' => $headers,
'body' => $this->callCodec->encode($message->getType(), $message->getProto()),
]);

list ($type, $result) = $this->callCodec->parsePayload($response->getBody());

$messageType = MessageType::valueOf($type);
$protoType = substr($messageType->name(), $prefixLen);
$reader = ["\\BitWasp\\TrezorProto\\{$protoType}", 'fromStream'];
assert(class_exists($reader[0]));

$protobuf = call_user_func($reader, $result);
return new Message($messageType, $protobuf);
])
->then(function (Response $response) use ($prefixLen, $message) {
echo "got response back for ({$message->getType()})";
list ($type, $result) = $this->callCodec->parsePayload($response->getBody());

$messageType = MessageType::valueOf($type);
$protoType = substr($messageType->name(), $prefixLen);
$reader = ["\\BitWasp\\TrezorProto\\{$protoType}", 'fromStream'];
assert(class_exists($reader[0]));

$protobuf = call_user_func($reader, $result);
return new Message($messageType, $protobuf);
});
}
}
36 changes: 27 additions & 9 deletions src/Bridge/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
use BitWasp\Trezor\Bridge\Message\Device;
use BitWasp\Trezor\Device\Exception\FailureException;
use BitWasp\Trezor\Device\Message;
use BitWasp\Trezor\Device\MessageBase;
use BitWasp\TrezorProto\Failure;
use GuzzleHttp\Promise\PromiseInterface;
use Protobuf\Message as ProtoMessage;

class Session
Expand Down Expand Up @@ -91,22 +93,38 @@ public function getDevice(): Device
{
return $this->device;
}

/**
* @param Message $message
* @param MessageBase $message
* @return ProtoMessage
* @throws FailureException
* @throws InactiveSessionException
*/
public function sendMessage(Message $message): ProtoMessage
public function sendMessageAsync(MessageBase $request, array $headers = []): PromiseInterface
{
$this->assertSessionIsActive();
$message = $this->client->call($this->getSessionId(), $message);
$proto = $message->getProto();
if ($proto instanceof Failure) {
FailureException::handleFailure($proto);
}
fwrite(STDERR, "(sending {$request->getType()})\n");
return $this->client->callAsync($this->getSessionId(), $request, $headers)
->then(function (Message $message) use ($request) {
fwrite(STDERR, "(for {$request->getType()}) got message back {$message->getType()})\n");
$proto = $message->getProto();
if ($proto instanceof Failure) {
fwrite(STDERR, "(failure {$request->getType()}) got message back {$message->getType()})\n");
FailureException::handleFailure($proto);
}

return $proto;
return $proto;
});
}
/**
* @param MessageBase $message
* @return ProtoMessage
* @throws FailureException
* @throws InactiveSessionException
*/
public function sendMessage(MessageBase $message): ProtoMessage
{
$this->assertSessionIsActive();
return $this->sendMessageAsync($message)
->wait(true);
}
}
14 changes: 14 additions & 0 deletions src/Device/Button/ButtonAck.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace BitWasp\Trezor\Device\Button;

use BitWasp\Trezor\Bridge\Session;
use BitWasp\TrezorProto\ButtonRequest;
use BitWasp\TrezorProto\ButtonRequestType;

abstract class ButtonAck
{
abstract function acknowledge(Session $session, ButtonRequest $request, ButtonRequestType $allowType);
}
62 changes: 62 additions & 0 deletions src/Device/Button/DebugButtonAck.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

declare(strict_types=1);

namespace BitWasp\Trezor\Device\Button;

use BitWasp\Trezor\Bridge\Session;
use BitWasp\Trezor\Device\DebugMessage;
use BitWasp\Trezor\Device\Message;
use BitWasp\TrezorProto\ButtonRequest;
use BitWasp\TrezorProto\ButtonRequestType;
use BitWasp\TrezorProto\DebugLinkDecision;
use BitWasp\TrezorProto\DebugLinkGetState;
use BitWasp\TrezorProto\DebugLinkStop;
use BitWasp\TrezorProto\Success;

class DebugButtonAck extends ButtonAck
{
private $debug;

public function __construct(Session $debugSession)
{
$this->debug = $debugSession;
}

public function acknowledge(Session $session, ButtonRequest $request, ButtonRequestType $expectedType)
{
$theirType = $request->getCode();
if ($theirType->value() !== $expectedType->value()) {
throw new \RuntimeException("Unexpected button request (expected: {$expectedType->name()}, got {$theirType->name()})");
}

fwrite(STDERR, microtime() . " - debugButtonAck.sending button ack (async)\n");
$t1 = microtime(true);
$ack = new \BitWasp\TrezorProto\ButtonAck();

$decision = new DebugLinkDecision();
$decision->setYesNo(true);

fwrite(STDERR, microtime() . " - debugButtonAck.sending DECISION (async)\n");
$t1 = microtime(true);

$success = $session->sendMessageAsync(Message::buttonAck($ack));
$debug = $this->debug->sendMessageAsync(DebugMessage::decision($decision), [
'Connection' => 'close',
]);

fwrite(STDERR, microtime() . " - debugButtonAck.DECISION async took ".(microtime(true)-$t1).PHP_EOL);

fwrite(STDERR, "create promise");
$val = null;
$success->then(function (Success $success) use (&$val) {
fwrite(STDERR, "success resolved");
$val = $success;
});
fwrite(STDERR, "wait for success");
$success->wait(true);
fwrite(STDERR, "DONE waiting");

return $val;
}
}
24 changes: 24 additions & 0 deletions src/Device/Button/HumanButtonAck.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace BitWasp\Trezor\Device\Button;

use BitWasp\Trezor\Bridge\Session;
use BitWasp\Trezor\Device\Message;
use BitWasp\TrezorProto\ButtonRequest;
use BitWasp\TrezorProto\ButtonRequestType;

class HumanButtonAck extends ButtonAck
{
public function acknowledge(Session $session, ButtonRequest $request, ButtonRequestType $expectedType)
{
$theirType = $request->getCode();
if ($theirType->value() !== $expectedType->value()) {
throw new \RuntimeException("Unexpected button request (expected: {$expectedType->name()}, got {$theirType->name()})");
}

echo "sending button ack\n";
return $session->sendMessage(Message::buttonAck(new \BitWasp\TrezorProto\ButtonAck()));
}
}
1 change: 0 additions & 1 deletion src/Device/Command/DeviceService.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ protected function provideCurrentPin(PinMatrixRequest $proto, CurrentPinInputInt
return Message::pinMatrixAck($pinMatrixAck);
}


protected function provideCurrentPassphrase(CurrentPassphraseInputInterface $passphraseInput): Message
{
$passphraseAck = new PassphraseAck();
Expand Down
43 changes: 43 additions & 0 deletions src/Device/Command/LoadDeviceService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

namespace BitWasp\Trezor\Device\Command;

use BitWasp\Trezor\Bridge\Session;
use BitWasp\Trezor\Device\Button\ButtonAck;
use BitWasp\Trezor\Device\Exception\UnexpectedResultException;
use BitWasp\Trezor\Device\Message;
use BitWasp\TrezorProto;

class LoadDeviceService extends DeviceService
{
private $ack;

public function __construct(ButtonAck $buttonAck)
{
$this->ack = $buttonAck;
}

public function call(
Session $session,
TrezorProto\LoadDevice $loadDevice
): TrezorProto\Success {

fwrite(STDERR, "loadService.sending load device\n");
$proto = $session->sendMessage(Message::loadDevice($loadDevice));
fwrite(STDERR, "loadService.response for load device\n");

if ($proto instanceof TrezorProto\ButtonRequest) {
fwrite(STDERR, "loadService.send button ack\n");
$proto = $this->ack->acknowledge($session, $proto, TrezorProto\ButtonRequestType::ButtonRequest_ProtectCall());
fwrite(STDERR, "loadService.response for ack device\n");
}

if (!($proto instanceof TrezorProto\Success)) {
throw new UnexpectedResultException("Unexpected response, expecting Success, got " . get_class($proto));
}
fwrite(STDERR, "done\n");
return $proto;
}
}
44 changes: 44 additions & 0 deletions src/Device/DebugMessage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace BitWasp\Trezor\Device;

use BitWasp\TrezorProto\DebugLinkDecision;
use BitWasp\TrezorProto\DebugLinkGetState;
use BitWasp\TrezorProto\DebugLinkMemoryRead;
use BitWasp\TrezorProto\DebugLinkStop;
use BitWasp\TrezorProto\MessageType;

class DebugMessage extends MessageBase
{
public static function getState(DebugLinkGetState $getState): self
{
return new self(
MessageType::MessageType_DebugLinkGetState(),
$getState
);
}
public static function stop(DebugLinkStop $stop)
{
return new self(
MessageType::MessageType_DebugLinkStop(),
$stop
);
}
public static function decision(DebugLinkDecision $decision)
{
return new self(
MessageType::MessageType_DebugLinkDecision(),
$decision
);
}

public static function memoryRead(DebugLinkMemoryRead $memoryRead): self
{
return new self(
MessageType::MessageType_DebugLinkMemoryRead(),
$memoryRead
);
}
}
Loading

0 comments on commit 0770d8a

Please sign in to comment.