github.com/rayrapetyan/go-ethereum@v1.8.21/cmd/swarm/access.go (about)

     1  // Copyright 2018 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // go-ethereum is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  package main
    17  
    18  import (
    19  	"crypto/rand"
    20  	"encoding/json"
    21  	"fmt"
    22  	"io"
    23  	"io/ioutil"
    24  	"strings"
    25  
    26  	"github.com/ethereum/go-ethereum/cmd/utils"
    27  	"github.com/ethereum/go-ethereum/swarm/api"
    28  	"github.com/ethereum/go-ethereum/swarm/api/client"
    29  	"gopkg.in/urfave/cli.v1"
    30  )
    31  
    32  var (
    33  	salt          = make([]byte, 32)
    34  	accessCommand = cli.Command{
    35  		CustomHelpTemplate: helpTemplate,
    36  		Name:               "access",
    37  		Usage:              "encrypts a reference and embeds it into a root manifest",
    38  		ArgsUsage:          "<ref>",
    39  		Description:        "encrypts a reference and embeds it into a root manifest",
    40  		Subcommands: []cli.Command{
    41  			{
    42  				CustomHelpTemplate: helpTemplate,
    43  				Name:               "new",
    44  				Usage:              "encrypts a reference and embeds it into a root manifest",
    45  				ArgsUsage:          "<ref>",
    46  				Description:        "encrypts a reference and embeds it into a root access manifest and prints the resulting manifest",
    47  				Subcommands: []cli.Command{
    48  					{
    49  						Action:             accessNewPass,
    50  						CustomHelpTemplate: helpTemplate,
    51  						Flags: []cli.Flag{
    52  							utils.PasswordFileFlag,
    53  							SwarmDryRunFlag,
    54  						},
    55  						Name:        "pass",
    56  						Usage:       "encrypts a reference with a password and embeds it into a root manifest",
    57  						ArgsUsage:   "<ref>",
    58  						Description: "encrypts a reference and embeds it into a root access manifest and prints the resulting manifest",
    59  					},
    60  					{
    61  						Action:             accessNewPK,
    62  						CustomHelpTemplate: helpTemplate,
    63  						Flags: []cli.Flag{
    64  							utils.PasswordFileFlag,
    65  							SwarmDryRunFlag,
    66  							SwarmAccessGrantKeyFlag,
    67  						},
    68  						Name:        "pk",
    69  						Usage:       "encrypts a reference with the node's private key and a given grantee's public key and embeds it into a root manifest",
    70  						ArgsUsage:   "<ref>",
    71  						Description: "encrypts a reference and embeds it into a root access manifest and prints the resulting manifest",
    72  					},
    73  					{
    74  						Action:             accessNewACT,
    75  						CustomHelpTemplate: helpTemplate,
    76  						Flags: []cli.Flag{
    77  							SwarmAccessGrantKeysFlag,
    78  							SwarmDryRunFlag,
    79  							utils.PasswordFileFlag,
    80  						},
    81  						Name:        "act",
    82  						Usage:       "encrypts a reference with the node's private key and a given grantee's public key and embeds it into a root manifest",
    83  						ArgsUsage:   "<ref>",
    84  						Description: "encrypts a reference and embeds it into a root access manifest and prints the resulting manifest",
    85  					},
    86  				},
    87  			},
    88  		},
    89  	}
    90  )
    91  
    92  func init() {
    93  	if _, err := io.ReadFull(rand.Reader, salt); err != nil {
    94  		panic("reading from crypto/rand failed: " + err.Error())
    95  	}
    96  }
    97  
    98  func accessNewPass(ctx *cli.Context) {
    99  	args := ctx.Args()
   100  	if len(args) != 1 {
   101  		utils.Fatalf("Expected 1 argument - the ref")
   102  	}
   103  
   104  	var (
   105  		ae        *api.AccessEntry
   106  		accessKey []byte
   107  		err       error
   108  		ref       = args[0]
   109  		password  = getPassPhrase("", 0, makePasswordList(ctx))
   110  		dryRun    = ctx.Bool(SwarmDryRunFlag.Name)
   111  	)
   112  	accessKey, ae, err = api.DoPassword(ctx, password, salt)
   113  	if err != nil {
   114  		utils.Fatalf("error getting session key: %v", err)
   115  	}
   116  	m, err := api.GenerateAccessControlManifest(ctx, ref, accessKey, ae)
   117  	if err != nil {
   118  		utils.Fatalf("had an error generating the manifest: %v", err)
   119  	}
   120  	if dryRun {
   121  		err = printManifests(m, nil)
   122  		if err != nil {
   123  			utils.Fatalf("had an error printing the manifests: %v", err)
   124  		}
   125  	} else {
   126  		err = uploadManifests(ctx, m, nil)
   127  		if err != nil {
   128  			utils.Fatalf("had an error uploading the manifests: %v", err)
   129  		}
   130  	}
   131  }
   132  
   133  func accessNewPK(ctx *cli.Context) {
   134  	args := ctx.Args()
   135  	if len(args) != 1 {
   136  		utils.Fatalf("Expected 1 argument - the ref")
   137  	}
   138  
   139  	var (
   140  		ae               *api.AccessEntry
   141  		sessionKey       []byte
   142  		err              error
   143  		ref              = args[0]
   144  		privateKey       = getPrivKey(ctx)
   145  		granteePublicKey = ctx.String(SwarmAccessGrantKeyFlag.Name)
   146  		dryRun           = ctx.Bool(SwarmDryRunFlag.Name)
   147  	)
   148  	sessionKey, ae, err = api.DoPK(ctx, privateKey, granteePublicKey, salt)
   149  	if err != nil {
   150  		utils.Fatalf("error getting session key: %v", err)
   151  	}
   152  	m, err := api.GenerateAccessControlManifest(ctx, ref, sessionKey, ae)
   153  	if err != nil {
   154  		utils.Fatalf("had an error generating the manifest: %v", err)
   155  	}
   156  	if dryRun {
   157  		err = printManifests(m, nil)
   158  		if err != nil {
   159  			utils.Fatalf("had an error printing the manifests: %v", err)
   160  		}
   161  	} else {
   162  		err = uploadManifests(ctx, m, nil)
   163  		if err != nil {
   164  			utils.Fatalf("had an error uploading the manifests: %v", err)
   165  		}
   166  	}
   167  }
   168  
   169  func accessNewACT(ctx *cli.Context) {
   170  	args := ctx.Args()
   171  	if len(args) != 1 {
   172  		utils.Fatalf("Expected 1 argument - the ref")
   173  	}
   174  
   175  	var (
   176  		ae                   *api.AccessEntry
   177  		actManifest          *api.Manifest
   178  		accessKey            []byte
   179  		err                  error
   180  		ref                  = args[0]
   181  		pkGrantees           = []string{}
   182  		passGrantees         = []string{}
   183  		pkGranteesFilename   = ctx.String(SwarmAccessGrantKeysFlag.Name)
   184  		passGranteesFilename = ctx.String(utils.PasswordFileFlag.Name)
   185  		privateKey           = getPrivKey(ctx)
   186  		dryRun               = ctx.Bool(SwarmDryRunFlag.Name)
   187  	)
   188  	if pkGranteesFilename == "" && passGranteesFilename == "" {
   189  		utils.Fatalf("you have to provide either a grantee public-keys file or an encryption passwords file (or both)")
   190  	}
   191  
   192  	if pkGranteesFilename != "" {
   193  		bytes, err := ioutil.ReadFile(pkGranteesFilename)
   194  		if err != nil {
   195  			utils.Fatalf("had an error reading the grantee public key list")
   196  		}
   197  		pkGrantees = strings.Split(strings.Trim(string(bytes), "\n"), "\n")
   198  	}
   199  
   200  	if passGranteesFilename != "" {
   201  		bytes, err := ioutil.ReadFile(passGranteesFilename)
   202  		if err != nil {
   203  			utils.Fatalf("could not read password filename: %v", err)
   204  		}
   205  		passGrantees = strings.Split(strings.Trim(string(bytes), "\n"), "\n")
   206  	}
   207  	accessKey, ae, actManifest, err = api.DoACT(ctx, privateKey, salt, pkGrantees, passGrantees)
   208  	if err != nil {
   209  		utils.Fatalf("error generating ACT manifest: %v", err)
   210  	}
   211  
   212  	if err != nil {
   213  		utils.Fatalf("error getting session key: %v", err)
   214  	}
   215  	m, err := api.GenerateAccessControlManifest(ctx, ref, accessKey, ae)
   216  	if err != nil {
   217  		utils.Fatalf("error generating root access manifest: %v", err)
   218  	}
   219  
   220  	if dryRun {
   221  		err = printManifests(m, actManifest)
   222  		if err != nil {
   223  			utils.Fatalf("had an error printing the manifests: %v", err)
   224  		}
   225  	} else {
   226  		err = uploadManifests(ctx, m, actManifest)
   227  		if err != nil {
   228  			utils.Fatalf("had an error uploading the manifests: %v", err)
   229  		}
   230  	}
   231  }
   232  
   233  func printManifests(rootAccessManifest, actManifest *api.Manifest) error {
   234  	js, err := json.Marshal(rootAccessManifest)
   235  	if err != nil {
   236  		return err
   237  	}
   238  	fmt.Println(string(js))
   239  
   240  	if actManifest != nil {
   241  		js, err := json.Marshal(actManifest)
   242  		if err != nil {
   243  			return err
   244  		}
   245  		fmt.Println(string(js))
   246  	}
   247  	return nil
   248  }
   249  
   250  func uploadManifests(ctx *cli.Context, rootAccessManifest, actManifest *api.Manifest) error {
   251  	bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
   252  	client := client.NewClient(bzzapi)
   253  
   254  	var (
   255  		key string
   256  		err error
   257  	)
   258  	if actManifest != nil {
   259  		key, err = client.UploadManifest(actManifest, false)
   260  		if err != nil {
   261  			return err
   262  		}
   263  
   264  		rootAccessManifest.Entries[0].Access.Act = key
   265  	}
   266  	key, err = client.UploadManifest(rootAccessManifest, false)
   267  	if err != nil {
   268  		return err
   269  	}
   270  	fmt.Println(key)
   271  	return nil
   272  }
   273  
   274  // makePasswordList reads password lines from the file specified by the global --password flag
   275  // and also by the same subcommand --password flag.
   276  // This function ia a fork of utils.MakePasswordList to lookup cli context for subcommand.
   277  // Function ctx.SetGlobal is not setting the global flag value that can be accessed
   278  // by ctx.GlobalString using the current version of cli package.
   279  func makePasswordList(ctx *cli.Context) []string {
   280  	path := ctx.GlobalString(utils.PasswordFileFlag.Name)
   281  	if path == "" {
   282  		path = ctx.String(utils.PasswordFileFlag.Name)
   283  		if path == "" {
   284  			return nil
   285  		}
   286  	}
   287  	text, err := ioutil.ReadFile(path)
   288  	if err != nil {
   289  		utils.Fatalf("Failed to read password file: %v", err)
   290  	}
   291  	lines := strings.Split(string(text), "\n")
   292  	// Sanitise DOS line endings.
   293  	for i := range lines {
   294  		lines[i] = strings.TrimRight(lines[i], "\r")
   295  	}
   296  	return lines
   297  }