@@ -19,15 +19,12 @@ package console
19
19
import (
20
20
"encoding/json"
21
21
"errors"
22
- "fmt"
23
22
"io"
24
23
"reflect"
25
24
"strings"
26
25
"time"
27
26
28
27
"github.com/dop251/goja"
29
- "github.com/ethereum/go-ethereum/accounts/scwallet"
30
- "github.com/ethereum/go-ethereum/accounts/usbwallet"
31
28
"github.com/ethereum/go-ethereum/common/hexutil"
32
29
"github.com/ethereum/go-ethereum/console/prompt"
33
30
"github.com/ethereum/go-ethereum/internal/jsre"
@@ -51,268 +48,6 @@ func newBridge(client *rpc.Client, prompter prompt.UserPrompter, printer io.Writ
51
48
}
52
49
}
53
50
54
- func getJeth (vm * goja.Runtime ) * goja.Object {
55
- jeth := vm .Get ("jeth" )
56
- if jeth == nil {
57
- panic (vm .ToValue ("jeth object does not exist" ))
58
- }
59
- return jeth .ToObject (vm )
60
- }
61
-
62
- // NewAccount is a wrapper around the personal.newAccount RPC method that uses a
63
- // non-echoing password prompt to acquire the passphrase and executes the original
64
- // RPC method (saved in jeth.newAccount) with it to actually execute the RPC call.
65
- func (b * bridge ) NewAccount (call jsre.Call ) (goja.Value , error ) {
66
- var (
67
- password string
68
- confirm string
69
- err error
70
- )
71
- switch {
72
- // No password was specified, prompt the user for it
73
- case len (call .Arguments ) == 0 :
74
- if password , err = b .prompter .PromptPassword ("Passphrase: " ); err != nil {
75
- return nil , err
76
- }
77
- if confirm , err = b .prompter .PromptPassword ("Repeat passphrase: " ); err != nil {
78
- return nil , err
79
- }
80
- if password != confirm {
81
- return nil , errors .New ("passwords don't match" )
82
- }
83
- // A single string password was specified, use that
84
- case len (call .Arguments ) == 1 && call .Argument (0 ).ToString () != nil :
85
- password = call .Argument (0 ).ToString ().String ()
86
- default :
87
- return nil , errors .New ("expected 0 or 1 string argument" )
88
- }
89
- // Password acquired, execute the call and return
90
- newAccount , callable := goja .AssertFunction (getJeth (call .VM ).Get ("newAccount" ))
91
- if ! callable {
92
- return nil , errors .New ("jeth.newAccount is not callable" )
93
- }
94
- ret , err := newAccount (goja .Null (), call .VM .ToValue (password ))
95
- if err != nil {
96
- return nil , err
97
- }
98
- return ret , nil
99
- }
100
-
101
- // OpenWallet is a wrapper around personal.openWallet which can interpret and
102
- // react to certain error messages, such as the Trezor PIN matrix request.
103
- func (b * bridge ) OpenWallet (call jsre.Call ) (goja.Value , error ) {
104
- // Make sure we have a wallet specified to open
105
- if call .Argument (0 ).ToObject (call .VM ).ClassName () != "String" {
106
- return nil , errors .New ("first argument must be the wallet URL to open" )
107
- }
108
- wallet := call .Argument (0 )
109
-
110
- var passwd goja.Value
111
- if goja .IsUndefined (call .Argument (1 )) || goja .IsNull (call .Argument (1 )) {
112
- passwd = call .VM .ToValue ("" )
113
- } else {
114
- passwd = call .Argument (1 )
115
- }
116
- // Open the wallet and return if successful in itself
117
- openWallet , callable := goja .AssertFunction (getJeth (call .VM ).Get ("openWallet" ))
118
- if ! callable {
119
- return nil , errors .New ("jeth.openWallet is not callable" )
120
- }
121
- val , err := openWallet (goja .Null (), wallet , passwd )
122
- if err == nil {
123
- return val , nil
124
- }
125
-
126
- // Wallet open failed, report error unless it's a PIN or PUK entry
127
- switch {
128
- case strings .HasSuffix (err .Error (), usbwallet .ErrTrezorPINNeeded .Error ()):
129
- val , err = b .readPinAndReopenWallet (call )
130
- if err == nil {
131
- return val , nil
132
- }
133
- val , err = b .readPassphraseAndReopenWallet (call )
134
- if err != nil {
135
- return nil , err
136
- }
137
-
138
- case strings .HasSuffix (err .Error (), scwallet .ErrPairingPasswordNeeded .Error ()):
139
- // PUK input requested, fetch from the user and call open again
140
- input , err := b .prompter .PromptPassword ("Please enter the pairing password: " )
141
- if err != nil {
142
- return nil , err
143
- }
144
- passwd = call .VM .ToValue (input )
145
- if val , err = openWallet (goja .Null (), wallet , passwd ); err != nil {
146
- if ! strings .HasSuffix (err .Error (), scwallet .ErrPINNeeded .Error ()) {
147
- return nil , err
148
- }
149
- // PIN input requested, fetch from the user and call open again
150
- input , err := b .prompter .PromptPassword ("Please enter current PIN: " )
151
- if err != nil {
152
- return nil , err
153
- }
154
- if val , err = openWallet (goja .Null (), wallet , call .VM .ToValue (input )); err != nil {
155
- return nil , err
156
- }
157
- }
158
-
159
- case strings .HasSuffix (err .Error (), scwallet .ErrPINUnblockNeeded .Error ()):
160
- // PIN unblock requested, fetch PUK and new PIN from the user
161
- var pukpin string
162
- input , err := b .prompter .PromptPassword ("Please enter current PUK: " )
163
- if err != nil {
164
- return nil , err
165
- }
166
- pukpin = input
167
- input , err = b .prompter .PromptPassword ("Please enter new PIN: " )
168
- if err != nil {
169
- return nil , err
170
- }
171
- pukpin += input
172
-
173
- if val , err = openWallet (goja .Null (), wallet , call .VM .ToValue (pukpin )); err != nil {
174
- return nil , err
175
- }
176
-
177
- case strings .HasSuffix (err .Error (), scwallet .ErrPINNeeded .Error ()):
178
- // PIN input requested, fetch from the user and call open again
179
- input , err := b .prompter .PromptPassword ("Please enter current PIN: " )
180
- if err != nil {
181
- return nil , err
182
- }
183
- if val , err = openWallet (goja .Null (), wallet , call .VM .ToValue (input )); err != nil {
184
- return nil , err
185
- }
186
-
187
- default :
188
- // Unknown error occurred, drop to the user
189
- return nil , err
190
- }
191
- return val , nil
192
- }
193
-
194
- func (b * bridge ) readPassphraseAndReopenWallet (call jsre.Call ) (goja.Value , error ) {
195
- wallet := call .Argument (0 )
196
- input , err := b .prompter .PromptPassword ("Please enter your passphrase: " )
197
- if err != nil {
198
- return nil , err
199
- }
200
- openWallet , callable := goja .AssertFunction (getJeth (call .VM ).Get ("openWallet" ))
201
- if ! callable {
202
- return nil , errors .New ("jeth.openWallet is not callable" )
203
- }
204
- return openWallet (goja .Null (), wallet , call .VM .ToValue (input ))
205
- }
206
-
207
- func (b * bridge ) readPinAndReopenWallet (call jsre.Call ) (goja.Value , error ) {
208
- wallet := call .Argument (0 )
209
- // Trezor PIN matrix input requested, display the matrix to the user and fetch the data
210
- fmt .Fprintf (b .printer , "Look at the device for number positions\n \n " )
211
- fmt .Fprintf (b .printer , "7 | 8 | 9\n " )
212
- fmt .Fprintf (b .printer , "--+---+--\n " )
213
- fmt .Fprintf (b .printer , "4 | 5 | 6\n " )
214
- fmt .Fprintf (b .printer , "--+---+--\n " )
215
- fmt .Fprintf (b .printer , "1 | 2 | 3\n \n " )
216
-
217
- input , err := b .prompter .PromptPassword ("Please enter current PIN: " )
218
- if err != nil {
219
- return nil , err
220
- }
221
- openWallet , callable := goja .AssertFunction (getJeth (call .VM ).Get ("openWallet" ))
222
- if ! callable {
223
- return nil , errors .New ("jeth.openWallet is not callable" )
224
- }
225
- return openWallet (goja .Null (), wallet , call .VM .ToValue (input ))
226
- }
227
-
228
- // UnlockAccount is a wrapper around the personal.unlockAccount RPC method that
229
- // uses a non-echoing password prompt to acquire the passphrase and executes the
230
- // original RPC method (saved in jeth.unlockAccount) with it to actually execute
231
- // the RPC call.
232
- func (b * bridge ) UnlockAccount (call jsre.Call ) (goja.Value , error ) {
233
- if len (call .Arguments ) < 1 {
234
- return nil , errors .New ("usage: unlockAccount(account, [ password, duration ])" )
235
- }
236
-
237
- account := call .Argument (0 )
238
- // Make sure we have an account specified to unlock.
239
- if goja .IsUndefined (account ) || goja .IsNull (account ) || account .ExportType ().Kind () != reflect .String {
240
- return nil , errors .New ("first argument must be the account to unlock" )
241
- }
242
-
243
- // If password is not given or is the null value, prompt the user for it.
244
- var passwd goja.Value
245
- if goja .IsUndefined (call .Argument (1 )) || goja .IsNull (call .Argument (1 )) {
246
- fmt .Fprintf (b .printer , "Unlock account %s\n " , account )
247
- input , err := b .prompter .PromptPassword ("Passphrase: " )
248
- if err != nil {
249
- return nil , err
250
- }
251
- passwd = call .VM .ToValue (input )
252
- } else {
253
- if call .Argument (1 ).ExportType ().Kind () != reflect .String {
254
- return nil , errors .New ("password must be a string" )
255
- }
256
- passwd = call .Argument (1 )
257
- }
258
-
259
- // Third argument is the duration how long the account should be unlocked.
260
- duration := goja .Null ()
261
- if ! goja .IsUndefined (call .Argument (2 )) && ! goja .IsNull (call .Argument (2 )) {
262
- if ! isNumber (call .Argument (2 )) {
263
- return nil , errors .New ("unlock duration must be a number" )
264
- }
265
- duration = call .Argument (2 )
266
- }
267
-
268
- // Send the request to the backend and return.
269
- unlockAccount , callable := goja .AssertFunction (getJeth (call .VM ).Get ("unlockAccount" ))
270
- if ! callable {
271
- return nil , errors .New ("jeth.unlockAccount is not callable" )
272
- }
273
- return unlockAccount (goja .Null (), account , passwd , duration )
274
- }
275
-
276
- // Sign is a wrapper around the personal.sign RPC method that uses a non-echoing password
277
- // prompt to acquire the passphrase and executes the original RPC method (saved in
278
- // jeth.sign) with it to actually execute the RPC call.
279
- func (b * bridge ) Sign (call jsre.Call ) (goja.Value , error ) {
280
- if nArgs := len (call .Arguments ); nArgs < 2 {
281
- return nil , errors .New ("usage: sign(message, account, [ password ])" )
282
- }
283
- var (
284
- message = call .Argument (0 )
285
- account = call .Argument (1 )
286
- passwd = call .Argument (2 )
287
- )
288
-
289
- if goja .IsUndefined (message ) || message .ExportType ().Kind () != reflect .String {
290
- return nil , errors .New ("first argument must be the message to sign" )
291
- }
292
- if goja .IsUndefined (account ) || account .ExportType ().Kind () != reflect .String {
293
- return nil , errors .New ("second argument must be the account to sign with" )
294
- }
295
-
296
- // if the password is not given or null ask the user and ensure password is a string
297
- if goja .IsUndefined (passwd ) || goja .IsNull (passwd ) {
298
- fmt .Fprintf (b .printer , "Give password for account %s\n " , account )
299
- input , err := b .prompter .PromptPassword ("Password: " )
300
- if err != nil {
301
- return nil , err
302
- }
303
- passwd = call .VM .ToValue (input )
304
- } else if passwd .ExportType ().Kind () != reflect .String {
305
- return nil , errors .New ("third argument must be the password to unlock the account" )
306
- }
307
-
308
- // Send the request to the backend and return
309
- sign , callable := goja .AssertFunction (getJeth (call .VM ).Get ("sign" ))
310
- if ! callable {
311
- return nil , errors .New ("jeth.sign is not callable" )
312
- }
313
- return sign (goja .Null (), message , account , passwd )
314
- }
315
-
316
51
// Sleep will block the console for the specified number of seconds.
317
52
func (b * bridge ) Sleep (call jsre.Call ) (goja.Value , error ) {
318
53
if nArgs := len (call .Arguments ); nArgs < 1 {
0 commit comments