diff --git a/apduWrapper.go b/apduWrapper.go index 49d6ab2..4e46353 100644 --- a/apduWrapper.go +++ b/apduWrapper.go @@ -30,11 +30,18 @@ const ( var codec = binary.BigEndian +const ( + ErrMsgPacketSize = "packet size must be at least 3" + ErrMsgInvalidChannel = "invalid channel" + ErrMsgInvalidTag = "invalid tag" + ErrMsgWrongSequenceIdx = "wrong sequenceIdx" +) + var ( - ErrPacketSize = errors.New("packet size must be at least 3") - ErrInvalidChannel = errors.New("invalid channel") - ErrInvalidTag = errors.New("invalid tag") - ErrWrongSequenceIdx = errors.New("wrong sequenceIdx") + ErrPacketSize = errors.New(ErrMsgPacketSize) + ErrInvalidChannel = errors.New(ErrMsgInvalidChannel) + ErrInvalidTag = errors.New(ErrMsgInvalidTag) + ErrWrongSequenceIdx = errors.New(ErrMsgWrongSequenceIdx) ) // ErrorMessage returns a human-readable error message for a given APDU error code. diff --git a/ledger.go b/ledger.go index 02563ef..28df9a4 100644 --- a/ledger.go +++ b/ledger.go @@ -16,12 +16,14 @@ package ledger_go +// LedgerAdmin defines the interface for managing Ledger devices. type LedgerAdmin interface { CountDevices() int ListDevices() ([]string, error) Connect(deviceIndex int) (LedgerDevice, error) } +// LedgerDevice defines the interface for interacting with a Ledger device. type LedgerDevice interface { Exchange(command []byte) ([]byte, error) Close() error diff --git a/ledger_hid.go b/ledger_hid.go index f8f83d7..7718479 100644 --- a/ledger_hid.go +++ b/ledger_hid.go @@ -59,27 +59,30 @@ func NewLedgerAdmin() *LedgerAdminHID { func (admin *LedgerAdminHID) ListDevices() ([]string, error) { devices := hid.Enumerate(0, 0) - if len(devices) == 0 { - fmt.Printf("No devices. Ledger LOCKED OR Other Program/Web Browser may have control of device.") + log.Println("No devices. Ledger LOCKED OR Other Program/Web Browser may have control of device.") } for _, d := range devices { - fmt.Printf("============ %s\n", d.Path) - fmt.Printf("VendorID : %x\n", d.VendorID) - fmt.Printf("ProductID : %x\n", d.ProductID) - fmt.Printf("Release : %x\n", d.Release) - fmt.Printf("Serial : %x\n", d.Serial) - fmt.Printf("Manufacturer : %s\n", d.Manufacturer) - fmt.Printf("Product : %s\n", d.Product) - fmt.Printf("UsagePage : %x\n", d.UsagePage) - fmt.Printf("Usage : %x\n", d.Usage) - fmt.Printf("\n") + logDeviceInfo(d) } return []string{}, nil } +func logDeviceInfo(d hid.DeviceInfo) { + log.Printf("============ %s\n", d.Path) + log.Printf("VendorID : %x\n", d.VendorID) + log.Printf("ProductID : %x\n", d.ProductID) + log.Printf("Release : %x\n", d.Release) + log.Printf("Serial : %x\n", d.Serial) + log.Printf("Manufacturer : %s\n", d.Manufacturer) + log.Printf("Product : %s\n", d.Product) + log.Printf("UsagePage : %x\n", d.UsagePage) + log.Printf("Usage : %x\n", d.Usage) + log.Printf("\n") +} + func isLedgerDevice(d hid.DeviceInfo) bool { deviceFound := d.UsagePage == UsagePageLedgerNanoS // Workarounds for possible empty usage pages diff --git a/ledger_mock.go b/ledger_mock.go index a16eb10..af1857f 100644 --- a/ledger_mock.go +++ b/ledger_mock.go @@ -24,10 +24,12 @@ import ( "fmt" ) +const mockDeviceName = "Mock device" + type LedgerAdminMock struct{} type LedgerDeviceMock struct { - commands map[string][]byte + commands map[string]string } func NewLedgerAdmin() *LedgerAdminMock { @@ -35,8 +37,7 @@ func NewLedgerAdmin() *LedgerAdminMock { } func (admin *LedgerAdminMock) ListDevices() ([]string, error) { - x := []string{"Mock device"} - return x, nil + return []string{mockDeviceName}, nil } func (admin *LedgerAdminMock) CountDevices() int { @@ -49,8 +50,8 @@ func (admin *LedgerAdminMock) Connect(deviceIndex int) (*LedgerDeviceMock, error func NewLedgerDeviceMock() *LedgerDeviceMock { return &LedgerDeviceMock{ - commands: map[string][]byte{ - "e001000000": []byte{0x31, 0x10, 0x00, 0x04, 0x08, 0x53, 0x70, 0x65, 0x63, 0x75, 0x6c, 0x6f, 0x73, 0x00, 0x0b, 0x53, 0x70, 0x65, 0x63, 0x75, 0x6c, 0x6f, 0x73, 0x4d, 0x43, 0x55}, + commands: map[string]string{ + "e001000000": "311000040853706563756c6f73000b53706563756c6f734d4355", }, } } @@ -58,7 +59,7 @@ func NewLedgerDeviceMock() *LedgerDeviceMock { func (ledger *LedgerDeviceMock) Exchange(command []byte) ([]byte, error) { hexCommand := hex.EncodeToString(command) if reply, ok := ledger.commands[hexCommand]; ok { - return reply, nil + return hex.DecodeString(reply) } return nil, fmt.Errorf("unknown command: %s", hexCommand) } diff --git a/ledger_test.go b/ledger_test.go index a117864..6f99623 100644 --- a/ledger_test.go +++ b/ledger_test.go @@ -27,13 +27,31 @@ import ( var mux sync.Mutex +func TestLedger(t *testing.T) { + tests := []struct { + name string + test func(t *testing.T) + }{ + {"CountLedgerDevices", Test_CountLedgerDevices}, + {"ListDevices", TestListDevices}, + {"GetLedger", Test_GetLedger}, + {"BasicExchange", Test_BasicExchange}, + {"Connect", TestConnect}, + {"GetVersion", TestGetVersion}, + } + + for _, tt := range tests { + t.Run(tt.name, tt.test) + } +} + func Test_CountLedgerDevices(t *testing.T) { mux.Lock() defer mux.Unlock() ledgerAdmin := NewLedgerAdmin() count := ledgerAdmin.CountDevices() - assert.True(t, count > 0) + require.True(t, count > 0) } func TestListDevices(t *testing.T) { @@ -121,4 +139,4 @@ func TestGetVersion(t *testing.T) { assert.NoError(t, err) assert.NotEmpty(t, response, "Response should not be empty") -} \ No newline at end of file +} diff --git a/ledger_zemu.go b/ledger_zemu.go index 5a5183c..db8a026 100644 --- a/ledger_zemu.go +++ b/ledger_zemu.go @@ -27,6 +27,11 @@ import ( "google.golang.org/grpc" ) +const ( + defaultGrpcURL = "localhost" + defaultGrpcPort = "3002" +) + type LedgerAdminZemu struct { grpcURL string grpcPort string @@ -39,9 +44,8 @@ type LedgerDeviceZemu struct { func NewLedgerAdmin() *LedgerAdminZemu { return &LedgerAdminZemu{ - //TODO get this from flag value or from Zemu response - grpcURL: "localhost", - grpcPort: "3002", + grpcURL: defaultGrpcURL, + grpcPort: defaultGrpcPort, } }