forked from Zondax/ledger-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ledger_zemu.go
114 lines (89 loc) · 2.85 KB
/
ledger_zemu.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//+build ledger_zemu
/*******************************************************************************
* (c) 2018 - 2022 ZondaX AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
package ledger_go
import (
"context"
"fmt"
"google.golang.org/grpc"
)
type LedgerAdminZemu struct {
grpcURL string
grpcPort string
}
type LedgerDeviceZemu struct {
connection *grpc.ClientConn
client ZemuCommandClient
}
func NewLedgerAdmin() *LedgerAdminZemu {
return &LedgerAdminZemu{
//TODO get this from flag value or from Zemu response
grpcURL: "localhost",
grpcPort: "3002",
}
}
func (admin *LedgerAdminZemu) ListDevices() ([]string, error) {
// It does not make sense for zemu devices
x := []string{"Zemu device"}
return x, nil
}
func (admin *LedgerAdminZemu) CountDevices() int {
// TODO: Always 1, maybe zero if zemu has not elf??
return 1
}
func (admin *LedgerAdminZemu) Connect(deviceIndex int) (*LedgerDeviceZemu, error) {
serverAddr := admin.grpcURL + ":" + admin.grpcPort
//TODO: check Dial flags
conn, err := grpc.Dial(serverAddr, grpc.WithInsecure())
if err != nil {
err = fmt.Errorf("could not connect to rpc server at %q : %q", serverAddr, err)
return &LedgerDeviceZemu{}, err
}
client := NewZemuCommandClient(conn)
return &LedgerDeviceZemu{connection: conn, client: client}, nil
}
func (ledger *LedgerDeviceZemu) Exchange(command []byte) ([]byte, error) {
if len(command) < 5 {
return nil, fmt.Errorf("APDU commands should not be smaller than 5")
}
if (byte)(len(command)-5) != command[4] {
return nil, fmt.Errorf("APDU[data length] mismatch")
}
// Send to Zemu and return reply or error
r, err := ledger.client.Exchange(context.Background(), &ExchangeRequest{Command: command})
if err != nil {
err = fmt.Errorf("could not call rpc service: %q", err)
return []byte{}, err
}
response := r.Reply
if len(response) < 2 {
return nil, fmt.Errorf("len(response) < 2")
}
swOffset := len(response) - 2
sw := codec.Uint16(response[swOffset:])
if sw != 0x9000 {
return response[:swOffset], fmt.Errorf("return code with error")
}
return response[:swOffset], nil
}
func (ledger *LedgerDeviceZemu) Close() error {
err := ledger.connection.Close()
if err != nil {
err = fmt.Errorf("could not close connection to rpc server")
return err
}
return nil
}