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 }