From 73d56fcecc8bcc061e7b7595a0948a18fd9941f9 Mon Sep 17 00:00:00 2001 From: cdcdx Date: Wed, 3 May 2023 00:40:30 +0800 Subject: [PATCH 1/8] # wallet-security-solution - Wallet mark management: ```shell lotus wallet mark add ##Add/update wallet mark lotus wallet mark del ##Delete wallet mark lotus wallet mark clear ##clear wallet mark ``` - Wallet password management: ```shell lotus wallet passwd add ##Add password lotus wallet passwd reset ##Change password lotus wallet passwd clear ##Clear password lotus wallet encrypt ##Ordinary wallet->encrypted wallet lotus wallet decrypt ##encryption wallet->ordinary wallet ``` --- api/api_full.go | 4 + api/api_wallet.go | 3 + api/api_wallet_ext.go | 44 ++ api/docgen/docgen.go | 5 + api/mocks/mock_full.go | 16 + api/proxy_gen.go | 27 + api/v0api/full.go | 4 + api/v0api/proxy_gen.go | 14 + api/v0api/v0mocks/mock_full.go | 16 + build/openrpc/full.json.gz | Bin 33316 -> 33455 bytes chain/wallet/key/key.go | 20 +- chain/wallet/key/key_ext.go | 104 ++++ chain/wallet/ledger/ledger.go | 6 + chain/wallet/multi_ext.go | 116 ++++ chain/wallet/wallet.go | 31 +- chain/wallet/wallet_aes.go | 230 ++++++++ chain/wallet/wallet_common.go | 51 ++ chain/wallet/wallet_ext.go | 566 ++++++++++++++++++++ cli/cmd.go | 6 + cli/send.go | 33 ++ cli/wallet.go | 162 +++++- cli/wallet_ext.go | 529 ++++++++++++++++++ cmd/lotus-wallet/interactive.go | 15 + cmd/lotus-wallet/logged.go | 6 + cmd/lotus-wallet/main.go | 4 +- cmd/lotus/daemon.go | 15 + documentation/en/api-v0-methods.md | 20 + documentation/en/api-v1-unstable-methods.md | 20 + 28 files changed, 2047 insertions(+), 20 deletions(-) create mode 100644 api/api_wallet_ext.go create mode 100644 chain/wallet/key/key_ext.go create mode 100644 chain/wallet/multi_ext.go create mode 100644 chain/wallet/wallet_aes.go create mode 100644 chain/wallet/wallet_common.go create mode 100644 chain/wallet/wallet_ext.go create mode 100644 cli/wallet_ext.go diff --git a/api/api_full.go b/api/api_full.go index 1f7c38edf80..f71af54766c 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -330,6 +330,10 @@ type FullNode interface { // WalletValidateAddress validates whether a given string can be decoded as a well-formed address WalletValidateAddress(context.Context, string) (address.Address, error) //perm:read + // wallet-security FullNodeExt WalletCustomMethod + // WalletCustomMethod wallet extension operation + WalletCustomMethod(context.Context, WalletMethod, []interface{}) (interface{}, error) //perm:admin + // Other // MethodGroup: Client diff --git a/api/api_wallet.go b/api/api_wallet.go index 973aaaf6d85..daf70af965e 100644 --- a/api/api_wallet.go +++ b/api/api_wallet.go @@ -44,4 +44,7 @@ type Wallet interface { WalletExport(context.Context, address.Address) (*types.KeyInfo, error) //perm:admin WalletImport(context.Context, *types.KeyInfo) (address.Address, error) //perm:admin WalletDelete(context.Context, address.Address) error //perm:admin + + // wallet-security WalletExt WalletCustomMethod + WalletCustomMethod(context.Context, WalletMethod, []interface{}) (interface{}, error) //perm:admin } diff --git a/api/api_wallet_ext.go b/api/api_wallet_ext.go new file mode 100644 index 00000000000..aae18de7343 --- /dev/null +++ b/api/api_wallet_ext.go @@ -0,0 +1,44 @@ +package api + +import ( + "github.com/filecoin-project/go-address" +) + +// wallet-security AddrListEncrypt stuct +type AddrListEncrypt struct { + Addr address.Address + Encrypt bool +} +type WalletMethod int64 + +const ( + Unknown WalletMethod = 0 + WalletListForEnc WalletMethod = 1 + WalletExportForEnc WalletMethod = 2 + WalletDeleteForEnc WalletMethod = 3 + WalletAddPasswd WalletMethod = 4 + WalletResetPasswd WalletMethod = 5 + WalletClearPasswd WalletMethod = 6 + WalletCheckPasswd WalletMethod = 7 + WalletEncrypt WalletMethod = 8 + WalletDecrypt WalletMethod = 9 + WalletIsEncrypt WalletMethod = 10 +) + +var WalletMethodStr = map[WalletMethod]string{ + Unknown: "Unknown", + WalletListForEnc: "WalletListForEnc", + WalletExportForEnc: "WalletExportForEnc", + WalletDeleteForEnc: "WalletDeleteForEnc", + WalletAddPasswd: "WalletAddPasswd", + WalletResetPasswd: "WalletResetPasswd", + WalletClearPasswd: "WalletClearPasswd", + WalletCheckPasswd: "WalletCheckPasswd", + WalletEncrypt: "WalletEncrypt", + WalletDecrypt: "WalletDecrypt", + WalletIsEncrypt: "WalletIsEncrypt", +} + +func (w WalletMethod) String() string { + return WalletMethodStr[w] +} diff --git a/api/docgen/docgen.go b/api/docgen/docgen.go index 0e97997a6d8..4a991c57f55 100644 --- a/api/docgen/docgen.go +++ b/api/docgen/docgen.go @@ -482,6 +482,11 @@ func ExampleValue(method string, t, parent reflect.Type) interface{} { } case reflect.Interface: return struct{}{} + // wallet-security fix docgen build err + case reflect.Int64: + return 0 + case reflect.Map: + return make(map[string]string) } panic(fmt.Sprintf("No example value for type: %s (method '%s')", t, method)) diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index 370a213a0c1..fc1bf586c68 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -4128,6 +4128,22 @@ func (mr *MockFullNodeMockRecorder) WalletVerify(arg0, arg1, arg2, arg3 interfac return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletVerify", reflect.TypeOf((*MockFullNode)(nil).WalletVerify), arg0, arg1, arg2, arg3) } +// wallet-security MockFullNode WalletCustomMethod +// WalletCustomMethod mocks base method +func (m *MockFullNode) WalletCustomMethod(arg0 context.Context, arg1 api.WalletMethod, arg2 []interface{}) (interface{}, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WalletCustomMethod", arg0, arg1, arg2) + ret0, _ := ret[0].(interface{}) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// WalletCustomMethod indicates an expected call of WalletCustomMethod +func (mr *MockFullNodeMockRecorder) WalletCustomMethod(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletCustomMethod", reflect.TypeOf((*MockFullNode)(nil).WalletCustomMethod), arg0, arg1, arg2) +} + // Web3ClientVersion mocks base method. func (m *MockFullNode) Web3ClientVersion(arg0 context.Context) (string, error) { m.ctrl.T.Helper() diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 70579af1a47..5d217d8e341 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -608,6 +608,9 @@ type FullNodeMethods struct { WalletVerify func(p0 context.Context, p1 address.Address, p2 []byte, p3 *crypto.Signature) (bool, error) `perm:"read"` + // wallet-security FullNodeStructExt WalletCustomMethod + WalletCustomMethod func(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) `perm:"admin"` + Web3ClientVersion func(p0 context.Context) (string, error) `perm:"read"` } @@ -1150,6 +1153,9 @@ type WalletMethods struct { WalletNew func(p0 context.Context, p1 types.KeyType) (address.Address, error) `perm:"admin"` WalletSign func(p0 context.Context, p1 address.Address, p2 []byte, p3 MsgMeta) (*crypto.Signature, error) `perm:"admin"` + + // wallet-security WalletStructExt WalletCustomMethod + WalletCustomMethod func(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) `perm:"admin"` } type WalletStub struct { @@ -4021,6 +4027,16 @@ func (s *FullNodeStub) WalletVerify(p0 context.Context, p1 address.Address, p2 [ return false, ErrNotSupported } +func (s *FullNodeStruct) WalletCustomMethod(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) { + if s.Internal.WalletCustomMethod == nil { + return nil, ErrNotSupported + } + return s.Internal.WalletCustomMethod(p0, p1, p2) +} +func (s *FullNodeStub) WalletCustomMethod(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) { + return nil, ErrNotSupported +} + func (s *FullNodeStruct) Web3ClientVersion(p0 context.Context) (string, error) { if s.Internal.Web3ClientVersion == nil { return "", ErrNotSupported @@ -6705,6 +6721,17 @@ func (s *WalletStub) WalletSign(p0 context.Context, p1 address.Address, p2 []byt return nil, ErrNotSupported } +// wallet-security WalletStruct WalletCustomMethod +func (s *WalletStruct) WalletCustomMethod(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) { + if s.Internal.WalletCustomMethod == nil { + return nil, ErrNotSupported + } + return s.Internal.WalletCustomMethod(p0, p1, p2) +} +func (s *WalletStub) WalletCustomMethod(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) { + return nil, ErrNotSupported +} + func (s *WorkerStruct) AddPiece(p0 context.Context, p1 storiface.SectorRef, p2 []abi.UnpaddedPieceSize, p3 abi.UnpaddedPieceSize, p4 storiface.Data) (storiface.CallID, error) { if s.Internal.AddPiece == nil { return *new(storiface.CallID), ErrNotSupported diff --git a/api/v0api/full.go b/api/v0api/full.go index 490cd73c839..29a84b822d0 100644 --- a/api/v0api/full.go +++ b/api/v0api/full.go @@ -305,6 +305,10 @@ type FullNode interface { // WalletValidateAddress validates whether a given string can be decoded as a well-formed address WalletValidateAddress(context.Context, string) (address.Address, error) //perm:read + // wallet-security FullNodeExt WalletCustomMethod + // WalletCustomMethod wallet extension operation + WalletCustomMethod(context.Context, api.WalletMethod, []interface{}) (interface{}, error) //perm:admin + // Other // MethodGroup: Client diff --git a/api/v0api/proxy_gen.go b/api/v0api/proxy_gen.go index 17a1ae84ae5..b1a88c54164 100644 --- a/api/v0api/proxy_gen.go +++ b/api/v0api/proxy_gen.go @@ -418,6 +418,10 @@ type FullNodeMethods struct { WalletValidateAddress func(p0 context.Context, p1 string) (address.Address, error) `perm:"read"` WalletVerify func(p0 context.Context, p1 address.Address, p2 []byte, p3 *crypto.Signature) (bool, error) `perm:"read"` + + // wallet-security FullNodeStructExt WalletCustomMethod + WalletCustomMethod func(p0 context.Context, p1 api.WalletMethod, p2 []interface{}) (interface{}, error) `perm:"admin"` + } type FullNodeStub struct { @@ -2575,6 +2579,16 @@ func (s *FullNodeStub) WalletVerify(p0 context.Context, p1 address.Address, p2 [ return false, ErrNotSupported } +func (s *FullNodeStruct) WalletCustomMethod(p0 context.Context, p1 api.WalletMethod, p2 []interface{}) (interface{}, error) { + if s.Internal.WalletCustomMethod == nil { + return nil, ErrNotSupported + } + return s.Internal.WalletCustomMethod(p0, p1, p2) +} +func (s *FullNodeStub) WalletCustomMethod(p0 context.Context, p1 api.WalletMethod, p2 []interface{}) (interface{}, error) { + return nil, ErrNotSupported +} + func (s *GatewayStruct) ChainGetBlockMessages(p0 context.Context, p1 cid.Cid) (*api.BlockMessages, error) { if s.Internal.ChainGetBlockMessages == nil { return nil, ErrNotSupported diff --git a/api/v0api/v0mocks/mock_full.go b/api/v0api/v0mocks/mock_full.go index 619f19d35bf..311471a7a33 100644 --- a/api/v0api/v0mocks/mock_full.go +++ b/api/v0api/v0mocks/mock_full.go @@ -3380,3 +3380,19 @@ func (mr *MockFullNodeMockRecorder) WalletVerify(arg0, arg1, arg2, arg3 interfac mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletVerify", reflect.TypeOf((*MockFullNode)(nil).WalletVerify), arg0, arg1, arg2, arg3) } + +// wallet-security MockFullNode WalletCustomMethod +// WalletCustomMethod mocks base method +func (m *MockFullNode) WalletCustomMethod(arg0 context.Context, arg1 api.WalletMethod, arg2 []interface{}) (interface{}, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WalletCustomMethod", arg0, arg1, arg2) + ret0, _ := ret[0].(interface{}) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// WalletCustomMethod indicates an expected call of WalletCustomMethod +func (mr *MockFullNodeMockRecorder) WalletCustomMethod(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletCustomMethod", reflect.TypeOf((*MockFullNode)(nil).WalletCustomMethod), arg0, arg1, arg2) +} diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index 1dfe553d5ab4ac09d6f4611415cf4f397e5d9057..c68072b2f031cf3d09140680fd8d6feb06817018 100644 GIT binary patch literal 33455 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 Y?f3rq=f^+)7XSeN|G3uS#rm`c0I^&wCIA2c delta 33275 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 F1^{qBXSDzT diff --git a/chain/wallet/key/key.go b/chain/wallet/key/key.go index 4220666108e..c7c6eb985e3 100644 --- a/chain/wallet/key/key.go +++ b/chain/wallet/key/key.go @@ -20,9 +20,16 @@ func GenerateKey(typ types.KeyType) (*Key, error) { if err != nil { return nil, err } + + // wallet-security 加密 + pk1, err := MakeByte(pk) + if err != nil { + return nil, err + } + ki := types.KeyInfo{ Type: typ, - PrivateKey: pk, + PrivateKey: pk1, //PrivateKey: pk, } return NewKey(ki) } @@ -39,8 +46,15 @@ func NewKey(keyinfo types.KeyInfo) (*Key, error) { KeyInfo: keyinfo, } - var err error - k.PublicKey, err = sigs.ToPublic(ActSigType(k.Type), k.PrivateKey) + // wallet-security 解密 + // var err error + // k.PublicKey, err = sigs.ToPublic(ActSigType(k.Type), k.PrivateKey) + pk, err := UnMakeByte(k.PrivateKey) + if err != nil { + return nil, err + } + k.PublicKey, err = sigs.ToPublic(ActSigType(k.Type), pk) + if err != nil { return nil, err } diff --git a/chain/wallet/key/key_ext.go b/chain/wallet/key/key_ext.go new file mode 100644 index 00000000000..d349aa0719a --- /dev/null +++ b/chain/wallet/key/key_ext.go @@ -0,0 +1,104 @@ +package key + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/hex" + "io" + + "golang.org/x/xerrors" +) + +var AddrPrefix = []byte{0xff, 0xff, 0xff, 0xff, 0xff} // addrPrefix = "/////" +var WalletPasswd string = "" +var PasswdPath string = "" + +// wallet-security AESEncrypt/AESDecrypt +// IsSetup check setup password for wallet +func IsSetup() bool { + return PasswdPath != "" +} + +// IsLock check setup lock for wallet +func IsLock() bool { + return WalletPasswd == "" +} + +func AESEncrypt(key, plaintext []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, xerrors.Errorf("passwd must 6 to 16 characters") + } + + ciphertext := make([]byte, aes.BlockSize+len(plaintext)) + iv := ciphertext[:aes.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return nil, err + } + + stream := cipher.NewCFBEncrypter(block, iv) + stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) + + return ciphertext, nil +} + +func AESDecrypt(key, ciphertext []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, xerrors.Errorf("passwd must 6 to 16 characters") + } else if len(ciphertext) < aes.BlockSize { + return nil, xerrors.Errorf("passwd must 6 to 16 characters") + } + + iv := ciphertext[:aes.BlockSize] + ciphertext = ciphertext[aes.BlockSize:] + stream := cipher.NewCFBDecrypter(block, iv) + stream.XORKeyStream(ciphertext, ciphertext) + + return ciphertext, nil +} + +func UnMakeByte(pk []byte) ([]byte, error) { + if !IsSetup() { + return pk, nil + } + + if !bytes.Equal(pk[:4], AddrPrefix) { + return pk, nil + } else if !IsLock() { + msg := make([]byte, len(pk)-4) + copy(msg, pk[4:]) + m5_passwd, _ := hex.DecodeString(WalletPasswd) + return AESDecrypt(m5_passwd, msg) + } + return nil, xerrors.Errorf("wallet is lock") +} + +func MakeByte(pk []byte) ([]byte, error) { + if !IsSetup() { + return pk, nil + } + + if IsLock() { + return nil, xerrors.Errorf("wallet is lock") + } + + m5_passwd, _ := hex.DecodeString(WalletPasswd) + msg, err := AESEncrypt(m5_passwd, pk) + if err != nil { + return nil, err + } + text := make([]byte, len(msg)+4) + copy(text[:4], AddrPrefix) + copy(text[4:], msg) + return text, nil +} + +func IsPrivateKeyEnc(pk []byte) bool { + if !IsSetup() || !bytes.Equal(pk[:4], AddrPrefix) { + return false + } + return true +} diff --git a/chain/wallet/ledger/ledger.go b/chain/wallet/ledger/ledger.go index 5279389de81..72545055881 100644 --- a/chain/wallet/ledger/ledger.go +++ b/chain/wallet/ledger/ledger.go @@ -227,6 +227,12 @@ func (lw LedgerWallet) WalletNew(ctx context.Context, t types.KeyType) (address. return lw.importKey(ctx, lki) } +// wallet-security LedgerWallet WalletCustomMethod +// WalletCustomMethod dont use this method for LedgerWallet +func (lw *LedgerWallet) WalletCustomMethod(ctx context.Context, meth api.WalletMethod, args []interface{}) (interface{}, error) { + return nil, xerrors.Errorf("LedgerWallet do not support extension operations for the time being") +} + func (lw *LedgerWallet) Get() api.Wallet { if lw == nil { return nil diff --git a/chain/wallet/multi_ext.go b/chain/wallet/multi_ext.go new file mode 100644 index 00000000000..48e61ea16ea --- /dev/null +++ b/chain/wallet/multi_ext.go @@ -0,0 +1,116 @@ +package wallet + +import ( + "context" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" +) + +// wallet-security MultiWallet func +// add MultiWallet Support extended +func (m MultiWallet) WalletListEncrypt(ctx context.Context) ([]api.AddrListEncrypt, error) { + out := make([]api.AddrListEncrypt, 0) + ws := nonNil(m.Remote, m.Ledger, m.Local) + for _, w := range ws { + if w == m.Local.Get() { + l, err := m.Local.WalletListEncrypt(ctx) + if err != nil { + return nil, err + } + out = append(out, l...) + } else { + l, err := w.WalletList(ctx) + if err != nil { + return nil, err + } + for _, v := range l { + out = append(out, api.AddrListEncrypt{ + Addr: v, + Encrypt: false, + }) + } + } + } + return out, nil +} +func (m MultiWallet) WalletExportEncrypt(ctx context.Context, address address.Address, passwd string) (*types.KeyInfo, error) { + w, err := m.find(ctx, address, m.Remote, m.Local) + if err != nil { + return nil, err + } + if w == nil { + return nil, xerrors.Errorf("key not found") + } + if w == m.Local.Get() { + return m.Local.WalletExportEncrypt(ctx, address, passwd) + } + return w.WalletExport(ctx, address) +} +func (m MultiWallet) WalletDeleteEncrypt(ctx context.Context, address address.Address, passwd string) error { + w, err := m.find(ctx, address, m.Remote, m.Ledger, m.Local) + if err != nil { + return err + } + if w == nil { + return nil + } + if w == m.Local.Get() { + return m.Local.WalletDeleteEncrypt(ctx, address, passwd) + } + return w.WalletDelete(ctx, address) +} + +// wallet-security MultiWallet WalletCustomMethod +// WalletCustomMethod dont use this method for MultiWallet +func (m MultiWallet) WalletCustomMethod(ctx context.Context, meth api.WalletMethod, args []interface{}) (interface{}, error) { + switch meth { + case api.WalletListForEnc: + return m.WalletListEncrypt(ctx) + case api.WalletExportForEnc: + if len(args) < 2 { + return nil, xerrors.Errorf("args must is 2 for exec method, but get args is %v", len(args)) + } + addr_str := args[0].(string) + addr, _ := address.NewFromString(addr_str) + passwd := args[1].(string) + return m.WalletExportEncrypt(ctx, addr, passwd) + case api.WalletDeleteForEnc: + if len(args) < 2 { + return nil, xerrors.Errorf("args must is 2 for exec method, but get args is %v", len(args)) + } + addr_str := args[0].(string) + addr, _ := address.NewFromString(addr_str) + passwd := args[1].(string) + return nil, m.WalletDeleteEncrypt(ctx, addr, passwd) + case api.WalletEncrypt: + if len(args) < 1 { + return nil, xerrors.Errorf("args must is 1 for exec method, but get args is %v", len(args)) + } + addr_str := args[0].(string) + addr, _ := address.NewFromString(addr_str) + return m.Local.WalletEncrypt(ctx, addr) + case api.WalletDecrypt: + if len(args) < 2 { + return nil, xerrors.Errorf("args must is 2 for exec method, but get args is %v", len(args)) + } + addr_str := args[0].(string) + addr, _ := address.NewFromString(addr_str) + passwd := args[1].(string) + return m.Local.WalletDecrypt(ctx, addr, passwd) + case api.WalletIsEncrypt: + if len(args) < 1 { + return nil, xerrors.Errorf("args must is 1 for exec method, but get args is %v", len(args)) + } + addr_str := args[0].(string) + addr, _ := address.NewFromString(addr_str) + return m.Local.WalletIsEncrypt(ctx, addr) + } + return m.Local.WalletCustomMethod(ctx, meth, args) +} + +var _ api.Wallet = MultiWallet{} diff --git a/chain/wallet/wallet.go b/chain/wallet/wallet.go index 76af663c780..f6f94e5a520 100644 --- a/chain/wallet/wallet.go +++ b/chain/wallet/wallet.go @@ -70,7 +70,13 @@ func (w *LocalWallet) WalletSign(ctx context.Context, addr address.Address, msg return nil, xerrors.Errorf("signing using key '%s': %w", addr.String(), types.ErrKeyInfoNotFound) } - return sigs.Sign(key.ActSigType(ki.Type), ki.PrivateKey, msg) + // wallet-security 解密 + // return sigs.Sign(key.ActSigType(ki.Type), ki.PrivateKey, msg) + pk, err := key.UnMakeByte(ki.PrivateKey) + if err != nil { + return nil, err + } + return sigs.Sign(key.ActSigType(ki.Type), pk, msg) } func (w *LocalWallet) findKey(addr address.Address) (*key.Key, error) { @@ -144,6 +150,12 @@ func (w *LocalWallet) WalletExport(ctx context.Context, addr address.Address) (* return nil, xerrors.Errorf("key not found for %s", addr) } + // wallet-security wallet加密判断 + pk := k.PrivateKey + if pk[0] == 0xff && pk[1] == 0xff && pk[2] == 0xff && pk[3] == 0xff { + return nil, xerrors.Errorf("The wallet is encrypted and there is no export permission.") + } + return &k.KeyInfo, nil } @@ -156,6 +168,13 @@ func (w *LocalWallet) WalletImport(ctx context.Context, ki *types.KeyInfo) (addr return address.Undef, xerrors.Errorf("failed to make key: %w", err) } + // wallet-security 加密 + pk, err := key.MakeByte(k.PrivateKey) + if err != nil { + return address.Undef, err + } + k.PrivateKey = pk + if err := w.keystore.Put(KNamePrefix+k.Address.String(), k.KeyInfo); err != nil { return address.Undef, xerrors.Errorf("saving to keystore: %w", err) } @@ -320,6 +339,16 @@ func (w *LocalWallet) deleteDefault() { } func (w *LocalWallet) WalletDelete(ctx context.Context, addr address.Address) error { + // wallet-security wallet加密判断 + key, err := w.findKey(addr) + if err != nil { + return err + } + pk := key.PrivateKey + if pk[0] == 0xff && pk[1] == 0xff && pk[2] == 0xff && pk[3] == 0xff { + return xerrors.Errorf("The wallet is encrypted and there is no delete permission.") + } + if err := w.walletDelete(ctx, addr); err != nil { return xerrors.Errorf("wallet delete: %w", err) } diff --git a/chain/wallet/wallet_aes.go b/chain/wallet/wallet_aes.go new file mode 100644 index 00000000000..5236f61f95c --- /dev/null +++ b/chain/wallet/wallet_aes.go @@ -0,0 +1,230 @@ +package wallet + +import ( + /* #nosec G501 */ + "crypto/md5" + "encoding/hex" + "fmt" + "io/ioutil" + "os" + "regexp" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/wallet/key" + "golang.org/x/xerrors" +) + +var substitutePwd = []byte("****************") + +const walletSaltPwd string = "8XBMT5OruN6XwEhaYfJfMJPL3WUhjWmH" +const walletCheckMsg string = "check passwd is success" + +type KeyInfo struct { + types.KeyInfo + Enc bool +} + +func completionPwd(pwd []byte) []byte { + sub := 16 - len(pwd) + if sub > 0 { + pwd = append(pwd, substitutePwd[:sub]...) + } + return pwd +} + +func SetupPasswd(passwd []byte, path string) error { + _, err := os.Stat(path) + if err == nil { + return xerrors.Errorf("checking file before Setup passwd '%s': file already exists", path) + } else if !os.IsNotExist(err) { + return xerrors.Errorf("checking file before Setup passwd '%s': %w", path, err) + } + + //用户密码加密check消息 + passwd = completionPwd(passwd) + /* #nosec G401 */ + m5 := md5.Sum(passwd) + checkmsg, err := key.AESEncrypt(m5[:], []byte(walletCheckMsg)) + m5passwd := hex.EncodeToString(m5[:]) + if err != nil { + return err + } + + //用户密码用盐密加密 + saltkey := completionPwd([]byte(walletSaltPwd)) + /* #nosec G401 */ + saltm5 := md5.Sum(saltkey) + saltm5passwdmsg, err := key.AESEncrypt(saltm5[:], []byte(m5passwd)) + //saltm5passwd := hex.EncodeToString(saltm5[:]) + if err != nil { + return err + } + + //存到/passwd + savetext := make([]byte, 64+len(checkmsg)) + copy(savetext[:64], saltm5passwdmsg) + copy(savetext[64:], checkmsg) + err = ioutil.WriteFile(path, savetext, 0600) + if err != nil { + return xerrors.Errorf("writing file '%s': %w", path, err) + } + + //密码保存到内存 + key.WalletPasswd = m5passwd + key.PasswdPath = path + + return nil +} + +func ResetPasswd(passwd []byte) error { + err := os.Remove(key.PasswdPath) + if err != nil { + return err + } + + err = SetupPasswd(passwd, key.PasswdPath) + if err != nil { + return err + } + + return nil +} + +func ClearPasswd() error { + err := os.Remove(key.PasswdPath) + if err != nil { + return err + } + key.WalletPasswd = "" + key.PasswdPath = "" + return nil +} + +func CheckPasswd(passwd []byte) error { + fstat, err := os.Stat(key.PasswdPath) + if os.IsNotExist(err) { + return fmt.Errorf("opening file '%s': file info not found", key.PasswdPath) + } else if err != nil { + return fmt.Errorf("opening file '%s': %w", key.PasswdPath, err) + } + + if fstat.Mode()&0077 != 0 { + return fmt.Errorf("permissions of key: '%s' are too relaxed, required: 0600, got: %#o", key.PasswdPath, fstat.Mode()) + } + + if fstat.Mode()&0077 != 0 { + return xerrors.Errorf("permissions of key: '%s' are too relaxed, required: 0600, got: %#o", key.PasswdPath, fstat.Mode()) + } + + file, err := os.Open(key.PasswdPath) + if err != nil { + return xerrors.Errorf("opening file '%s': %w", key.PasswdPath, err) + } + defer file.Close() //nolint:errcheck + + data, err := ioutil.ReadAll(file) + if err != nil { + return xerrors.Errorf("reading file '%s': %w", key.PasswdPath, err) + } + + //读取加密check消息 + passwd = completionPwd(passwd) + /* #nosec G401 */ + m5 := md5.Sum(passwd) + text, err := key.AESDecrypt(m5[:], data[64:]) + if err != nil { + return err + } + + //验证check消息 + str := string(text) + if walletCheckMsg != str { + return xerrors.Errorf("check passwd is failed") + } + //密码保存到内存 + if key.IsLock() { + key.WalletPasswd = hex.EncodeToString(m5[:]) + } + return nil +} + +func GetSetupState(path string) bool { + fstat, err := os.Stat(path) + if os.IsNotExist(err) { + return false + } else if err != nil { + return false + } + + if fstat.Mode()&0077 != 0 { + return false + } + + file, err := os.Open(path) + if err != nil { + log.Infof("opening file '%s': %w", path, err) + return false + } + defer file.Close() //nolint:errcheck + + data, err := ioutil.ReadAll(file) + if err != nil { + log.Infof("reading file '%s': %w", path, err) + return false + } + + //读取密码 + saltkey := completionPwd([]byte(walletSaltPwd)) + /* #nosec G401 */ + saltm5 := md5.Sum(saltkey) + m5passwd, err := key.AESDecrypt(saltm5[:], data[:64]) + if err != nil { + log.Infof("err: %v", err) + return false + } + + //用读取密码去验证加密check消息 + m5pwdstr := string(m5passwd[:32]) + m5pwd, _ := hex.DecodeString(m5pwdstr) + text, err := key.AESDecrypt(m5pwd[:16], data[64:]) + if err != nil { + log.Infof("err: %v", err) + return false + } + str := string(text) + if walletCheckMsg != str { + log.Infof("check passwd is failed") + return false + } + + key.PasswdPath = path + key.WalletPasswd = m5pwdstr + return true +} + +// GetSetupStateForLocal only lotus-wallet use +// +// check encryption status +func GetSetupStateForLocal(path string) bool { + fstat, err := os.Stat(path) + if os.IsNotExist(err) { + return false + } else if err != nil { + return false + } + + if fstat.Mode()&0077 != 0 { + return false + } + + return true +} + +func RegexpPasswd(passwd string) error { + // if ok, _ := regexp.MatchString(`^[a-zA-Z].{5,15}`, passwd); len(passwd) > 16 || !ok { + if ok, _ := regexp.MatchString(`^[a-zA-Z].[0-9A-Za-z!@#$%^&*]{4,15}`, passwd); len(passwd) > 16 || !ok { + // if ok, _ := regexp.MatchString(`^(?![0-9]+$)(?![a-zA-Z]+$)[a-zA-Z][0-9A-Za-z!@#$%^&*]{5,15}$`, passwd); len(passwd) > 18 || !ok { + return fmt.Errorf("invalid password format. (The beginning of the letter, 6 to 16 characters.)") + } + return nil +} diff --git a/chain/wallet/wallet_common.go b/chain/wallet/wallet_common.go new file mode 100644 index 00000000000..f98cfd1e2cf --- /dev/null +++ b/chain/wallet/wallet_common.go @@ -0,0 +1,51 @@ +package wallet + +import ( + "bufio" + "fmt" + "os" + "strings" +) + +/* +#cgo LDFLAGS: -L${SRCDIR}/ +#include +#include +struct termios disable_echo() { + struct termios of, nf; + tcgetattr(fileno(stdin), &of); + nf = of; + nf.c_lflag &= ~ECHO; + nf.c_lflag |= ECHONL; + if (tcsetattr(fileno(stdin), TCSANOW, &nf) != 0) { + perror("tcsetattr"); + } + return of; +} +void restore_echo(struct termios f) { + if (tcsetattr(fileno(stdin), TCSANOW, &f) != 0) { + perror("tcsetattr"); + } +} +*/ +import "C" + +func Prompt(msg string) string { + fmt.Printf("%s", msg) + oldFlags := C.disable_echo() + passwd, err := bufio.NewReader(os.Stdin).ReadString('\n') + C.restore_echo(oldFlags) + if err != nil { + panic(err) + } + return strings.TrimSpace(passwd) +} + +func PromptSimple(msg string) string { + fmt.Printf("%s", msg) + passwd, err := bufio.NewReader(os.Stdin).ReadString('\n') + if err != nil { + panic(err) + } + return strings.TrimSpace(passwd) +} diff --git a/chain/wallet/wallet_ext.go b/chain/wallet/wallet_ext.go new file mode 100644 index 00000000000..0f83a6e7c37 --- /dev/null +++ b/chain/wallet/wallet_ext.go @@ -0,0 +1,566 @@ +package wallet + +import ( + "bytes" + "context" + "fmt" + "sort" + "strings" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/wallet/key" + "golang.org/x/xerrors" +) + +// wallet-security LocalWallet WalletCustomMethod +func (w *LocalWallet) WalletCustomMethod(ctx context.Context, meth api.WalletMethod, args []interface{}) (interface{}, error) { + + switch meth { + case api.Unknown: + return nil, xerrors.Errorf("exec method is unknown") + case api.WalletListForEnc: + return w.WalletListEncrypt(ctx) + case api.WalletExportForEnc: + if len(args) < 2 { + return nil, xerrors.Errorf("args must is 2 for exec method, but get args is %v", len(args)) + } + addr := args[0].(address.Address) + passwd := args[1].(string) + return w.WalletExportEncrypt(ctx, addr, passwd) + case api.WalletDeleteForEnc: + if len(args) < 2 { + return nil, xerrors.Errorf("args must is 2 for exec method, but get args is %v", len(args)) + } + addr := args[0].(address.Address) + passwd := args[1].(string) + return nil, w.WalletDeleteEncrypt(ctx, addr, passwd) + case api.WalletAddPasswd: + if len(args) < 2 { + return nil, xerrors.Errorf("args must is 2 for exec method, but get args is %v", len(args)) + } + passwd := args[0].(string) + path := args[1].(string) + return nil, w.WalletAddPasswd(ctx, passwd, path) + case api.WalletResetPasswd: + if len(args) < 2 { + return nil, xerrors.Errorf("args must is 2 for exec method, but get args is %v", len(args)) + } + oldPasswd := args[0].(string) + newPasswd := args[1].(string) + return w.WalletResetPasswd(ctx, oldPasswd, newPasswd) + case api.WalletClearPasswd: + if len(args) < 1 { + return nil, xerrors.Errorf("args must is 1 for exec method, but get args is %v", len(args)) + } + passwd := args[0].(string) + return w.WalletClearPasswd(ctx, passwd) + case api.WalletCheckPasswd: + if len(args) < 1 { + return nil, xerrors.Errorf("args must is 1 for exec method, but get args is %v", len(args)) + } + passwd := args[0].(string) + return w.WalletCheckPasswd(ctx, passwd), nil + case api.WalletEncrypt: + if len(args) < 1 { + return nil, xerrors.Errorf("args must is 1 for exec method, but get args is %v", len(args)) + } + addr := args[0].(address.Address) + return w.WalletEncrypt(ctx, addr) + case api.WalletDecrypt: + if len(args) < 2 { + return nil, xerrors.Errorf("args must is 2 for exec method, but get args is %v", len(args)) + } + addr := args[0].(address.Address) + passwd := args[1].(string) + return w.WalletDecrypt(ctx, addr, passwd) + case api.WalletIsEncrypt: + if len(args) < 1 { + return nil, xerrors.Errorf("args must is 1 for exec method, but get args is %v", len(args)) + } + addr := args[0].(address.Address) + // passwd := args[1].(string) + return w.WalletIsEncrypt(ctx, addr) + default: + return nil, xerrors.Errorf("exec method is unknown") + } +} + +// wallet-security LocalWallet func +func (w *LocalWallet) WalletListEncrypt(context.Context) ([]api.AddrListEncrypt, error) { + all, err := w.keystore.List() + if err != nil { + return nil, xerrors.Errorf("listing keystore: %w", err) + } + + sort.Strings(all) + + seen := map[address.Address]struct{}{} + out := make([]api.AddrListEncrypt, 0, len(all)) + for _, a := range all { + var addr address.Address + var err error + if strings.HasPrefix(a, KNamePrefix) { + name := strings.TrimPrefix(a, KNamePrefix) + addr, err = address.NewFromString(name) + if err != nil { + return nil, xerrors.Errorf("converting name to address: %w", err) + } + + if _, ok := seen[addr]; ok { + continue // got duplicate with a different prefix + } + seen[addr] = struct{}{} + + key, err := w.findKey(addr) + if err != nil { + return nil, err + } + pk := key.PrivateKey + var encrypt bool + if pk[0] == 0xff && pk[1] == 0xff && pk[2] == 0xff && pk[3] == 0xff { + encrypt = true + } + + out = append(out, api.AddrListEncrypt{Addr: addr, Encrypt: encrypt}) + } + } + + sort.Slice(out, func(i, j int) bool { + return out[i].Addr.String() < out[j].Addr.String() + }) + + return out, nil +} + +func (w *LocalWallet) WalletExportEncrypt(ctx context.Context, addr address.Address, passwd string) (*types.KeyInfo, error) { + if key.IsSetup() { + if err := CheckPasswd([]byte(passwd)); err != nil { + return nil, err + } + } + + k, err := w.findKey(addr) + if err != nil { + return nil, xerrors.Errorf("failed to find key to export: %w", err) + } + if k == nil { + return nil, xerrors.Errorf("key not found") + } + + // wallet-security 解密 + pk, err := key.UnMakeByte(k.PrivateKey) + if err != nil { + return nil, err + } + var pki types.KeyInfo + pki.Type = k.Type + pki.PrivateKey = pk + return &pki, nil +} + +func (w *LocalWallet) WalletDeleteEncrypt(ctx context.Context, addr address.Address, passwd string) error { + if key.IsSetup() { + if err := CheckPasswd([]byte(passwd)); err != nil { + return err + } + } + + if err := w.walletDelete(ctx, addr); err != nil { + return xerrors.Errorf("wallet delete: %w", err) + } + + if def, err := w.GetDefault(); err == nil { + if def == addr { + w.deleteDefault() + } + } + return nil +} + +func (w *LocalWallet) WalletAddPasswd(ctx context.Context, passwd string, path string) error { + + if key.IsSetup() { + err := xerrors.Errorf("passwd is setup, no need to setup again") + log.Warn(err.Error()) + return err + } + + if err := RegexpPasswd(passwd); err != nil { + return err + } + + err := SetupPasswd([]byte(passwd), path) + if err != nil { + return err + } + + return nil +} + +func (w *LocalWallet) WalletResetPasswd(ctx context.Context, oldPasswd, newPasswd string) (bool, error) { + if !key.IsSetup() { + return false, xerrors.Errorf("passwd is not setup") + } + + if err := CheckPasswd([]byte(oldPasswd)); err != nil { + return false, err + } + + if err := RegexpPasswd(newPasswd); err != nil { + return false, err + } + + addr_list, err := w.WalletList(ctx) + if err != nil { + return false, err + } + + addr_all := make(map[address.Address]*KeyInfo) + for _, v := range addr_list { + k, err := w.findKey(v) + if err != nil { + return false, fmt.Errorf("failed to find key to export: %w", err) + } + if k == nil { + return false, fmt.Errorf("key not found") + } + + pk, err := key.UnMakeByte(k.PrivateKey) + if err != nil { + return false, err + } + + ki := &KeyInfo{ + KeyInfo: types.KeyInfo{ + Type: k.Type, + PrivateKey: pk, + }, + Enc: key.IsPrivateKeyEnc(k.PrivateKey), + } + addr_all[v] = ki + + err = w.WalletDeleteKey2(v) + if err != nil { + return false, err + } + } + + setDefault := true + defalutAddr, err := w.GetDefault() + if err != nil { + setDefault = false + } + + err = ResetPasswd([]byte(newPasswd)) + if err != nil { + return false, err + } + + for addr, v := range addr_all { + k, err := key.NewKey(v.KeyInfo) + if err != nil { + return false, fmt.Errorf("failed to make key: %w", err) + } + + if v.Enc { + pk, err := key.MakeByte(k.PrivateKey) + if err != nil { + return false, err + } + k.PrivateKey = pk + } + + if err := w.keystore.Put(KNamePrefix+k.Address.String(), k.KeyInfo); err != nil { + return false, fmt.Errorf("saving to keystore: %w", err) + } + + if k.Address != addr { + return false, fmt.Errorf("import error") + } + } + + if setDefault { + err = w.SetDefault(defalutAddr) + if err != nil { + return false, err + } + } + + w.WalletClearCache() + + return true, nil +} + +func (w *LocalWallet) WalletClearPasswd(ctx context.Context, passwd string) (bool, error) { + if !key.IsSetup() { + return false, xerrors.Errorf("passwd is not setup") + } + + if err := CheckPasswd([]byte(passwd)); err != nil { + return false, err + } + + addr_list, err := w.WalletList(ctx) + if err != nil { + return false, err + } + addr_all := make(map[address.Address]*types.KeyInfo) + for _, v := range addr_list { + addr_all[v], err = w.WalletExportEncrypt(ctx, v, passwd) + if err != nil { + return false, err + } + err = w.WalletDeleteKey2(v) + if err != nil { + return false, err + } + } + + setDefault := true + defalutAddr, err := w.GetDefault() + if err != nil { + setDefault = false + } + + err = ClearPasswd() + if err != nil { + return false, err + } + + for k, v := range addr_all { + addr, err := w.WalletImport(ctx, v) + if err != nil { + return false, nil + } else if addr != k { + return false, xerrors.Errorf("import error") + } + } + + if setDefault { + err = w.SetDefault(defalutAddr) + if err != nil { + return false, err + } + } + + w.WalletClearCache() + return true, nil +} + +func (w *LocalWallet) WalletCheckPasswd(ctx context.Context, passwd string) bool { + if err := CheckPasswd([]byte(passwd)); err != nil { + return false + } + return true +} + +func (w *LocalWallet) WalletEncrypt(ctx context.Context, addr address.Address) (bool, error) { + if !key.IsSetup() { + return false, xerrors.Errorf("passwd is not setup") + } + + addr_list, err := w.WalletList(ctx) + if err != nil { + return false, err + } + addr_all := make(map[address.Address]*KeyInfo) + for _, v := range addr_list { + if v == addr { + k, err := w.findKey(v) + if err != nil { + return false, fmt.Errorf("failed to find key to export: %w", err) + } + if k == nil { + return false, fmt.Errorf("key not found") + } + + pk, err := key.UnMakeByte(k.PrivateKey) + if err != nil { + return false, err + } + + ki := &KeyInfo{ + KeyInfo: types.KeyInfo{ + Type: k.Type, + PrivateKey: pk, + }, + Enc: key.IsPrivateKeyEnc(k.PrivateKey), + } + addr_all[v] = ki + + err = w.WalletDeleteKey2(v) + if err != nil { + return false, err + } + } + } + + setDefault := true + defalutAddr, err := w.GetDefault() + if err != nil { + setDefault = false + } + + for k, v := range addr_all { + if k == addr { + k, err := key.NewKey(v.KeyInfo) + if err != nil { + return false, fmt.Errorf("failed to make key: %w", err) + } + + pk, err := key.MakeByte(k.PrivateKey) + if err != nil { + return false, err + } + k.PrivateKey = pk + + if err := w.keystore.Put(KNamePrefix+k.Address.String(), k.KeyInfo); err != nil { + return false, fmt.Errorf("saving to keystore: %w", err) + } + + if k.Address != addr { + return false, fmt.Errorf("import error") + } + } + } + + if setDefault { + err = w.SetDefault(defalutAddr) + if err != nil { + return false, err + } + } + + w.WalletClearCache() + return true, nil +} + +func (w *LocalWallet) WalletDecrypt(ctx context.Context, addr address.Address, passwd string) (bool, error) { + if !key.IsSetup() { + return false, xerrors.Errorf("passwd is not setup") + } + + if err := CheckPasswd([]byte(passwd)); err != nil { + return false, err + } + + addr_list, err := w.WalletList(ctx) + if err != nil { + return false, err + } + + addr_all := make(map[address.Address]*KeyInfo) + for _, v := range addr_list { + if v == addr { + k, err := w.findKey(v) + if err != nil { + return false, fmt.Errorf("failed to find key to export: %w", err) + } + if k == nil { + return false, fmt.Errorf("key not found") + } + + pk, err := key.UnMakeByte(k.PrivateKey) + if err != nil { + return false, err + } + + ki := &KeyInfo{ + KeyInfo: types.KeyInfo{ + Type: k.Type, + PrivateKey: pk, + }, + Enc: key.IsPrivateKeyEnc(k.PrivateKey), + } + addr_all[v] = ki + + err = w.WalletDeleteKey2(v) + if err != nil { + return false, err + } + } + } + + setDefault := true + defalutAddr, err := w.GetDefault() + if err != nil { + setDefault = false + } + + for k, v := range addr_all { + if k == addr { + k, err := key.NewKey(v.KeyInfo) + if err != nil { + return false, fmt.Errorf("failed to make key: %w", err) + } + + if err := w.keystore.Put(KNamePrefix+k.Address.String(), k.KeyInfo); err != nil { + return false, fmt.Errorf("saving to keystore: %w", err) + } + + if k.Address != addr { + return false, fmt.Errorf("import error") + } + } + } + + if setDefault { + err = w.SetDefault(defalutAddr) + if err != nil { + return false, err + } + } + + w.WalletClearCache() + return true, nil +} + +func (w *LocalWallet) WalletIsEncrypt(ctx context.Context, addr address.Address) (bool, error) { + if !key.IsSetup() { + log.Infof("passwd is not setup") + return false, nil + } + + addr_list, err := w.WalletList(ctx) + if err != nil { + return false, err + } + + for _, v := range addr_list { + if v == addr { + ki, err := w.tryFind(v) + if err != nil { + if xerrors.Is(err, types.ErrKeyInfoNotFound) { + return false, nil + } + return false, xerrors.Errorf("getting from keystore: %w", err) + } + + // wallet-security 解密 + if bytes.Equal(ki.PrivateKey[:4], key.AddrPrefix) { + return true, nil + } + return false, nil + } + } + return false, nil +} + +func (w *LocalWallet) WalletDeleteKey2(addr address.Address) error { + k, err := w.findKey(addr) + if err != nil { + return xerrors.Errorf("failed to delete key %s : %w", addr, err) + } + + if err := w.keystore.Delete(KNamePrefix + k.Address.String()); err != nil { + return xerrors.Errorf("failed to delete key %s: %w", addr, err) + } + + return nil +} + +func (w *LocalWallet) WalletClearCache() { + w.keys = make(map[address.Address]*key.Key) +} diff --git a/cli/cmd.go b/cli/cmd.go index 802df0c99ac..c189e776f97 100644 --- a/cli/cmd.go +++ b/cli/cmd.go @@ -93,3 +93,9 @@ func WithCategory(cat string, cmd *cli.Command) *cli.Command { cmd.Category = strings.ToUpper(cat) return cmd } + +// wallet-security GetWalletCmd +// GetWalletCmd get wallet cmds +func GetWalletCmd() []*cli.Command { + return walletCmd.Subcommands +} diff --git a/cli/send.go b/cli/send.go index cfa2515c07b..f6c3794bc4b 100644 --- a/cli/send.go +++ b/cli/send.go @@ -17,6 +17,10 @@ import ( "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types/ethtypes" + + // wallet-security api + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/wallet" ) var sendCmd = &cli.Command{ @@ -199,6 +203,35 @@ var sendCmd = &cli.Command{ params.Params = decparams } + // wallet-security WalletDefaultAddress + fullapi := srv.FullNodeAPI() + if params.From == address.Undef { + defaddr, err := fullapi.WalletDefaultAddress(ctx) + if err != nil { + return err + } + params.From = defaddr + } + // wallet-security send + if wallet.GetSetupStateForLocal(getWalletPwdRepo(cctx)) { + rest, _ := fullapi.WalletCustomMethod(ctx, api.WalletIsEncrypt, []interface{}{params.From}) + if rest != nil && rest.(bool) { + // passwd := cctx.String("passwd") + passwd := wallet.Prompt("Enter your Password:\n") + if passwd == "" { + return xerrors.Errorf("must enter your passwd") + } + if err := wallet.RegexpPasswd(passwd); err != nil { + return err + } + + rest, _ := fullapi.WalletCustomMethod(ctx, api.WalletCheckPasswd, []interface{}{passwd}) + if !rest.(bool) { + return fmt.Errorf("check passwd is failed") + } + } + } + if cctx.IsSet("nonce") { n := cctx.Uint64("nonce") params.Nonce = &n diff --git a/cli/wallet.go b/cli/wallet.go index 3a21cdaba81..f0ef7b79e7a 100644 --- a/cli/wallet.go +++ b/cli/wallet.go @@ -22,6 +22,10 @@ import ( "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/tablewriter" + + // wallet-security api + lapi "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/wallet" ) var walletCmd = &cli.Command{ @@ -39,6 +43,13 @@ var walletCmd = &cli.Command{ walletVerify, walletDelete, walletMarket, + + // wallet-extand mark func cmd + WithCategory("custom", walletMarkCmd), + // wallet-security func cmd + WithCategory("custom", walletPasswdCmd), + WithCategory("custom", walletEncrypt), + WithCategory("custom", walletDecrypt), }, } @@ -102,9 +113,50 @@ var walletList = &cli.Command{ afmt := NewAppFmt(cctx.App) - addrs, err := api.WalletList(ctx) - if err != nil { - return err + // wallet-security walletlist + // addrs, err := api.WalletList(ctx) + // if err != nil { + // return err + // } + encryptAddrs := make([]lapi.AddrListEncrypt, 0) + rest, err := api.WalletCustomMethod(ctx, lapi.WalletListForEnc, []interface{}{}) + if rest != nil { + if err != nil { + return err + } + addrs, _ := json.Marshal(rest) + if err := json.Unmarshal(addrs, &encryptAddrs); err != nil { + return err + } + } else { + addrs, err := api.WalletList(ctx) + if err != nil { + return err + } + for _, v := range addrs { + encryptAddrs = append(encryptAddrs, lapi.AddrListEncrypt{ + Addr: v, + Encrypt: false, + }) + } + } + + // wallet-extand keymark + var keyMark map[string]string + var keymarkPath string = getWalletMarkRepo(cctx) + _, err = os.Stat(keymarkPath) + if err == nil { + sector, err := ioutil.ReadFile(keymarkPath) + if err == nil { + err = json.Unmarshal(sector, &keyMark) + if err != nil { + keyMark = map[string]string{} + } + } else { + keyMark = map[string]string{} + } + } else { + keyMark = map[string]string{} } // Assume an error means no default key is set @@ -118,17 +170,20 @@ var walletList = &cli.Command{ tablewriter.Col("Market(Locked)"), tablewriter.Col("Nonce"), tablewriter.Col("Default"), + tablewriter.Col("Encrypt"), + tablewriter.Col("Mark"), tablewriter.NewLineCol("Error")) - for _, addr := range addrs { + for _, encryptAddr := range encryptAddrs { if cctx.Bool("addr-only") { - afmt.Println(addr.String()) + //afmt.Println(addr.String()) + afmt.Println(encryptAddr.Addr.String()) } else { - a, err := api.StateGetActor(ctx, addr, types.EmptyTSK) + a, err := api.StateGetActor(ctx, encryptAddr.Addr, types.EmptyTSK) if err != nil { if !strings.Contains(err.Error(), "actor not found") { tw.Write(map[string]interface{}{ - "Address": addr, + "Address": encryptAddr.Addr, "Error": err, }) continue @@ -140,16 +195,26 @@ var walletList = &cli.Command{ } row := map[string]interface{}{ - "Address": addr, + "Address": encryptAddr.Addr, "Balance": types.FIL(a.Balance), "Nonce": a.Nonce, + "Encrypt": encryptAddr.Encrypt, } - if addr == def { + if encryptAddr.Addr == def { row["Default"] = "X" } + // wallet-extand keymark + addrmark, exist := keyMark[encryptAddr.Addr.String()] + if !exist && addrmark != "" { + addrmark = "" + } + if addrmark != "" { + row["Mark"] = addrmark + } + if cctx.Bool("id") { - id, err := api.StateLookupID(ctx, addr, types.EmptyTSK) + id, err := api.StateLookupID(ctx, encryptAddr.Addr, types.EmptyTSK) if err != nil { row["ID"] = "n/a" } else { @@ -158,7 +223,7 @@ var walletList = &cli.Command{ } if cctx.Bool("market") { - mbal, err := api.StateMarketBalance(ctx, addr, types.EmptyTSK) + mbal, err := api.StateMarketBalance(ctx, encryptAddr.Addr, types.EmptyTSK) if err == nil { row["Market(Avail)"] = types.FIL(types.BigSub(mbal.Escrow, mbal.Locked)) row["Market(Locked)"] = types.FIL(mbal.Locked) @@ -283,14 +348,49 @@ var walletExport = &cli.Command{ return fmt.Errorf("must specify key to export") } + // wallet-security panic + defer func() { + if err := recover(); err != nil { + fmt.Println("invaild address payload") + } + }() + addr, err := address.NewFromString(cctx.Args().First()) if err != nil { return err } - ki, err := api.WalletExport(ctx, addr) - if err != nil { - return err + // wallet-security walletexport + // ki, err := api.WalletExport(ctx, addr) + // if err != nil { + // return err + // } + ki := new(types.KeyInfo) + rest, _ := api.WalletCustomMethod(ctx, lapi.WalletIsEncrypt, []interface{}{addr}) + if rest != nil && (wallet.GetSetupStateForLocal(getWalletPwdRepo(cctx)) && rest.(bool)) { + // passwd := cctx.String("passwd") + passwd := wallet.Prompt("Enter your Password:\n") + if passwd == "" { + return xerrors.Errorf("must enter your passwd") + } + + if err := wallet.RegexpPasswd(passwd); err != nil { + return err + } + + rest, err := api.WalletCustomMethod(ctx, lapi.WalletExportForEnc, []interface{}{addr, passwd}) + if err != nil { + return err + } + keyinfo, _ := json.Marshal(rest) + if err := json.Unmarshal(keyinfo, ki); err != nil { + return err + } + } else { + ki, err = api.WalletExport(ctx, addr) + if err != nil { + return err + } } b, err := json.Marshal(ki) @@ -513,6 +613,13 @@ var walletDelete = &cli.Command{ return fmt.Errorf("must specify address to delete") } + // wallet-security panic + defer func() { + if err := recover(); err != nil { + fmt.Println("invaild address payload") + } + }() + addr, err := address.NewFromString(cctx.Args().First()) if err != nil { return err @@ -520,7 +627,32 @@ var walletDelete = &cli.Command{ fmt.Println("Soft deleting address:", addr) fmt.Println("Hard deletion of the address in `~/.lotus/keystore` is needed for permanent removal") - return api.WalletDelete(ctx, addr) + + // wallet-security walletdelete + // return api.WalletDelete(ctx, addr) + rest, _ := api.WalletCustomMethod(ctx, lapi.WalletIsEncrypt, []interface{}{addr}) + if rest != nil && (wallet.GetSetupStateForLocal(getWalletPwdRepo(cctx)) && rest.(bool)) { + // passwd := cctx.String("passwd") + passwd := wallet.Prompt("Enter your Password:\n") + if passwd == "" { + return xerrors.Errorf("Must enter your passwd") + } + + if err := wallet.RegexpPasswd(passwd); err != nil { + return err + } + + _, err = api.WalletCustomMethod(ctx, lapi.WalletDeleteForEnc, []interface{}{addr, passwd}) + if err != nil { + return err + } + } else { + if err := api.WalletDelete(ctx, addr); err != nil { + return err + } + } + + return nil }, } diff --git a/cli/wallet_ext.go b/cli/wallet_ext.go new file mode 100644 index 00000000000..a6b1b26484e --- /dev/null +++ b/cli/wallet_ext.go @@ -0,0 +1,529 @@ +package cli + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + + "github.com/mitchellh/go-homedir" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + + "github.com/filecoin-project/lotus/chain/wallet" + + // wallet-security api + lapi "github.com/filecoin-project/lotus/api" +) + +// wallet-security func cmd +var walletPasswdCmd = &cli.Command{ + Name: "passwd", + Usage: "Manage wallet passwd info", + Subcommands: []*cli.Command{ + walletAddPasswd, + walletResetPasswd, + walletClearPasswd, + }, +} +var walletAddPasswd = &cli.Command{ + Name: "add", + Usage: "Add wallet password", + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + if wallet.GetSetupStateForLocal(getWalletPwdRepo(cctx)) { + fmt.Println("passwd is setup,no need to setup again") + return nil + } + + // passwd := cctx.String("passwd") + passwd := wallet.Prompt("Enter your password:\n") + if passwd == "" { + return xerrors.Errorf("must enter your passwd") + } + if err := wallet.RegexpPasswd(passwd); err != nil { + return err + } + + passwd_ag := wallet.Prompt("Enter your password again:\n") + if passwd_ag == "" { + return fmt.Errorf("must enter your passwd") + } + if err := wallet.RegexpPasswd(passwd_ag); err != nil { + return err + } + if passwd != passwd_ag { + return fmt.Errorf("the two passwords do not match") + } + + _, err = api.WalletCustomMethod(ctx, lapi.WalletAddPasswd, []interface{}{passwd, getWalletPwdRepo(cctx)}) + if err != nil { + fmt.Println(err.Error()) + return err + } + fmt.Printf("add wallet password success. \n") + return nil + }, +} +var walletResetPasswd = &cli.Command{ + Name: "reset", + Usage: "Reset wallet password", + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + if !wallet.GetSetupStateForLocal(getWalletPwdRepo(cctx)) { + fmt.Println("passwd is not setup") + return nil + } + + // passwd := cctx.String("passwd") + passwd := wallet.Prompt("Enter your old Password:\n") + if passwd == "" { + return xerrors.Errorf("Must enter your old passwd") + } + if err := wallet.RegexpPasswd(passwd); err != nil { + return err + } + + rest, _ := api.WalletCustomMethod(ctx, lapi.WalletCheckPasswd, []interface{}{passwd}) + if !rest.(bool) { + return fmt.Errorf("check passwd is failed") + } + + newPasswd := wallet.Prompt("Enter your new Password:\n") + if passwd == "" { + return xerrors.Errorf("Must enter your new passwd") + } + if err := wallet.RegexpPasswd(newPasswd); err != nil { + return fmt.Errorf("new passwd : %w", err) + } + + newPasswd_ag := wallet.Prompt("Enter your password again:\n") + if newPasswd_ag == "" { + return fmt.Errorf("must enter your passwd") + } + if err := wallet.RegexpPasswd(newPasswd_ag); err != nil { + return err + } + if newPasswd != newPasswd_ag { + return fmt.Errorf("the two passwords do not match") + } + + _, err = api.WalletCustomMethod(ctx, lapi.WalletResetPasswd, []interface{}{passwd, newPasswd}) + if err != nil { + return err + } + + fmt.Printf("wallet passwd change success. \n") + return nil + }, +} +var walletClearPasswd = &cli.Command{ + Name: "clear", + Usage: "Clear wallet password", + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + if !wallet.GetSetupStateForLocal(getWalletPwdRepo(cctx)) { + fmt.Println("passwd is not setup") + return nil + } + + // passwd := cctx.String("passwd") + passwd := wallet.Prompt("Enter your Password:\n") + if passwd == "" { + return xerrors.Errorf("Must enter your passwd") + } + if err := wallet.RegexpPasswd(passwd); err != nil { + return err + } + + _, err = api.WalletCustomMethod(ctx, lapi.WalletClearPasswd, []interface{}{passwd}) + if err != nil { + return err + } + + fmt.Printf("wallet passwd clear success. \n") + return nil + }, +} + +var walletEncrypt = &cli.Command{ + Name: "encrypt", + Usage: "encrypt wallet account", + ArgsUsage: "[address]", + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + if !wallet.GetSetupStateForLocal(getWalletPwdRepo(cctx)) { + fmt.Println("passwd is not setup") + return nil + } + + if cctx.Args().First() == "all" { + // wallet-security encrypt all + encryptAddrs := make([]lapi.AddrListEncrypt, 0) + rest, err := api.WalletCustomMethod(ctx, lapi.WalletListForEnc, []interface{}{}) + if rest != nil { + if err != nil { + return err + } + addrs, _ := json.Marshal(rest) + if err := json.Unmarshal(addrs, &encryptAddrs); err != nil { + return err + } + } else { + l, err := api.WalletList(ctx) + if err != nil { + return err + } + for _, v := range l { + encryptAddrs = append(encryptAddrs, lapi.AddrListEncrypt{ + Addr: v, + Encrypt: false, + }) + } + } + + // passwd := cctx.String("passwd") + passwd := wallet.Prompt("Enter your Password:\n") + if passwd == "" { + return xerrors.Errorf("Must enter your passwd") + } + if err := wallet.RegexpPasswd(passwd); err != nil { + return err + } + + for _, encryptAddr := range encryptAddrs { + if encryptAddr.Encrypt { + continue + } + + rest, _ := api.WalletCustomMethod(ctx, lapi.WalletIsEncrypt, []interface{}{encryptAddr.Addr}) + if rest != nil && !rest.(bool) { + _, err = api.WalletCustomMethod(ctx, lapi.WalletEncrypt, []interface{}{encryptAddr.Addr}) + if err != nil { + return err + } + + fmt.Printf("Wallet %v encrypt success \n", encryptAddr.Addr) + } else { + fmt.Printf("Wallet %v is encrypted \n", encryptAddr.Addr) + } + } + } else { + addr, err := address.NewFromString(cctx.Args().First()) + if err != nil { + return err + } + + rest, _ := api.WalletCustomMethod(ctx, lapi.WalletIsEncrypt, []interface{}{addr}) + if rest != nil && !rest.(bool) { + + _, err = api.WalletCustomMethod(ctx, lapi.WalletEncrypt, []interface{}{addr}) + if err != nil { + return err + } + + fmt.Printf("Wallet encrypt success \n") + } else { + fmt.Printf("Wallet is encrypted \n") + } + } + return nil + }, +} +var walletDecrypt = &cli.Command{ + Name: "decrypt", + Usage: "decrypt wallet account", + ArgsUsage: "[address]", + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + if !wallet.GetSetupStateForLocal(getWalletPwdRepo(cctx)) { + fmt.Println("passwd is not setup") + return nil + } + + if cctx.Args().First() == "all" { + // wallet-security encrypt all + encryptAddrs := make([]lapi.AddrListEncrypt, 0) + rest, err := api.WalletCustomMethod(ctx, lapi.WalletListForEnc, []interface{}{}) + if rest != nil { + if err != nil { + return err + } + addrs, _ := json.Marshal(rest) + if err := json.Unmarshal(addrs, &encryptAddrs); err != nil { + return err + } + } else { + l, err := api.WalletList(ctx) + if err != nil { + return err + } + for _, v := range l { + encryptAddrs = append(encryptAddrs, lapi.AddrListEncrypt{ + Addr: v, + Encrypt: false, + }) + } + } + + // passwd := cctx.String("passwd") + passwd := wallet.Prompt("Enter your Password:\n") + if passwd == "" { + return xerrors.Errorf("Must enter your passwd") + } + if err := wallet.RegexpPasswd(passwd); err != nil { + return err + } + + for _, encryptAddr := range encryptAddrs { + if !encryptAddr.Encrypt { + continue + } + + rest, _ := api.WalletCustomMethod(ctx, lapi.WalletIsEncrypt, []interface{}{encryptAddr.Addr}) + if rest != nil && rest.(bool) { + _, err = api.WalletCustomMethod(ctx, lapi.WalletDecrypt, []interface{}{encryptAddr.Addr, passwd}) + if err != nil { + return err + } + + fmt.Printf("Wallet %v decrypt success \n", encryptAddr.Addr) + } else { + fmt.Printf("Wallet %v is not encrypted \n", encryptAddr.Addr) + } + } + } else { + addr, err := address.NewFromString(cctx.Args().First()) + if err != nil { + return err + } + + rest, _ := api.WalletCustomMethod(ctx, lapi.WalletIsEncrypt, []interface{}{addr}) + if rest != nil && rest.(bool) { + // passwd := cctx.String("passwd") + passwd := wallet.Prompt("Enter your Password:\n") + if passwd == "" { + return xerrors.Errorf("Must enter your passwd") + } + if err := wallet.RegexpPasswd(passwd); err != nil { + return err + } + + _, err = api.WalletCustomMethod(ctx, lapi.WalletDecrypt, []interface{}{addr, passwd}) + if err != nil { + return err + } + + fmt.Printf("Wallet decrypt success \n") + } else { + fmt.Printf("Wallet is not encrypted \n") + } + } + return nil + }, +} + +// wallet-security pwd func +func getWalletPwdRepo(cctx *cli.Context) string { + passwdPath, err := homedir.Expand(cctx.String("repo")) + if err != nil { + return "" + } + return passwdPath + "/keystore/passwd" +} + +// wallet-extand mark func cmd +var walletMarkCmd = &cli.Command{ + Name: "mark", + Usage: "Manage wallet mark info", + Subcommands: []*cli.Command{ + walletAddMarkCmd, + walletDelMarkCmd, + walletClearMarkCmd, + }, +} +var walletAddMarkCmd = &cli.Command{ + Name: "add", + Usage: "Add/Update wallet mark", + ArgsUsage: "[address]", + Action: func(cctx *cli.Context) error { + addr, err := address.NewFromString(cctx.Args().First()) + if err != nil { + return err + } + + mark := wallet.PromptSimple("Enter mark:\n") + if mark == "" { + return xerrors.Errorf("Enter mark is empty.") + } + + var keyMark map[string]string + var keymarkPath string = getWalletMarkRepo(cctx) + _, err = os.Stat(keymarkPath) + if err == nil { + sector, err := ioutil.ReadFile(keymarkPath) + if err == nil { + err = json.Unmarshal(sector, &keyMark) + if err != nil { + keyMark = map[string]string{} + } + } else { + keyMark = map[string]string{} + } + } else { + keyMark = map[string]string{} + } + + keyMark[addr.String()] = mark + + err = saveWalletMarkFile(cctx, keyMark) + if err != nil { + return err + } + + fmt.Printf("wallet add mark success. %v:%v \n", addr.String(), mark) + return nil + }, +} +var walletDelMarkCmd = &cli.Command{ + Name: "del", + Usage: "Delete wallet mark", + ArgsUsage: "[address]", + Action: func(cctx *cli.Context) error { + if !wallet.GetSetupStateForLocal(getWalletMarkRepo(cctx)) { + fmt.Println("mark is not setup") + return nil + } + + addr, err := address.NewFromString(cctx.Args().First()) + if err != nil { + return err + } + + var keyMark map[string]string + var keymarkPath string = getWalletMarkRepo(cctx) + _, err = os.Stat(keymarkPath) + if err == nil { + sector, err := ioutil.ReadFile(keymarkPath) + if err == nil { + err = json.Unmarshal(sector, &keyMark) + if err != nil { + keyMark = map[string]string{} + } + } else { + keyMark = map[string]string{} + } + } else { + keyMark = map[string]string{} + } + + for k := range keyMark { + if k == addr.String() { + delete(keyMark, addr.String()) + } + } + + err = saveWalletMarkFile(cctx, keyMark) + if err != nil { + return err + } + + fmt.Printf("wallet delete mark success. %v \n", addr.String()) + return nil + }, +} +var walletClearMarkCmd = &cli.Command{ + Name: "clear", + Usage: "Clear wallet mark", + Action: func(cctx *cli.Context) error { + if !wallet.GetSetupStateForLocal(getWalletMarkRepo(cctx)) { + fmt.Println("mark is not setup") + return nil + } + + var keyMark map[string]string + var keymarkPath string = getWalletMarkRepo(cctx) + _, err := os.Stat(keymarkPath) + if err == nil { + sector, err := ioutil.ReadFile(keymarkPath) + if err == nil { + err = json.Unmarshal(sector, &keyMark) + if err != nil { + keyMark = map[string]string{} + } + } else { + keyMark = map[string]string{} + } + } else { + keyMark = map[string]string{} + } + + for k := range keyMark { + delete(keyMark, k) + } + + err = saveWalletMarkFile(cctx, keyMark) + if err != nil { + return err + } + + fmt.Printf("wallet clear mark success. \n") + return nil + }, +} + +// wallet-extand mark func +func getWalletMarkRepo(cctx *cli.Context) string { + keymarkPath, err := homedir.Expand(cctx.String("repo")) + if err != nil { + return "" + } + return keymarkPath + "/keystore/keymark" +} + +func saveWalletMarkFile(cctx *cli.Context, keyMark map[string]string) error { + var keymarkPath string = getWalletMarkRepo(cctx) + f, err := os.OpenFile(keymarkPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY|os.O_SYNC, 0600) + if err != nil { + return err + } + defer f.Close() //nolint:errcheck + + sector, err := json.MarshalIndent(keyMark, "", "\t") + if err != nil { + return err + } + err = ioutil.WriteFile(keymarkPath, sector, 0600) + if err != nil { + return xerrors.Errorf("writing file '%s': %w", keymarkPath, err) + } + return nil +} diff --git a/cmd/lotus-wallet/interactive.go b/cmd/lotus-wallet/interactive.go index 40c3f892231..db8bc0b65f8 100644 --- a/cmd/lotus-wallet/interactive.go +++ b/cmd/lotus-wallet/interactive.go @@ -194,6 +194,21 @@ func (c *InteractiveWallet) WalletDelete(ctx context.Context, addr address.Addre return c.under.WalletDelete(ctx, addr) } +// wallet-security InteractiveWallet WalletCustomMethod +func (c *InteractiveWallet) WalletCustomMethod(ctx context.Context, meth api.WalletMethod, args []interface{}) (interface{}, error) { + err := c.accept(func() error { + fmt.Println("-----") + fmt.Println("ACTION: WalletCustomMethod - Wallet extension operation") + fmt.Printf("METHOD: %s\n", meth) + fmt.Printf("Args: %s\n", args) + return nil + }) + if err != nil { + return nil, err + } + return c.under.WalletCustomMethod(ctx, meth, args) +} + func (c *InteractiveWallet) accept(prompt func() error) error { c.lk.Lock() defer c.lk.Unlock() diff --git a/cmd/lotus-wallet/logged.go b/cmd/lotus-wallet/logged.go index 4f07d6ae46e..87b0bbd2a1d 100644 --- a/cmd/lotus-wallet/logged.go +++ b/cmd/lotus-wallet/logged.go @@ -87,3 +87,9 @@ func (c *LoggedWallet) WalletDelete(ctx context.Context, addr address.Address) e return c.under.WalletDelete(ctx, addr) } + +// wallet-security LoggedWallet WalletCustomMethod +func (c *LoggedWallet) WalletCustomMethod(ctx context.Context, meth api.WalletMethod, args []interface{}) (interface{}, error) { + log.Infof("LoggedWallet WalletCustomMethod meth %+v args %+v ", meth, args) + return c.under.WalletCustomMethod(ctx, meth, args) +} diff --git a/cmd/lotus-wallet/main.go b/cmd/lotus-wallet/main.go index 8360dae15d0..b12118c1ce9 100644 --- a/cmd/lotus-wallet/main.go +++ b/cmd/lotus-wallet/main.go @@ -78,7 +78,9 @@ To configure your lotus node to use a remote wallet: }, }, - Commands: local, + // wallet-security GetWalletCmd + // Commands: local, + Commands: append(local, lcli.GetWalletCmd()...), } app.Setup() diff --git a/cmd/lotus/daemon.go b/cmd/lotus/daemon.go index 59f9d725888..17a84ba44fd 100644 --- a/cmd/lotus/daemon.go +++ b/cmd/lotus/daemon.go @@ -50,6 +50,9 @@ import ( "github.com/filecoin-project/lotus/node/modules/testing" "github.com/filecoin-project/lotus/node/repo" "github.com/filecoin-project/lotus/storage/sealer/ffiwrapper" + + // wallet-security api + "github.com/filecoin-project/lotus/chain/wallet" ) const ( @@ -235,6 +238,18 @@ var DaemonCmd = &cli.Command{ } freshRepo := err != repo.ErrRepoExists + // wallet-security keystore/passwd + passwdPath, err := homedir.Expand(cctx.String("repo")) + if err != nil { + return err + } + ok := wallet.GetSetupState(passwdPath + "/keystore/passwd") + if !ok { + log.Info("Passwd is not setup") + } else { + log.Info("Passwd is setup") + } + if !isLite { if err := paramfetch.GetParams(lcli.ReqContext(cctx), build.ParametersJSON(), build.SrsJSON(), 0); err != nil { return xerrors.Errorf("fetching proof parameters: %w", err) diff --git a/documentation/en/api-v0-methods.md b/documentation/en/api-v0-methods.md index 3e5d0dea4da..35fbb1abbf8 100644 --- a/documentation/en/api-v0-methods.md +++ b/documentation/en/api-v0-methods.md @@ -229,6 +229,7 @@ * [SyncValidateTipset](#SyncValidateTipset) * [Wallet](#Wallet) * [WalletBalance](#WalletBalance) + * [WalletCustomMethod](#WalletCustomMethod) * [WalletDefaultAddress](#WalletDefaultAddress) * [WalletDelete](#WalletDelete) * [WalletExport](#WalletExport) @@ -7471,6 +7472,25 @@ Inputs: Response: `"0"` +### WalletCustomMethod +wallet-security FullNodeExt WalletCustomMethod +WalletCustomMethod wallet extension operation + + +Perms: admin + +Inputs: +```json +[ + 0, + [ + {} + ] +] +``` + +Response: `{}` + ### WalletDefaultAddress WalletDefaultAddress returns the address marked as default in the wallet. diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index dc98ffae918..f39bcae49a5 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -282,6 +282,7 @@ * [SyncValidateTipset](#SyncValidateTipset) * [Wallet](#Wallet) * [WalletBalance](#WalletBalance) + * [WalletCustomMethod](#WalletCustomMethod) * [WalletDefaultAddress](#WalletDefaultAddress) * [WalletDelete](#WalletDelete) * [WalletExport](#WalletExport) @@ -8727,6 +8728,25 @@ Inputs: Response: `"0"` +### WalletCustomMethod +wallet-security FullNodeExt WalletCustomMethod +WalletCustomMethod wallet extension operation + + +Perms: admin + +Inputs: +```json +[ + 0, + [ + {} + ] +] +``` + +Response: `{}` + ### WalletDefaultAddress WalletDefaultAddress returns the address marked as default in the wallet. From bd6a5ebc340ef4f6deac3d7a9048eafc7af0390f Mon Sep 17 00:00:00 2001 From: cdcdx Date: Wed, 3 May 2023 01:14:23 +0800 Subject: [PATCH 2/8] fix 'git --no-pager diff' --- api/mocks/mock_full.go | 32 ++++++++++---------- api/proxy_gen.go | 54 +++++++++++++++++----------------- api/v0api/proxy_gen.go | 26 ++++++++-------- api/v0api/v0mocks/mock_full.go | 33 +++++++++++---------- chain/wallet/wallet_aes.go | 3 +- chain/wallet/wallet_ext.go | 4 ++- 6 files changed, 78 insertions(+), 74 deletions(-) diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index fc1bf586c68..2f0d7c534b2 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -3950,6 +3950,22 @@ func (mr *MockFullNodeMockRecorder) WalletBalance(arg0, arg1 interface{}) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletBalance", reflect.TypeOf((*MockFullNode)(nil).WalletBalance), arg0, arg1) } +// wallet-security MockFullNode WalletCustomMethod +// WalletCustomMethod mocks base method +func (m *MockFullNode) WalletCustomMethod(arg0 context.Context, arg1 api.WalletMethod, arg2 []interface{}) (interface{}, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WalletCustomMethod", arg0, arg1, arg2) + ret0, _ := ret[0].(interface{}) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// WalletCustomMethod indicates an expected call of WalletCustomMethod +func (mr *MockFullNodeMockRecorder) WalletCustomMethod(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletCustomMethod", reflect.TypeOf((*MockFullNode)(nil).WalletCustomMethod), arg0, arg1, arg2) +} + // WalletDefaultAddress mocks base method. func (m *MockFullNode) WalletDefaultAddress(arg0 context.Context) (address.Address, error) { m.ctrl.T.Helper() @@ -4128,22 +4144,6 @@ func (mr *MockFullNodeMockRecorder) WalletVerify(arg0, arg1, arg2, arg3 interfac return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletVerify", reflect.TypeOf((*MockFullNode)(nil).WalletVerify), arg0, arg1, arg2, arg3) } -// wallet-security MockFullNode WalletCustomMethod -// WalletCustomMethod mocks base method -func (m *MockFullNode) WalletCustomMethod(arg0 context.Context, arg1 api.WalletMethod, arg2 []interface{}) (interface{}, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WalletCustomMethod", arg0, arg1, arg2) - ret0, _ := ret[0].(interface{}) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// WalletCustomMethod indicates an expected call of WalletCustomMethod -func (mr *MockFullNodeMockRecorder) WalletCustomMethod(arg0, arg1, arg2 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletCustomMethod", reflect.TypeOf((*MockFullNode)(nil).WalletCustomMethod), arg0, arg1, arg2) -} - // Web3ClientVersion mocks base method. func (m *MockFullNode) Web3ClientVersion(arg0 context.Context) (string, error) { m.ctrl.T.Helper() diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 5d217d8e341..249d4575cee 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -584,6 +584,9 @@ type FullNodeMethods struct { WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) `perm:"read"` + // wallet-security FullNodeStructExt WalletCustomMethod + WalletCustomMethod func(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) `perm:"admin"` + WalletDefaultAddress func(p0 context.Context) (address.Address, error) `perm:"write"` WalletDelete func(p0 context.Context, p1 address.Address) error `perm:"admin"` @@ -608,9 +611,6 @@ type FullNodeMethods struct { WalletVerify func(p0 context.Context, p1 address.Address, p2 []byte, p3 *crypto.Signature) (bool, error) `perm:"read"` - // wallet-security FullNodeStructExt WalletCustomMethod - WalletCustomMethod func(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) `perm:"admin"` - Web3ClientVersion func(p0 context.Context) (string, error) `perm:"read"` } @@ -1140,6 +1140,9 @@ type WalletStruct struct { } type WalletMethods struct { + // wallet-security WalletStructExt WalletCustomMethod + WalletCustomMethod func(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) `perm:"admin"` + WalletDelete func(p0 context.Context, p1 address.Address) error `perm:"admin"` WalletExport func(p0 context.Context, p1 address.Address) (*types.KeyInfo, error) `perm:"admin"` @@ -1153,9 +1156,6 @@ type WalletMethods struct { WalletNew func(p0 context.Context, p1 types.KeyType) (address.Address, error) `perm:"admin"` WalletSign func(p0 context.Context, p1 address.Address, p2 []byte, p3 MsgMeta) (*crypto.Signature, error) `perm:"admin"` - - // wallet-security WalletStructExt WalletCustomMethod - WalletCustomMethod func(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) `perm:"admin"` } type WalletStub struct { @@ -3895,6 +3895,16 @@ func (s *FullNodeStub) WalletBalance(p0 context.Context, p1 address.Address) (ty return *new(types.BigInt), ErrNotSupported } +func (s *FullNodeStruct) WalletCustomMethod(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) { + if s.Internal.WalletCustomMethod == nil { + return nil, ErrNotSupported + } + return s.Internal.WalletCustomMethod(p0, p1, p2) +} +func (s *FullNodeStub) WalletCustomMethod(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) { + return nil, ErrNotSupported +} + func (s *FullNodeStruct) WalletDefaultAddress(p0 context.Context) (address.Address, error) { if s.Internal.WalletDefaultAddress == nil { return *new(address.Address), ErrNotSupported @@ -4027,16 +4037,6 @@ func (s *FullNodeStub) WalletVerify(p0 context.Context, p1 address.Address, p2 [ return false, ErrNotSupported } -func (s *FullNodeStruct) WalletCustomMethod(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) { - if s.Internal.WalletCustomMethod == nil { - return nil, ErrNotSupported - } - return s.Internal.WalletCustomMethod(p0, p1, p2) -} -func (s *FullNodeStub) WalletCustomMethod(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) { - return nil, ErrNotSupported -} - func (s *FullNodeStruct) Web3ClientVersion(p0 context.Context) (string, error) { if s.Internal.Web3ClientVersion == nil { return "", ErrNotSupported @@ -6644,6 +6644,17 @@ func (s *StorageMinerStub) WorkerStats(p0 context.Context) (map[uuid.UUID]storif return *new(map[uuid.UUID]storiface.WorkerStats), ErrNotSupported } +// wallet-security WalletStruct WalletCustomMethod +func (s *WalletStruct) WalletCustomMethod(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) { + if s.Internal.WalletCustomMethod == nil { + return nil, ErrNotSupported + } + return s.Internal.WalletCustomMethod(p0, p1, p2) +} +func (s *WalletStub) WalletCustomMethod(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) { + return nil, ErrNotSupported +} + func (s *WalletStruct) WalletDelete(p0 context.Context, p1 address.Address) error { if s.Internal.WalletDelete == nil { return ErrNotSupported @@ -6721,17 +6732,6 @@ func (s *WalletStub) WalletSign(p0 context.Context, p1 address.Address, p2 []byt return nil, ErrNotSupported } -// wallet-security WalletStruct WalletCustomMethod -func (s *WalletStruct) WalletCustomMethod(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) { - if s.Internal.WalletCustomMethod == nil { - return nil, ErrNotSupported - } - return s.Internal.WalletCustomMethod(p0, p1, p2) -} -func (s *WalletStub) WalletCustomMethod(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) { - return nil, ErrNotSupported -} - func (s *WorkerStruct) AddPiece(p0 context.Context, p1 storiface.SectorRef, p2 []abi.UnpaddedPieceSize, p3 abi.UnpaddedPieceSize, p4 storiface.Data) (storiface.CallID, error) { if s.Internal.AddPiece == nil { return *new(storiface.CallID), ErrNotSupported diff --git a/api/v0api/proxy_gen.go b/api/v0api/proxy_gen.go index b1a88c54164..0e27d71230e 100644 --- a/api/v0api/proxy_gen.go +++ b/api/v0api/proxy_gen.go @@ -395,6 +395,9 @@ type FullNodeMethods struct { WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) `perm:"read"` + // wallet-security FullNodeStructExt WalletCustomMethod + WalletCustomMethod func(p0 context.Context, p1 api.WalletMethod, p2 []interface{}) (interface{}, error) `perm:"admin"` + WalletDefaultAddress func(p0 context.Context) (address.Address, error) `perm:"write"` WalletDelete func(p0 context.Context, p1 address.Address) error `perm:"admin"` @@ -419,9 +422,6 @@ type FullNodeMethods struct { WalletVerify func(p0 context.Context, p1 address.Address, p2 []byte, p3 *crypto.Signature) (bool, error) `perm:"read"` - // wallet-security FullNodeStructExt WalletCustomMethod - WalletCustomMethod func(p0 context.Context, p1 api.WalletMethod, p2 []interface{}) (interface{}, error) `perm:"admin"` - } type FullNodeStub struct { @@ -2447,6 +2447,16 @@ func (s *FullNodeStub) WalletBalance(p0 context.Context, p1 address.Address) (ty return *new(types.BigInt), ErrNotSupported } +func (s *FullNodeStruct) WalletCustomMethod(p0 context.Context, p1 api.WalletMethod, p2 []interface{}) (interface{}, error) { + if s.Internal.WalletCustomMethod == nil { + return nil, ErrNotSupported + } + return s.Internal.WalletCustomMethod(p0, p1, p2) +} +func (s *FullNodeStub) WalletCustomMethod(p0 context.Context, p1 api.WalletMethod, p2 []interface{}) (interface{}, error) { + return nil, ErrNotSupported +} + func (s *FullNodeStruct) WalletDefaultAddress(p0 context.Context) (address.Address, error) { if s.Internal.WalletDefaultAddress == nil { return *new(address.Address), ErrNotSupported @@ -2579,16 +2589,6 @@ func (s *FullNodeStub) WalletVerify(p0 context.Context, p1 address.Address, p2 [ return false, ErrNotSupported } -func (s *FullNodeStruct) WalletCustomMethod(p0 context.Context, p1 api.WalletMethod, p2 []interface{}) (interface{}, error) { - if s.Internal.WalletCustomMethod == nil { - return nil, ErrNotSupported - } - return s.Internal.WalletCustomMethod(p0, p1, p2) -} -func (s *FullNodeStub) WalletCustomMethod(p0 context.Context, p1 api.WalletMethod, p2 []interface{}) (interface{}, error) { - return nil, ErrNotSupported -} - func (s *GatewayStruct) ChainGetBlockMessages(p0 context.Context, p1 cid.Cid) (*api.BlockMessages, error) { if s.Internal.ChainGetBlockMessages == nil { return nil, ErrNotSupported diff --git a/api/v0api/v0mocks/mock_full.go b/api/v0api/v0mocks/mock_full.go index 311471a7a33..55ece8fcdb2 100644 --- a/api/v0api/v0mocks/mock_full.go +++ b/api/v0api/v0mocks/mock_full.go @@ -3203,6 +3203,23 @@ func (mr *MockFullNodeMockRecorder) WalletBalance(arg0, arg1 interface{}) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletBalance", reflect.TypeOf((*MockFullNode)(nil).WalletBalance), arg0, arg1) } +// wallet-security MockFullNode WalletCustomMethod +// WalletCustomMethod mocks base method +func (m *MockFullNode) WalletCustomMethod(arg0 context.Context, arg1 api.WalletMethod, arg2 []interface{}) (interface{}, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WalletCustomMethod", arg0, arg1, arg2) + ret0, _ := ret[0].(interface{}) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// WalletCustomMethod indicates an expected call of WalletCustomMethod +func (mr *MockFullNodeMockRecorder) WalletCustomMethod(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletCustomMethod", reflect.TypeOf((*MockFullNode)(nil).WalletCustomMethod), arg0, arg1, arg2) +} + + // WalletDefaultAddress mocks base method. func (m *MockFullNode) WalletDefaultAddress(arg0 context.Context) (address.Address, error) { m.ctrl.T.Helper() @@ -3380,19 +3397,3 @@ func (mr *MockFullNodeMockRecorder) WalletVerify(arg0, arg1, arg2, arg3 interfac mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletVerify", reflect.TypeOf((*MockFullNode)(nil).WalletVerify), arg0, arg1, arg2, arg3) } - -// wallet-security MockFullNode WalletCustomMethod -// WalletCustomMethod mocks base method -func (m *MockFullNode) WalletCustomMethod(arg0 context.Context, arg1 api.WalletMethod, arg2 []interface{}) (interface{}, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WalletCustomMethod", arg0, arg1, arg2) - ret0, _ := ret[0].(interface{}) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// WalletCustomMethod indicates an expected call of WalletCustomMethod -func (mr *MockFullNodeMockRecorder) WalletCustomMethod(arg0, arg1, arg2 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletCustomMethod", reflect.TypeOf((*MockFullNode)(nil).WalletCustomMethod), arg0, arg1, arg2) -} diff --git a/chain/wallet/wallet_aes.go b/chain/wallet/wallet_aes.go index 5236f61f95c..f5ae90d5f90 100644 --- a/chain/wallet/wallet_aes.go +++ b/chain/wallet/wallet_aes.go @@ -9,9 +9,10 @@ import ( "os" "regexp" + "golang.org/x/xerrors" + "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet/key" - "golang.org/x/xerrors" ) var substitutePwd = []byte("****************") diff --git a/chain/wallet/wallet_ext.go b/chain/wallet/wallet_ext.go index 0f83a6e7c37..396fa328c77 100644 --- a/chain/wallet/wallet_ext.go +++ b/chain/wallet/wallet_ext.go @@ -7,11 +7,13 @@ import ( "sort" "strings" + "golang.org/x/xerrors" + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet/key" - "golang.org/x/xerrors" ) // wallet-security LocalWallet WalletCustomMethod From ef37d6a0fea10f48b68ad7599e6f0912d6295f92 Mon Sep 17 00:00:00 2001 From: cdcdx Date: Wed, 3 May 2023 01:26:32 +0800 Subject: [PATCH 3/8] fix 'git --no-pager diff' --- api/mocks/mock_full.go | 5 ++--- api/proxy_gen.go | 4 ++-- api/v0api/proxy_gen.go | 3 +-- api/v0api/v0mocks/mock_full.go | 6 ++---- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index 2f0d7c534b2..ec1b9f886cc 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -3950,8 +3950,7 @@ func (mr *MockFullNodeMockRecorder) WalletBalance(arg0, arg1 interface{}) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletBalance", reflect.TypeOf((*MockFullNode)(nil).WalletBalance), arg0, arg1) } -// wallet-security MockFullNode WalletCustomMethod -// WalletCustomMethod mocks base method +// WalletCustomMethod mocks base method. func (m *MockFullNode) WalletCustomMethod(arg0 context.Context, arg1 api.WalletMethod, arg2 []interface{}) (interface{}, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "WalletCustomMethod", arg0, arg1, arg2) @@ -3960,7 +3959,7 @@ func (m *MockFullNode) WalletCustomMethod(arg0 context.Context, arg1 api.WalletM return ret0, ret1 } -// WalletCustomMethod indicates an expected call of WalletCustomMethod +// WalletCustomMethod indicates an expected call of WalletCustomMethod. func (mr *MockFullNodeMockRecorder) WalletCustomMethod(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletCustomMethod", reflect.TypeOf((*MockFullNode)(nil).WalletCustomMethod), arg0, arg1, arg2) diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 249d4575cee..543cd39ae15 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -584,7 +584,6 @@ type FullNodeMethods struct { WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) `perm:"read"` - // wallet-security FullNodeStructExt WalletCustomMethod WalletCustomMethod func(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) `perm:"admin"` WalletDefaultAddress func(p0 context.Context) (address.Address, error) `perm:"write"` @@ -3901,6 +3900,7 @@ func (s *FullNodeStruct) WalletCustomMethod(p0 context.Context, p1 WalletMethod, } return s.Internal.WalletCustomMethod(p0, p1, p2) } + func (s *FullNodeStub) WalletCustomMethod(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) { return nil, ErrNotSupported } @@ -6644,13 +6644,13 @@ func (s *StorageMinerStub) WorkerStats(p0 context.Context) (map[uuid.UUID]storif return *new(map[uuid.UUID]storiface.WorkerStats), ErrNotSupported } -// wallet-security WalletStruct WalletCustomMethod func (s *WalletStruct) WalletCustomMethod(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) { if s.Internal.WalletCustomMethod == nil { return nil, ErrNotSupported } return s.Internal.WalletCustomMethod(p0, p1, p2) } + func (s *WalletStub) WalletCustomMethod(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) { return nil, ErrNotSupported } diff --git a/api/v0api/proxy_gen.go b/api/v0api/proxy_gen.go index 0e27d71230e..704eccf5833 100644 --- a/api/v0api/proxy_gen.go +++ b/api/v0api/proxy_gen.go @@ -395,7 +395,6 @@ type FullNodeMethods struct { WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) `perm:"read"` - // wallet-security FullNodeStructExt WalletCustomMethod WalletCustomMethod func(p0 context.Context, p1 api.WalletMethod, p2 []interface{}) (interface{}, error) `perm:"admin"` WalletDefaultAddress func(p0 context.Context) (address.Address, error) `perm:"write"` @@ -421,7 +420,6 @@ type FullNodeMethods struct { WalletValidateAddress func(p0 context.Context, p1 string) (address.Address, error) `perm:"read"` WalletVerify func(p0 context.Context, p1 address.Address, p2 []byte, p3 *crypto.Signature) (bool, error) `perm:"read"` - } type FullNodeStub struct { @@ -2453,6 +2451,7 @@ func (s *FullNodeStruct) WalletCustomMethod(p0 context.Context, p1 api.WalletMet } return s.Internal.WalletCustomMethod(p0, p1, p2) } + func (s *FullNodeStub) WalletCustomMethod(p0 context.Context, p1 api.WalletMethod, p2 []interface{}) (interface{}, error) { return nil, ErrNotSupported } diff --git a/api/v0api/v0mocks/mock_full.go b/api/v0api/v0mocks/mock_full.go index 55ece8fcdb2..5fb8577bf10 100644 --- a/api/v0api/v0mocks/mock_full.go +++ b/api/v0api/v0mocks/mock_full.go @@ -3203,8 +3203,7 @@ func (mr *MockFullNodeMockRecorder) WalletBalance(arg0, arg1 interface{}) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletBalance", reflect.TypeOf((*MockFullNode)(nil).WalletBalance), arg0, arg1) } -// wallet-security MockFullNode WalletCustomMethod -// WalletCustomMethod mocks base method +// WalletCustomMethod mocks base method. func (m *MockFullNode) WalletCustomMethod(arg0 context.Context, arg1 api.WalletMethod, arg2 []interface{}) (interface{}, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "WalletCustomMethod", arg0, arg1, arg2) @@ -3213,13 +3212,12 @@ func (m *MockFullNode) WalletCustomMethod(arg0 context.Context, arg1 api.WalletM return ret0, ret1 } -// WalletCustomMethod indicates an expected call of WalletCustomMethod +// WalletCustomMethod indicates an expected call of WalletCustomMethod. func (mr *MockFullNodeMockRecorder) WalletCustomMethod(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletCustomMethod", reflect.TypeOf((*MockFullNode)(nil).WalletCustomMethod), arg0, arg1, arg2) } - // WalletDefaultAddress mocks base method. func (m *MockFullNode) WalletDefaultAddress(arg0 context.Context) (address.Address, error) { m.ctrl.T.Helper() From 4f8115aa11aaca8a56bc4df960a032b9e2af6211 Mon Sep 17 00:00:00 2001 From: cdcdx Date: Wed, 3 May 2023 01:33:27 +0800 Subject: [PATCH 4/8] fix 'git --no-pager diff' --- api/proxy_gen.go | 1 - 1 file changed, 1 deletion(-) diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 543cd39ae15..fc633077100 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -1139,7 +1139,6 @@ type WalletStruct struct { } type WalletMethods struct { - // wallet-security WalletStructExt WalletCustomMethod WalletCustomMethod func(p0 context.Context, p1 WalletMethod, p2 []interface{}) (interface{}, error) `perm:"admin"` WalletDelete func(p0 context.Context, p1 address.Address) error `perm:"admin"` From 8fb087602e6f3b59318f3cd3bafcee01645026f3 Mon Sep 17 00:00:00 2001 From: cdcdx Date: Wed, 3 May 2023 01:42:20 +0800 Subject: [PATCH 5/8] update full.json.gz --- build/openrpc/full.json.gz | Bin 33455 -> 33453 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index c68072b2f031cf3d09140680fd8d6feb06817018..16f2a198910941947761ebe25e5a6be0fe272472 100644 GIT binary patch delta 29749 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 UAOHMc00030|LO7-_WHC20G*?d_W%F@ delta 29760 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 From 0185173e505a077442d1ac918414ab3c1b18aff8 Mon Sep 17 00:00:00 2001 From: cdcdx Date: Wed, 3 May 2023 01:50:58 +0800 Subject: [PATCH 6/8] update gateway.json.gz update miner.json.gz update worker.json.gz --- build/openrpc/gateway.json.gz | Bin 9295 -> 9295 bytes build/openrpc/miner.json.gz | Bin 16043 -> 16041 bytes build/openrpc/worker.json.gz | Bin 5221 -> 5221 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/build/openrpc/gateway.json.gz b/build/openrpc/gateway.json.gz index 25b1983479de2466123bf653808b69cecac58aed..481e559f35d2cfbd2f9001261f26d59274d07dbd 100644 GIT binary patch literal 9295 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 diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index 470a9c5a47b8a6eb9a2093f89ad580d3fca6201f..ec7d197f3fc43ea4bc93e1afb7018a138bdefdbe 100644 GIT binary patch delta 10585 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 n2D6jElHw5v_SA>Lb| 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 z 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 h0@}~Br#bBe6%YHyyZVTALyfyGCs|L^gNW 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 delta 4341 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 Date: Wed, 3 May 2023 02:06:26 +0800 Subject: [PATCH 7/8] fix 'git --no-pager diff' --- documentation/en/cli-lotus.md | 153 ++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/documentation/en/cli-lotus.md b/documentation/en/cli-lotus.md index feb6e0f1b47..7b991d249eb 100644 --- a/documentation/en/cli-lotus.md +++ b/documentation/en/cli-lotus.md @@ -215,6 +215,11 @@ COMMANDS: delete Soft delete an address from the wallet - hard deletion needed for permanent removal market Interact with market balances help, h Shows a list of commands or help for one command + CUSTOM: + mark Manage wallet mark info + passwd Manage wallet passwd info + encrypt encrypt wallet account + decrypt decrypt wallet account OPTIONS: --help, -h show help (default: false) @@ -401,6 +406,154 @@ OPTIONS: ``` +### lotus wallet mark +``` +NAME: + lotus wallet mark - Manage wallet mark info + +USAGE: + lotus wallet mark command [command options] [arguments...] + +COMMANDS: + add Add/Update wallet mark + del Delete wallet mark + clear Clear wallet mark + help, h Shows a list of commands or help for one command + +OPTIONS: + --help, -h show help (default: false) + +``` + +#### lotus wallet mark add +``` +NAME: + lotus wallet mark add - Add/Update wallet mark + +USAGE: + lotus wallet mark add [command options] [address] + +OPTIONS: + --help, -h show help (default: false) + +``` + +#### lotus wallet mark del +``` +NAME: + lotus wallet mark del - Delete wallet mark + +USAGE: + lotus wallet mark del [command options] [address] + +OPTIONS: + --help, -h show help (default: false) + +``` + +#### lotus wallet mark clear +``` +NAME: + lotus wallet mark clear - Clear wallet mark + +USAGE: + lotus wallet mark clear [command options] [arguments...] + +OPTIONS: + --help, -h show help (default: false) + +``` + +### lotus wallet passwd +``` +NAME: + lotus wallet passwd - Manage wallet passwd info + +USAGE: + lotus wallet passwd command [command options] [arguments...] + +COMMANDS: + add Add wallet password + reset Reset wallet password + clear Clear wallet password + help, h Shows a list of commands or help for one command + +OPTIONS: + --help, -h show help (default: false) + +``` + +#### lotus wallet passwd add +``` +NAME: + lotus wallet passwd add - Add wallet password + +USAGE: + lotus wallet passwd add [command options] [arguments...] + +OPTIONS: + --help, -h show help (default: false) + +``` + +#### lotus wallet passwd reset +``` +NAME: + lotus wallet passwd reset - Reset wallet password + +USAGE: + lotus wallet passwd reset [command options] [arguments...] + +OPTIONS: + --help, -h show help (default: false) + +``` + +#### lotus wallet passwd clear +``` +NAME: + lotus wallet passwd clear - Clear wallet password + +USAGE: + lotus wallet passwd clear [command options] [arguments...] + +OPTIONS: + --help, -h show help (default: false) + +``` + +### lotus wallet encrypt +``` +NAME: + lotus wallet encrypt - encrypt wallet account + +USAGE: + lotus wallet encrypt [command options] [address] + +CATEGORY: + CUSTOM + +OPTIONS: + --help, -h show help (default: false) + +``` + +### lotus wallet decrypt +``` +NAME: + lotus wallet decrypt - decrypt wallet account + +USAGE: + lotus wallet decrypt [command options] [address] + +CATEGORY: + CUSTOM + +OPTIONS: + --help, -h show help (default: false) + +``` + ## lotus info ``` NAME: From aa5fab690e32ad37790b2285c1337cd9d867b331 Mon Sep 17 00:00:00 2001 From: cdcdx Date: Wed, 3 May 2023 11:39:40 +0800 Subject: [PATCH 8/8] fix 'go test cli' --- cli/send.go | 18 ++++----- cli/wallet.go | 103 +++++++++++++++++++++++++++++++------------------- 2 files changed, 74 insertions(+), 47 deletions(-) diff --git a/cli/send.go b/cli/send.go index f6c3794bc4b..b32d8c96bea 100644 --- a/cli/send.go +++ b/cli/send.go @@ -203,17 +203,17 @@ var sendCmd = &cli.Command{ params.Params = decparams } - // wallet-security WalletDefaultAddress - fullapi := srv.FullNodeAPI() - if params.From == address.Undef { - defaddr, err := fullapi.WalletDefaultAddress(ctx) - if err != nil { - return err - } - params.From = defaddr - } // wallet-security send if wallet.GetSetupStateForLocal(getWalletPwdRepo(cctx)) { + fullapi := srv.FullNodeAPI() + // wallet-security WalletDefaultAddress + if params.From == address.Undef { + defaddr, err := fullapi.WalletDefaultAddress(ctx) + if err != nil { + return err + } + params.From = defaddr + } rest, _ := fullapi.WalletCustomMethod(ctx, api.WalletIsEncrypt, []interface{}{params.From}) if rest != nil && rest.(bool) { // passwd := cctx.String("passwd") diff --git a/cli/wallet.go b/cli/wallet.go index f0ef7b79e7a..8d43afec697 100644 --- a/cli/wallet.go +++ b/cli/wallet.go @@ -119,14 +119,27 @@ var walletList = &cli.Command{ // return err // } encryptAddrs := make([]lapi.AddrListEncrypt, 0) - rest, err := api.WalletCustomMethod(ctx, lapi.WalletListForEnc, []interface{}{}) - if rest != nil { - if err != nil { - return err - } - addrs, _ := json.Marshal(rest) - if err := json.Unmarshal(addrs, &encryptAddrs); err != nil { - return err + if wallet.GetSetupStateForLocal(getWalletPwdRepo(cctx)) { + rest, err := api.WalletCustomMethod(ctx, lapi.WalletListForEnc, []interface{}{}) + if rest != nil { + if err != nil { + return err + } + addrs, _ := json.Marshal(rest) + if err := json.Unmarshal(addrs, &encryptAddrs); err != nil { + return err + } + } else { + addrs, err := api.WalletList(ctx) + if err != nil { + return err + } + for _, v := range addrs { + encryptAddrs = append(encryptAddrs, lapi.AddrListEncrypt{ + Addr: v, + Encrypt: false, + }) + } } } else { addrs, err := api.WalletList(ctx) @@ -366,25 +379,33 @@ var walletExport = &cli.Command{ // return err // } ki := new(types.KeyInfo) - rest, _ := api.WalletCustomMethod(ctx, lapi.WalletIsEncrypt, []interface{}{addr}) - if rest != nil && (wallet.GetSetupStateForLocal(getWalletPwdRepo(cctx)) && rest.(bool)) { - // passwd := cctx.String("passwd") - passwd := wallet.Prompt("Enter your Password:\n") - if passwd == "" { - return xerrors.Errorf("must enter your passwd") - } - if err := wallet.RegexpPasswd(passwd); err != nil { - return err - } + if wallet.GetSetupStateForLocal(getWalletPwdRepo(cctx)) { + rest, _ := api.WalletCustomMethod(ctx, lapi.WalletIsEncrypt, []interface{}{addr}) + if rest != nil && rest.(bool) { + // passwd := cctx.String("passwd") + passwd := wallet.Prompt("Enter your Password:\n") + if passwd == "" { + return xerrors.Errorf("must enter your passwd") + } - rest, err := api.WalletCustomMethod(ctx, lapi.WalletExportForEnc, []interface{}{addr, passwd}) - if err != nil { - return err - } - keyinfo, _ := json.Marshal(rest) - if err := json.Unmarshal(keyinfo, ki); err != nil { - return err + if err := wallet.RegexpPasswd(passwd); err != nil { + return err + } + + rest, err := api.WalletCustomMethod(ctx, lapi.WalletExportForEnc, []interface{}{addr, passwd}) + if err != nil { + return err + } + keyinfo, _ := json.Marshal(rest) + if err := json.Unmarshal(keyinfo, ki); err != nil { + return err + } + } else { + ki, err = api.WalletExport(ctx, addr) + if err != nil { + return err + } } } else { ki, err = api.WalletExport(ctx, addr) @@ -630,21 +651,27 @@ var walletDelete = &cli.Command{ // wallet-security walletdelete // return api.WalletDelete(ctx, addr) - rest, _ := api.WalletCustomMethod(ctx, lapi.WalletIsEncrypt, []interface{}{addr}) - if rest != nil && (wallet.GetSetupStateForLocal(getWalletPwdRepo(cctx)) && rest.(bool)) { - // passwd := cctx.String("passwd") - passwd := wallet.Prompt("Enter your Password:\n") - if passwd == "" { - return xerrors.Errorf("Must enter your passwd") - } + if wallet.GetSetupStateForLocal(getWalletPwdRepo(cctx)) { + rest, _ := api.WalletCustomMethod(ctx, lapi.WalletIsEncrypt, []interface{}{addr}) + if rest != nil && rest.(bool) { + // passwd := cctx.String("passwd") + passwd := wallet.Prompt("Enter your Password:\n") + if passwd == "" { + return xerrors.Errorf("Must enter your passwd") + } - if err := wallet.RegexpPasswd(passwd); err != nil { - return err - } + if err := wallet.RegexpPasswd(passwd); err != nil { + return err + } - _, err = api.WalletCustomMethod(ctx, lapi.WalletDeleteForEnc, []interface{}{addr, passwd}) - if err != nil { - return err + _, err = api.WalletCustomMethod(ctx, lapi.WalletDeleteForEnc, []interface{}{addr, passwd}) + if err != nil { + return err + } + } else { + if err := api.WalletDelete(ctx, addr); err != nil { + return err + } } } else { if err := api.WalletDelete(ctx, addr); err != nil {