| 
									
										
										
										
											2018-08-15 17:41:52 +02:00
										 |  |  | // Copyright 2018 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of go-ethereum. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // go-ethereum is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // go-ethereum is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | package main | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"crypto/rand" | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/cmd/utils" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/swarm/api" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/swarm/api/client" | 
					
						
							|  |  |  | 	"gopkg.in/urfave/cli.v1" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-12 14:51:38 +02:00
										 |  |  | var ( | 
					
						
							|  |  |  | 	salt          = make([]byte, 32) | 
					
						
							|  |  |  | 	accessCommand = cli.Command{ | 
					
						
							|  |  |  | 		CustomHelpTemplate: helpTemplate, | 
					
						
							|  |  |  | 		Name:               "access", | 
					
						
							|  |  |  | 		Usage:              "encrypts a reference and embeds it into a root manifest", | 
					
						
							|  |  |  | 		ArgsUsage:          "<ref>", | 
					
						
							|  |  |  | 		Description:        "encrypts a reference and embeds it into a root manifest", | 
					
						
							|  |  |  | 		Subcommands: []cli.Command{ | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				CustomHelpTemplate: helpTemplate, | 
					
						
							|  |  |  | 				Name:               "new", | 
					
						
							|  |  |  | 				Usage:              "encrypts a reference and embeds it into a root manifest", | 
					
						
							|  |  |  | 				ArgsUsage:          "<ref>", | 
					
						
							|  |  |  | 				Description:        "encrypts a reference and embeds it into a root access manifest and prints the resulting manifest", | 
					
						
							|  |  |  | 				Subcommands: []cli.Command{ | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						Action:             accessNewPass, | 
					
						
							|  |  |  | 						CustomHelpTemplate: helpTemplate, | 
					
						
							|  |  |  | 						Flags: []cli.Flag{ | 
					
						
							|  |  |  | 							utils.PasswordFileFlag, | 
					
						
							|  |  |  | 							SwarmDryRunFlag, | 
					
						
							|  |  |  | 						}, | 
					
						
							|  |  |  | 						Name:        "pass", | 
					
						
							|  |  |  | 						Usage:       "encrypts a reference with a password and embeds it into a root manifest", | 
					
						
							|  |  |  | 						ArgsUsage:   "<ref>", | 
					
						
							|  |  |  | 						Description: "encrypts a reference and embeds it into a root access manifest and prints the resulting manifest", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						Action:             accessNewPK, | 
					
						
							|  |  |  | 						CustomHelpTemplate: helpTemplate, | 
					
						
							|  |  |  | 						Flags: []cli.Flag{ | 
					
						
							|  |  |  | 							utils.PasswordFileFlag, | 
					
						
							|  |  |  | 							SwarmDryRunFlag, | 
					
						
							|  |  |  | 							SwarmAccessGrantKeyFlag, | 
					
						
							|  |  |  | 						}, | 
					
						
							|  |  |  | 						Name:        "pk", | 
					
						
							|  |  |  | 						Usage:       "encrypts a reference with the node's private key and a given grantee's public key and embeds it into a root manifest", | 
					
						
							|  |  |  | 						ArgsUsage:   "<ref>", | 
					
						
							|  |  |  | 						Description: "encrypts a reference and embeds it into a root access manifest and prints the resulting manifest", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						Action:             accessNewACT, | 
					
						
							|  |  |  | 						CustomHelpTemplate: helpTemplate, | 
					
						
							|  |  |  | 						Flags: []cli.Flag{ | 
					
						
							|  |  |  | 							SwarmAccessGrantKeysFlag, | 
					
						
							|  |  |  | 							SwarmDryRunFlag, | 
					
						
							|  |  |  | 							utils.PasswordFileFlag, | 
					
						
							|  |  |  | 						}, | 
					
						
							|  |  |  | 						Name:        "act", | 
					
						
							|  |  |  | 						Usage:       "encrypts a reference with the node's private key and a given grantee's public key and embeds it into a root manifest", | 
					
						
							|  |  |  | 						ArgsUsage:   "<ref>", | 
					
						
							|  |  |  | 						Description: "encrypts a reference and embeds it into a root access manifest and prints the resulting manifest", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2018-08-15 17:41:52 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | func init() { | 
					
						
							|  |  |  | 	if _, err := io.ReadFull(rand.Reader, salt); err != nil { | 
					
						
							|  |  |  | 		panic("reading from crypto/rand failed: " + err.Error()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func accessNewPass(ctx *cli.Context) { | 
					
						
							|  |  |  | 	args := ctx.Args() | 
					
						
							|  |  |  | 	if len(args) != 1 { | 
					
						
							|  |  |  | 		utils.Fatalf("Expected 1 argument - the ref") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		ae        *api.AccessEntry | 
					
						
							|  |  |  | 		accessKey []byte | 
					
						
							|  |  |  | 		err       error | 
					
						
							|  |  |  | 		ref       = args[0] | 
					
						
							|  |  |  | 		password  = getPassPhrase("", 0, makePasswordList(ctx)) | 
					
						
							|  |  |  | 		dryRun    = ctx.Bool(SwarmDryRunFlag.Name) | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2018-09-07 09:56:05 +02:00
										 |  |  | 	accessKey, ae, err = api.DoPassword(ctx, password, salt) | 
					
						
							| 
									
										
										
										
											2018-08-15 17:41:52 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		utils.Fatalf("error getting session key: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	m, err := api.GenerateAccessControlManifest(ctx, ref, accessKey, ae) | 
					
						
							| 
									
										
										
										
											2018-11-07 20:39:08 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		utils.Fatalf("had an error generating the manifest: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-15 17:41:52 +02:00
										 |  |  | 	if dryRun { | 
					
						
							|  |  |  | 		err = printManifests(m, nil) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			utils.Fatalf("had an error printing the manifests: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		err = uploadManifests(ctx, m, nil) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			utils.Fatalf("had an error uploading the manifests: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func accessNewPK(ctx *cli.Context) { | 
					
						
							|  |  |  | 	args := ctx.Args() | 
					
						
							|  |  |  | 	if len(args) != 1 { | 
					
						
							|  |  |  | 		utils.Fatalf("Expected 1 argument - the ref") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		ae               *api.AccessEntry | 
					
						
							|  |  |  | 		sessionKey       []byte | 
					
						
							|  |  |  | 		err              error | 
					
						
							|  |  |  | 		ref              = args[0] | 
					
						
							|  |  |  | 		privateKey       = getPrivKey(ctx) | 
					
						
							|  |  |  | 		granteePublicKey = ctx.String(SwarmAccessGrantKeyFlag.Name) | 
					
						
							|  |  |  | 		dryRun           = ctx.Bool(SwarmDryRunFlag.Name) | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2018-09-07 09:56:05 +02:00
										 |  |  | 	sessionKey, ae, err = api.DoPK(ctx, privateKey, granteePublicKey, salt) | 
					
						
							| 
									
										
										
										
											2018-08-15 17:41:52 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		utils.Fatalf("error getting session key: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	m, err := api.GenerateAccessControlManifest(ctx, ref, sessionKey, ae) | 
					
						
							| 
									
										
										
										
											2018-11-07 20:39:08 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		utils.Fatalf("had an error generating the manifest: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-15 17:41:52 +02:00
										 |  |  | 	if dryRun { | 
					
						
							|  |  |  | 		err = printManifests(m, nil) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			utils.Fatalf("had an error printing the manifests: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		err = uploadManifests(ctx, m, nil) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			utils.Fatalf("had an error uploading the manifests: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func accessNewACT(ctx *cli.Context) { | 
					
						
							|  |  |  | 	args := ctx.Args() | 
					
						
							|  |  |  | 	if len(args) != 1 { | 
					
						
							|  |  |  | 		utils.Fatalf("Expected 1 argument - the ref") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2018-09-07 09:56:05 +02:00
										 |  |  | 		ae                   *api.AccessEntry | 
					
						
							|  |  |  | 		actManifest          *api.Manifest | 
					
						
							|  |  |  | 		accessKey            []byte | 
					
						
							|  |  |  | 		err                  error | 
					
						
							|  |  |  | 		ref                  = args[0] | 
					
						
							|  |  |  | 		pkGrantees           = []string{} | 
					
						
							|  |  |  | 		passGrantees         = []string{} | 
					
						
							|  |  |  | 		pkGranteesFilename   = ctx.String(SwarmAccessGrantKeysFlag.Name) | 
					
						
							|  |  |  | 		passGranteesFilename = ctx.String(utils.PasswordFileFlag.Name) | 
					
						
							|  |  |  | 		privateKey           = getPrivKey(ctx) | 
					
						
							|  |  |  | 		dryRun               = ctx.Bool(SwarmDryRunFlag.Name) | 
					
						
							| 
									
										
										
										
											2018-08-15 17:41:52 +02:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2018-09-07 09:56:05 +02:00
										 |  |  | 	if pkGranteesFilename == "" && passGranteesFilename == "" { | 
					
						
							|  |  |  | 		utils.Fatalf("you have to provide either a grantee public-keys file or an encryption passwords file (or both)") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-15 17:41:52 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-07 09:56:05 +02:00
										 |  |  | 	if pkGranteesFilename != "" { | 
					
						
							|  |  |  | 		bytes, err := ioutil.ReadFile(pkGranteesFilename) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			utils.Fatalf("had an error reading the grantee public key list") | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-09-28 14:38:05 +02:00
										 |  |  | 		pkGrantees = strings.Split(strings.Trim(string(bytes), "\n"), "\n") | 
					
						
							| 
									
										
										
										
											2018-09-07 09:56:05 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if passGranteesFilename != "" { | 
					
						
							|  |  |  | 		bytes, err := ioutil.ReadFile(passGranteesFilename) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			utils.Fatalf("could not read password filename: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-09-28 14:38:05 +02:00
										 |  |  | 		passGrantees = strings.Split(strings.Trim(string(bytes), "\n"), "\n") | 
					
						
							| 
									
										
										
										
											2018-08-15 17:41:52 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-09-07 09:56:05 +02:00
										 |  |  | 	accessKey, ae, actManifest, err = api.DoACT(ctx, privateKey, salt, pkGrantees, passGrantees) | 
					
						
							| 
									
										
										
										
											2018-08-15 17:41:52 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		utils.Fatalf("error generating ACT manifest: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		utils.Fatalf("error getting session key: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	m, err := api.GenerateAccessControlManifest(ctx, ref, accessKey, ae) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		utils.Fatalf("error generating root access manifest: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if dryRun { | 
					
						
							|  |  |  | 		err = printManifests(m, actManifest) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			utils.Fatalf("had an error printing the manifests: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		err = uploadManifests(ctx, m, actManifest) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			utils.Fatalf("had an error uploading the manifests: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func printManifests(rootAccessManifest, actManifest *api.Manifest) error { | 
					
						
							|  |  |  | 	js, err := json.Marshal(rootAccessManifest) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	fmt.Println(string(js)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if actManifest != nil { | 
					
						
							|  |  |  | 		js, err := json.Marshal(actManifest) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		fmt.Println(string(js)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func uploadManifests(ctx *cli.Context, rootAccessManifest, actManifest *api.Manifest) error { | 
					
						
							|  |  |  | 	bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") | 
					
						
							|  |  |  | 	client := client.NewClient(bzzapi) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		key string | 
					
						
							|  |  |  | 		err error | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if actManifest != nil { | 
					
						
							|  |  |  | 		key, err = client.UploadManifest(actManifest, false) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		rootAccessManifest.Entries[0].Access.Act = key | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	key, err = client.UploadManifest(rootAccessManifest, false) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	fmt.Println(key) | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // makePasswordList reads password lines from the file specified by the global --password flag | 
					
						
							|  |  |  | // and also by the same subcommand --password flag. | 
					
						
							|  |  |  | // This function ia a fork of utils.MakePasswordList to lookup cli context for subcommand. | 
					
						
							|  |  |  | // Function ctx.SetGlobal is not setting the global flag value that can be accessed | 
					
						
							|  |  |  | // by ctx.GlobalString using the current version of cli package. | 
					
						
							|  |  |  | func makePasswordList(ctx *cli.Context) []string { | 
					
						
							|  |  |  | 	path := ctx.GlobalString(utils.PasswordFileFlag.Name) | 
					
						
							|  |  |  | 	if path == "" { | 
					
						
							|  |  |  | 		path = ctx.String(utils.PasswordFileFlag.Name) | 
					
						
							|  |  |  | 		if path == "" { | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	text, err := ioutil.ReadFile(path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		utils.Fatalf("Failed to read password file: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	lines := strings.Split(string(text), "\n") | 
					
						
							|  |  |  | 	// Sanitise DOS line endings. | 
					
						
							|  |  |  | 	for i := range lines { | 
					
						
							|  |  |  | 		lines[i] = strings.TrimRight(lines[i], "\r") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return lines | 
					
						
							|  |  |  | } |