github.com/oskarth/go-ethereum@v1.6.8-0.20191013093314-dac24a9d3494/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 dryRun {
   118  		err = printManifests(m, nil)
   119  		if err != nil {
   120  			utils.Fatalf("had an error printing the manifests: %v", err)
   121  		}
   122  	} else {
   123  		err = uploadManifests(ctx, m, nil)
   124  		if err != nil {
   125  			utils.Fatalf("had an error uploading the manifests: %v", err)
   126  		}
   127  	}
   128  }
   129  
   130  func accessNewPK(ctx *cli.Context) {
   131  	args := ctx.Args()
   132  	if len(args) != 1 {
   133  		utils.Fatalf("Expected 1 argument - the ref")
   134  	}
   135  
   136  	var (
   137  		ae               *api.AccessEntry
   138  		sessionKey       []byte
   139  		err              error
   140  		ref              = args[0]
   141  		privateKey       = getPrivKey(ctx)
   142  		granteePublicKey = ctx.String(SwarmAccessGrantKeyFlag.Name)
   143  		dryRun           = ctx.Bool(SwarmDryRunFlag.Name)
   144  	)
   145  	sessionKey, ae, err = api.DoPK(ctx, privateKey, granteePublicKey, salt)
   146  	if err != nil {
   147  		utils.Fatalf("error getting session key: %v", err)
   148  	}
   149  	m, err := api.GenerateAccessControlManifest(ctx, ref, sessionKey, ae)
   150  	if dryRun {
   151  		err = printManifests(m, nil)
   152  		if err != nil {
   153  			utils.Fatalf("had an error printing the manifests: %v", err)
   154  		}
   155  	} else {
   156  		err = uploadManifests(ctx, m, nil)
   157  		if err != nil {
   158  			utils.Fatalf("had an error uploading the manifests: %v", err)
   159  		}
   160  	}
   161  }
   162  
   163  func accessNewACT(ctx *cli.Context) {
   164  	args := ctx.Args()
   165  	if len(args) != 1 {
   166  		utils.Fatalf("Expected 1 argument - the ref")
   167  	}
   168  
   169  	var (
   170  		ae                   *api.AccessEntry
   171  		actManifest          *api.Manifest
   172  		accessKey            []byte
   173  		err                  error
   174  		ref                  = args[0]
   175  		pkGrantees           = []string{}
   176  		passGrantees         = []string{}
   177  		pkGranteesFilename   = ctx.String(SwarmAccessGrantKeysFlag.Name)
   178  		passGranteesFilename = ctx.String(utils.PasswordFileFlag.Name)
   179  		privateKey           = getPrivKey(ctx)
   180  		dryRun               = ctx.Bool(SwarmDryRunFlag.Name)
   181  	)
   182  	if pkGranteesFilename == "" && passGranteesFilename == "" {
   183  		utils.Fatalf("you have to provide either a grantee public-keys file or an encryption passwords file (or both)")
   184  	}
   185  
   186  	if pkGranteesFilename != "" {
   187  		bytes, err := ioutil.ReadFile(pkGranteesFilename)
   188  		if err != nil {
   189  			utils.Fatalf("had an error reading the grantee public key list")
   190  		}
   191  		pkGrantees = strings.Split(strings.Trim(string(bytes), "\n"), "\n")
   192  	}
   193  
   194  	if passGranteesFilename != "" {
   195  		bytes, err := ioutil.ReadFile(passGranteesFilename)
   196  		if err != nil {
   197  			utils.Fatalf("could not read password filename: %v", err)
   198  		}
   199  		passGrantees = strings.Split(strings.Trim(string(bytes), "\n"), "\n")
   200  	}
   201  	accessKey, ae, actManifest, err = api.DoACT(ctx, privateKey, salt, pkGrantees, passGrantees)
   202  	if err != nil {
   203  		utils.Fatalf("error generating ACT manifest: %v", err)
   204  	}
   205  
   206  	if err != nil {
   207  		utils.Fatalf("error getting session key: %v", err)
   208  	}
   209  	m, err := api.GenerateAccessControlManifest(ctx, ref, accessKey, ae)
   210  	if err != nil {
   211  		utils.Fatalf("error generating root access manifest: %v", err)
   212  	}
   213  
   214  	if dryRun {
   215  		err = printManifests(m, actManifest)
   216  		if err != nil {
   217  			utils.Fatalf("had an error printing the manifests: %v", err)
   218  		}
   219  	} else {
   220  		err = uploadManifests(ctx, m, actManifest)
   221  		if err != nil {
   222  			utils.Fatalf("had an error uploading the manifests: %v", err)
   223  		}
   224  	}
   225  }
   226  
   227  func printManifests(rootAccessManifest, actManifest *api.Manifest) error {
   228  	js, err := json.Marshal(rootAccessManifest)
   229  	if err != nil {
   230  		return err
   231  	}
   232  	fmt.Println(string(js))
   233  
   234  	if actManifest != nil {
   235  		js, err := json.Marshal(actManifest)
   236  		if err != nil {
   237  			return err
   238  		}
   239  		fmt.Println(string(js))
   240  	}
   241  	return nil
   242  }
   243  
   244  func uploadManifests(ctx *cli.Context, rootAccessManifest, actManifest *api.Manifest) error {
   245  	bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
   246  	client := client.NewClient(bzzapi)
   247  
   248  	var (
   249  		key string
   250  		err error
   251  	)
   252  	if actManifest != nil {
   253  		key, err = client.UploadManifest(actManifest, false)
   254  		if err != nil {
   255  			return err
   256  		}
   257  
   258  		rootAccessManifest.Entries[0].Access.Act = key
   259  	}
   260  	key, err = client.UploadManifest(rootAccessManifest, false)
   261  	if err != nil {
   262  		return err
   263  	}
   264  	fmt.Println(key)
   265  	return nil
   266  }
   267  
   268  // makePasswordList reads password lines from the file specified by the global --password flag
   269  // and also by the same subcommand --password flag.
   270  // This function ia a fork of utils.MakePasswordList to lookup cli context for subcommand.
   271  // Function ctx.SetGlobal is not setting the global flag value that can be accessed
   272  // by ctx.GlobalString using the current version of cli package.
   273  func makePasswordList(ctx *cli.Context) []string {
   274  	path := ctx.GlobalString(utils.PasswordFileFlag.Name)
   275  	if path == "" {
   276  		path = ctx.String(utils.PasswordFileFlag.Name)
   277  		if path == "" {
   278  			return nil
   279  		}
   280  	}
   281  	text, err := ioutil.ReadFile(path)
   282  	if err != nil {
   283  		utils.Fatalf("Failed to read password file: %v", err)
   284  	}
   285  	lines := strings.Split(string(text), "\n")
   286  	// Sanitise DOS line endings.
   287  	for i := range lines {
   288  		lines[i] = strings.TrimRight(lines[i], "\r")
   289  	}
   290  	return lines
   291  }