From a5500e3a15e50e33a1211ce64a1350cfbab078c4 Mon Sep 17 00:00:00 2001 From: Shawn-Huang-Tron <107823650+Shawn-Huang-Tron@users.noreply.github.com> Date: Wed, 27 Dec 2023 18:09:18 +0800 Subject: [PATCH] Release 2.3.4 (#405) * feat: support loose mode for unknow param or header (#397) * feat: support loose mode for unknow param or header * fix: unused var * feat: implementation of btip52 (#398) * feat: init btip52 * feat: impletation by go-btfs-api * feat: p2p remote call * fix: decryption to cat * test: fix command test * test: command test shows that tagline is required * fix: hex private may not exists (#402) * feat: init btip52 * feat: impletation by go-btfs-api * feat: p2p remote call * fix: decryption to cat * test: fix command test * test: command test shows that tagline is required * fix: hex private may not exists * fix: libp2p crypto to eth ecdsa (#403) * feat: update version number (#404) --- core/commands/commands_test.go | 2 + core/commands/encrypt.go | 168 +++++++++++++++++++++++++++++++++ core/commands/root.go | 15 +-- s3/api/requests/parsers.go | 17 ++-- version.go | 2 +- 5 files changed, 189 insertions(+), 15 deletions(-) create mode 100644 core/commands/encrypt.go diff --git a/core/commands/commands_test.go b/core/commands/commands_test.go index aafe6fc7b..bcc0877a9 100644 --- a/core/commands/commands_test.go +++ b/core/commands/commands_test.go @@ -358,6 +358,8 @@ func TestCommands(t *testing.T) { "/accesskey/get", "/accesskey/list", "/cheque/fix_cheque_cashout", + "/encrypt", + "/decrypt", } cmdSet := make(map[string]struct{}) diff --git a/core/commands/encrypt.go b/core/commands/encrypt.go new file mode 100644 index 000000000..d9ef4a7f9 --- /dev/null +++ b/core/commands/encrypt.go @@ -0,0 +1,168 @@ +package commands + +import ( + "bytes" + "crypto/rand" + "encoding/base64" + "errors" + "io" + "os" + + shell "github.com/bittorrent/go-btfs-api" + cmds "github.com/bittorrent/go-btfs-cmds" + cp "github.com/bittorrent/go-btfs-common/crypto" + "github.com/bittorrent/go-btfs/core/commands/cmdenv" + "github.com/bittorrent/go-btfs/core/corehttp/remote" + ethCrypto "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/ecies" + peer "github.com/libp2p/go-libp2p/core/peer" +) + +const toOption = "to" +const fromOption = "from" + +var encryptCmd = &cmds.Command{ + Helptext: cmds.HelpText{ + Tagline: "encrypt file with the public key of the peer", + }, + Arguments: []cmds.Argument{ + cmds.FileArg("path", true, true, "The path to a file to be added to btfs.").EnableRecursive().EnableStdin(), + }, + Options: []cmds.Option{ + cmds.StringOption(toOption, "the peerID of the node which you want to share with"), + }, + Run: func(r *cmds.Request, re cmds.ResponseEmitter, e cmds.Environment) error { + n, err := cmdenv.GetNode(e) + if err != nil { + return err + } + to, ok := r.Options[toOption].(string) + if !ok { + to = n.Identity.String() + } + id, err := peer.Decode(to) + if err != nil { + return errors.New("the to option must be a valid peerID") + } + p2pPk, err := id.ExtractPublicKey() + if err != nil { + return errors.New("can't extract public key from peerID") + } + pkBytes, err := cp.Secp256k1PublicKeyRaw(p2pPk) + if err != nil { + return errors.New("can't change from p2p public key to secp256k1 public key from peerID") + } + + ethPk, err := ethCrypto.UnmarshalPubkey(pkBytes) + if err != nil { + return errors.New("can't unmarshall public key from peerID") + } + + eciesPk := ecies.ImportECDSAPublic(ethPk) + it := r.Files.Entries() + file, err := cmdenv.GetFileArg(it) + if err != nil { + return err + } + originalBytes, err := io.ReadAll(file) + if err != nil { + return err + } + encryptedBytes, err := ECCEncrypt(originalBytes, *eciesPk) + if err != nil { + return err + } + btfsClient := shell.NewLocalShell() + cid, err := btfsClient.Add(bytes.NewReader(encryptedBytes), shell.Pin(true)) + if err != nil { + return err + } + return re.Emit(cid) + }, +} + +var decryptCmd = &cmds.Command{ + Helptext: cmds.HelpText{ + Tagline: "decrypt the content of a CID with the private key of this peer", + }, + Arguments: []cmds.Argument{ + cmds.StringArg("cid", true, false, "the CID of the encrypted file"), + }, + Options: []cmds.Option{ + cmds.StringOption(fromOption, "specify the source peerID of CID"), + }, + Run: func(r *cmds.Request, re cmds.ResponseEmitter, e cmds.Environment) error { + conf, err := cmdenv.GetConfig(e) + if err != nil { + return err + } + n, err := cmdenv.GetNode(e) + if err != nil { + return err + } + api, err := cmdenv.GetApi(e, r) + if err != nil { + return err + } + + var readClose io.ReadCloser + cid := r.Arguments[0] + from, ok := r.Options[fromOption].(string) + if ok { + peerID, err := peer.Decode(from) + if err != nil { + return err + } + b, err := remote.P2PCallStrings(r.Context, n, api, peerID, "/decryption", cid) + if err != nil { + return err + } + readClose = io.NopCloser(bytes.NewReader(b)) + } else { + readClose, err = shell.NewLocalShell().Cat(cid) + if err != nil { + return err + } + } + + pkbytesOri, err := base64.StdEncoding.DecodeString(conf.Identity.PrivKey) + if err != nil { + return err + } + ecdsaPrivateKey, err := ethCrypto.ToECDSA(pkbytesOri[4:]) + if err != nil { + return err + } + eciesPrivateKey := ecies.ImportECDSA(ecdsaPrivateKey) + endata, err := io.ReadAll(readClose) + if err != nil { + return err + } + defer readClose.Close() + dedata, err := ECCDecrypt(endata, *eciesPrivateKey) + if err != nil { + return errors.New("decryption is failed, maybe the content of encryption is not encrypted by your public key") + } + fileName := "./decrypt-file-of-" + cid + f, err := os.Create(fileName) + if err != nil { + return err + } + defer f.Close() + _, err = f.Write(dedata) + if err != nil { + return err + } + return re.Emit("decrypted file name is: " + fileName) + }, +} + +func ECCEncrypt(pt []byte, puk ecies.PublicKey) ([]byte, error) { + ct, err := ecies.Encrypt(rand.Reader, &puk, pt, nil, nil) + return ct, err +} + +func ECCDecrypt(ct []byte, prk ecies.PrivateKey) ([]byte, error) { + pt, err := prk.Decrypt(ct, nil, nil) + return pt, err +} diff --git a/core/commands/root.go b/core/commands/root.go index 0c5bb9a46..0b41fb0ef 100644 --- a/core/commands/root.go +++ b/core/commands/root.go @@ -183,6 +183,8 @@ var rootSubcommands = map[string]*cmds.Command{ "backup": BackupCmd, "recovery": RecoveryCmd, "accesskey": AccessKeyCmd, + "encrypt": encryptCmd, + "decrypt": decryptCmd, } // RootRO is the readonly version of Root @@ -199,7 +201,7 @@ var VersionROCmd = &cmds.Command{} var rootROSubcommands = map[string]*cmds.Command{ "commands": CommandsDaemonROCmd, "cat": CatCmd, - "block": &cmds.Command{ + "block": { Subcommands: map[string]*cmds.Command{ "stat": blockStatCmd, "get": blockGetCmd, @@ -235,14 +237,14 @@ var rootROSubcommands = map[string]*cmds.Command{ var RootRemote = &cmds.Command{} var rootRemoteSubcommands = map[string]*cmds.Command{ - "storage": &cmds.Command{ + "storage": { Subcommands: map[string]*cmds.Command{ - "challenge": &cmds.Command{ + "challenge": { Subcommands: map[string]*cmds.Command{ "response": challenge.StorageChallengeResponseCmd, }, }, - "upload": &cmds.Command{ + "upload": { Subcommands: map[string]*cmds.Command{ "init": upload.StorageUploadInitCmd, "supporttokens": upload.StorageUploadSupportTokensCmd, @@ -250,18 +252,19 @@ var rootRemoteSubcommands = map[string]*cmds.Command{ "cheque": upload.StorageUploadChequeCmd, }, }, - "dcrepair": &cmds.Command{ + "dcrepair": { Subcommands: map[string]*cmds.Command{ "response": upload.HostRepairResponseCmd, }, }, }, }, - "p2p": &cmds.Command{ + "p2p": { Subcommands: map[string]*cmds.Command{ "handshake": P2phandshakeCmd, }, }, + "decryption": CatCmd, } func init() { diff --git a/s3/api/requests/parsers.go b/s3/api/requests/parsers.go index 37c6f89c4..69d6e1c5a 100644 --- a/s3/api/requests/parsers.go +++ b/s3/api/requests/parsers.go @@ -4,15 +4,16 @@ import ( "encoding/base64" "encoding/xml" "errors" - "github.com/aws/aws-sdk-go/private/protocol" - "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil" - "github.com/gorilla/mux" "net/http" "net/url" "reflect" "strconv" "strings" "time" + + "github.com/aws/aws-sdk-go/private/protocol" + "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil" + "github.com/gorilla/mux" ) type fields map[string]bool @@ -85,7 +86,7 @@ func parseLocationField(vars map[string]string, query url.Values, headers http.H loca := ftag.Get("location") name := ftag.Get("locationName") requ := ftag.Get("required") == "true" - supp := supports[ft.Name] + // supp := supports[ft.Name] var ( vals map[string]*string isVals bool @@ -105,10 +106,10 @@ func parseLocationField(vars map[string]string, query url.Values, headers http.H default: return } - if !supp && has { - err = ErrWithUnsupportedParam{name} - return - } + // if !supp && has { + // err = ErrWithUnsupportedParam{name} + // return + // } if requ && !has { err = ErrMissingRequiredParam{name} return diff --git a/version.go b/version.go index 04dee3da2..c5616df32 100644 --- a/version.go +++ b/version.go @@ -4,7 +4,7 @@ package btfs var CurrentCommit string // CurrentVersionNumber is the current application's version literal -const CurrentVersionNumber = "2.3.3" +const CurrentVersionNumber = "2.3.4" const ApiVersion = "/go-btfs/" + CurrentVersionNumber + "/"