github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/cmd/swarm/access_test.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2018 Go Ethereum作者 10 //此文件是Go以太坊的一部分。 11 // 12 //Go以太坊是免费软件:您可以重新发布和/或修改它 13 //根据GNU通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊的分布希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU通用公共许可证了解更多详细信息。 21 // 22 //你应该已经收到一份GNU通用公共许可证的副本 23 //一起去以太坊吧。如果没有,请参见<http://www.gnu.org/licenses/>。 24 package main 25 26 import ( 27 "bytes" 28 "crypto/rand" 29 "encoding/hex" 30 "encoding/json" 31 "io" 32 "io/ioutil" 33 gorand "math/rand" 34 "net/http" 35 "os" 36 "path/filepath" 37 "strings" 38 "testing" 39 "time" 40 41 "github.com/ethereum/go-ethereum/crypto" 42 "github.com/ethereum/go-ethereum/crypto/sha3" 43 "github.com/ethereum/go-ethereum/log" 44 "github.com/ethereum/go-ethereum/swarm/api" 45 swarm "github.com/ethereum/go-ethereum/swarm/api/client" 46 ) 47 48 // 49 // 50 // 51 // 52 // 53 func TestAccessPassword(t *testing.T) { 54 cluster := newTestCluster(t, 1) 55 defer cluster.Shutdown() 56 proxyNode := cluster.Nodes[0] 57 58 // 59 tmp, err := ioutil.TempDir("", "swarm-test") 60 if err != nil { 61 t.Fatal(err) 62 } 63 defer os.RemoveAll(tmp) 64 65 // 66 data := "notsorandomdata" 67 dataFilename := filepath.Join(tmp, "data.txt") 68 69 err = ioutil.WriteFile(dataFilename, []byte(data), 0666) 70 if err != nil { 71 t.Fatal(err) 72 } 73 74 hashRegexp := `[a-f\d]{128}` 75 76 //用“swarm up”上传文件,并期望得到一个哈希值 77 up := runSwarm(t, 78 "--bzzapi", 79 proxyNode.URL, // 80 "up", 81 "--encrypt", 82 dataFilename) 83 _, matches := up.ExpectRegexp(hashRegexp) 84 up.ExpectExit() 85 86 if len(matches) < 1 { 87 t.Fatal("no matches found") 88 } 89 90 ref := matches[0] 91 92 password := "smth" 93 passwordFilename := filepath.Join(tmp, "password.txt") 94 95 err = ioutil.WriteFile(passwordFilename, []byte(password), 0666) 96 if err != nil { 97 t.Fatal(err) 98 } 99 100 up = runSwarm(t, 101 "access", 102 "new", 103 "pass", 104 "--dry-run", 105 "--password", 106 passwordFilename, 107 ref, 108 ) 109 110 _, matches = up.ExpectRegexp(".+") 111 up.ExpectExit() 112 113 if len(matches) == 0 { 114 t.Fatalf("stdout not matched") 115 } 116 117 var m api.Manifest 118 119 err = json.Unmarshal([]byte(matches[0]), &m) 120 if err != nil { 121 t.Fatalf("unmarshal manifest: %v", err) 122 } 123 124 if len(m.Entries) != 1 { 125 t.Fatalf("expected one manifest entry, got %v", len(m.Entries)) 126 } 127 128 e := m.Entries[0] 129 130 ct := "application/bzz-manifest+json" 131 if e.ContentType != ct { 132 t.Errorf("expected %q content type, got %q", ct, e.ContentType) 133 } 134 135 if e.Access == nil { 136 t.Fatal("manifest access is nil") 137 } 138 139 a := e.Access 140 141 if a.Type != "pass" { 142 t.Errorf(`got access type %q, expected "pass"`, a.Type) 143 } 144 if len(a.Salt) < 32 { 145 t.Errorf(`got salt with length %v, expected not less the 32 bytes`, len(a.Salt)) 146 } 147 if a.KdfParams == nil { 148 t.Fatal("manifest access kdf params is nil") 149 } 150 151 client := swarm.NewClient(cluster.Nodes[0].URL) 152 153 hash, err := client.UploadManifest(&m, false) 154 if err != nil { 155 t.Fatal(err) 156 } 157 158 httpClient := &http.Client{} 159 160 url := cluster.Nodes[0].URL + "/" + "bzz:/" + hash 161 response, err := httpClient.Get(url) 162 if err != nil { 163 t.Fatal(err) 164 } 165 if response.StatusCode != http.StatusUnauthorized { 166 t.Fatal("should be a 401") 167 } 168 authHeader := response.Header.Get("WWW-Authenticate") 169 if authHeader == "" { 170 t.Fatal("should be something here") 171 } 172 173 req, err := http.NewRequest(http.MethodGet, url, nil) 174 if err != nil { 175 t.Fatal(err) 176 } 177 req.SetBasicAuth("", password) 178 179 response, err = http.DefaultClient.Do(req) 180 if err != nil { 181 t.Fatal(err) 182 } 183 defer response.Body.Close() 184 185 if response.StatusCode != http.StatusOK { 186 t.Errorf("expected status %v, got %v", http.StatusOK, response.StatusCode) 187 } 188 d, err := ioutil.ReadAll(response.Body) 189 if err != nil { 190 t.Fatal(err) 191 } 192 if string(d) != data { 193 t.Errorf("expected decrypted data %q, got %q", data, string(d)) 194 } 195 196 wrongPasswordFilename := filepath.Join(tmp, "password-wrong.txt") 197 198 err = ioutil.WriteFile(wrongPasswordFilename, []byte("just wr0ng"), 0666) 199 if err != nil { 200 t.Fatal(err) 201 } 202 203 //下载带有错误密码的“swarm down”文件 204 up = runSwarm(t, 205 "--bzzapi", 206 proxyNode.URL, 207 "down", 208 "bzz:/"+hash, 209 tmp, 210 "--password", 211 wrongPasswordFilename) 212 213 _, matches = up.ExpectRegexp("unauthorized") 214 if len(matches) != 1 && matches[0] != "unauthorized" { 215 t.Fatal(`"unauthorized" not found in output"`) 216 } 217 up.ExpectExit() 218 } 219 220 // 221 // 222 //参与方-节点(发布者),上载到第二个节点(也是被授予者),然后消失。 223 // 224 // 225 func TestAccessPK(t *testing.T) { 226 // 227 cluster := newTestCluster(t, 1) 228 defer cluster.Shutdown() 229 230 // 231 tmp, err := ioutil.TempFile("", "swarm-test") 232 if err != nil { 233 t.Fatal(err) 234 } 235 defer tmp.Close() 236 defer os.Remove(tmp.Name()) 237 238 // 239 data := "notsorandomdata" 240 _, err = io.WriteString(tmp, data) 241 if err != nil { 242 t.Fatal(err) 243 } 244 245 hashRegexp := `[a-f\d]{128}` 246 247 //用“swarm up”上传文件,并期望得到一个哈希值 248 up := runSwarm(t, 249 "--bzzapi", 250 cluster.Nodes[0].URL, 251 "up", 252 "--encrypt", 253 tmp.Name()) 254 _, matches := up.ExpectRegexp(hashRegexp) 255 up.ExpectExit() 256 257 if len(matches) < 1 { 258 t.Fatal("no matches found") 259 } 260 261 ref := matches[0] 262 263 pk := cluster.Nodes[0].PrivateKey 264 granteePubKey := crypto.CompressPubkey(&pk.PublicKey) 265 266 publisherDir, err := ioutil.TempDir("", "swarm-account-dir-temp") 267 if err != nil { 268 t.Fatal(err) 269 } 270 271 passFile, err := ioutil.TempFile("", "swarm-test") 272 if err != nil { 273 t.Fatal(err) 274 } 275 defer passFile.Close() 276 defer os.Remove(passFile.Name()) 277 _, err = io.WriteString(passFile, testPassphrase) 278 if err != nil { 279 t.Fatal(err) 280 } 281 _, publisherAccount := getTestAccount(t, publisherDir) 282 up = runSwarm(t, 283 "--bzzaccount", 284 publisherAccount.Address.String(), 285 "--password", 286 passFile.Name(), 287 "--datadir", 288 publisherDir, 289 "--bzzapi", 290 cluster.Nodes[0].URL, 291 "access", 292 "new", 293 "pk", 294 "--dry-run", 295 "--grant-key", 296 hex.EncodeToString(granteePubKey), 297 ref, 298 ) 299 300 _, matches = up.ExpectRegexp(".+") 301 up.ExpectExit() 302 303 if len(matches) == 0 { 304 t.Fatalf("stdout not matched") 305 } 306 307 var m api.Manifest 308 309 err = json.Unmarshal([]byte(matches[0]), &m) 310 if err != nil { 311 t.Fatalf("unmarshal manifest: %v", err) 312 } 313 314 if len(m.Entries) != 1 { 315 t.Fatalf("expected one manifest entry, got %v", len(m.Entries)) 316 } 317 318 e := m.Entries[0] 319 320 ct := "application/bzz-manifest+json" 321 if e.ContentType != ct { 322 t.Errorf("expected %q content type, got %q", ct, e.ContentType) 323 } 324 325 if e.Access == nil { 326 t.Fatal("manifest access is nil") 327 } 328 329 a := e.Access 330 331 if a.Type != "pk" { 332 t.Errorf(`got access type %q, expected "pk"`, a.Type) 333 } 334 if len(a.Salt) < 32 { 335 t.Errorf(`got salt with length %v, expected not less the 32 bytes`, len(a.Salt)) 336 } 337 if a.KdfParams != nil { 338 t.Fatal("manifest access kdf params should be nil") 339 } 340 341 client := swarm.NewClient(cluster.Nodes[0].URL) 342 343 hash, err := client.UploadManifest(&m, false) 344 if err != nil { 345 t.Fatal(err) 346 } 347 348 httpClient := &http.Client{} 349 350 url := cluster.Nodes[0].URL + "/" + "bzz:/" + hash 351 response, err := httpClient.Get(url) 352 if err != nil { 353 t.Fatal(err) 354 } 355 if response.StatusCode != http.StatusOK { 356 t.Fatal("should be a 200") 357 } 358 d, err := ioutil.ReadAll(response.Body) 359 if err != nil { 360 t.Fatal(err) 361 } 362 if string(d) != data { 363 t.Errorf("expected decrypted data %q, got %q", data, string(d)) 364 } 365 } 366 367 // 368 // 369 // 370 // 371 func TestAccessACT(t *testing.T) { 372 // 373 cluster := newTestCluster(t, 3) 374 defer cluster.Shutdown() 375 376 var uploadThroughNode = cluster.Nodes[0] 377 client := swarm.NewClient(uploadThroughNode.URL) 378 379 r1 := gorand.New(gorand.NewSource(time.Now().UnixNano())) 380 nodeToSkip := r1.Intn(3) // 381 // 382 tmp, err := ioutil.TempFile("", "swarm-test") 383 if err != nil { 384 t.Fatal(err) 385 } 386 defer tmp.Close() 387 defer os.Remove(tmp.Name()) 388 389 // 390 data := "notsorandomdata" 391 _, err = io.WriteString(tmp, data) 392 if err != nil { 393 t.Fatal(err) 394 } 395 396 hashRegexp := `[a-f\d]{128}` 397 398 //用“swarm up”上传文件,并期望得到一个哈希值 399 up := runSwarm(t, 400 "--bzzapi", 401 cluster.Nodes[0].URL, 402 "up", 403 "--encrypt", 404 tmp.Name()) 405 _, matches := up.ExpectRegexp(hashRegexp) 406 up.ExpectExit() 407 408 if len(matches) < 1 { 409 t.Fatal("no matches found") 410 } 411 412 ref := matches[0] 413 grantees := []string{} 414 for i, v := range cluster.Nodes { 415 if i == nodeToSkip { 416 continue 417 } 418 pk := v.PrivateKey 419 granteePubKey := crypto.CompressPubkey(&pk.PublicKey) 420 grantees = append(grantees, hex.EncodeToString(granteePubKey)) 421 } 422 423 granteesPubkeyListFile, err := ioutil.TempFile("", "grantees-pubkey-list.csv") 424 if err != nil { 425 t.Fatal(err) 426 } 427 428 _, err = granteesPubkeyListFile.WriteString(strings.Join(grantees, "\n")) 429 if err != nil { 430 t.Fatal(err) 431 } 432 433 defer granteesPubkeyListFile.Close() 434 defer os.Remove(granteesPubkeyListFile.Name()) 435 436 publisherDir, err := ioutil.TempDir("", "swarm-account-dir-temp") 437 if err != nil { 438 t.Fatal(err) 439 } 440 441 passFile, err := ioutil.TempFile("", "swarm-test") 442 if err != nil { 443 t.Fatal(err) 444 } 445 defer passFile.Close() 446 defer os.Remove(passFile.Name()) 447 _, err = io.WriteString(passFile, testPassphrase) 448 if err != nil { 449 t.Fatal(err) 450 } 451 452 _, publisherAccount := getTestAccount(t, publisherDir) 453 up = runSwarm(t, 454 "--bzzaccount", 455 publisherAccount.Address.String(), 456 "--password", 457 passFile.Name(), 458 "--datadir", 459 publisherDir, 460 "--bzzapi", 461 cluster.Nodes[0].URL, 462 "access", 463 "new", 464 "act", 465 "--grant-keys", 466 granteesPubkeyListFile.Name(), 467 ref, 468 ) 469 470 _, matches = up.ExpectRegexp(`[a-f\d]{64}`) 471 up.ExpectExit() 472 473 if len(matches) == 0 { 474 t.Fatalf("stdout not matched") 475 } 476 hash := matches[0] 477 m, _, err := client.DownloadManifest(hash) 478 if err != nil { 479 t.Fatalf("unmarshal manifest: %v", err) 480 } 481 482 if len(m.Entries) != 1 { 483 t.Fatalf("expected one manifest entry, got %v", len(m.Entries)) 484 } 485 486 e := m.Entries[0] 487 488 ct := "application/bzz-manifest+json" 489 if e.ContentType != ct { 490 t.Errorf("expected %q content type, got %q", ct, e.ContentType) 491 } 492 493 if e.Access == nil { 494 t.Fatal("manifest access is nil") 495 } 496 497 a := e.Access 498 499 if a.Type != "act" { 500 t.Fatalf(`got access type %q, expected "act"`, a.Type) 501 } 502 if len(a.Salt) < 32 { 503 t.Fatalf(`got salt with length %v, expected not less the 32 bytes`, len(a.Salt)) 504 } 505 if a.KdfParams != nil { 506 t.Fatal("manifest access kdf params should be nil") 507 } 508 509 httpClient := &http.Client{} 510 511 // 512 for i, node := range cluster.Nodes { 513 log.Debug("trying to fetch from node", "node index", i) 514 515 url := node.URL + "/" + "bzz:/" + hash 516 response, err := httpClient.Get(url) 517 if err != nil { 518 t.Fatal(err) 519 } 520 log.Debug("got response from node", "response code", response.StatusCode) 521 522 if i == nodeToSkip { 523 log.Debug("reached node to skip", "status code", response.StatusCode) 524 525 if response.StatusCode != http.StatusUnauthorized { 526 t.Fatalf("should be a 401") 527 } 528 529 continue 530 } 531 532 if response.StatusCode != http.StatusOK { 533 t.Fatal("should be a 200") 534 } 535 d, err := ioutil.ReadAll(response.Body) 536 if err != nil { 537 t.Fatal(err) 538 } 539 if string(d) != data { 540 t.Errorf("expected decrypted data %q, got %q", data, string(d)) 541 } 542 } 543 } 544 545 // 546 // 547 func TestKeypairSanity(t *testing.T) { 548 salt := make([]byte, 32) 549 if _, err := io.ReadFull(rand.Reader, salt); err != nil { 550 t.Fatalf("reading from crypto/rand failed: %v", err.Error()) 551 } 552 sharedSecret := "a85586744a1ddd56a7ed9f33fa24f40dd745b3a941be296a0d60e329dbdb896d" 553 554 for i, v := range []struct { 555 publisherPriv string 556 granteePub string 557 }{ 558 { 559 publisherPriv: "ec5541555f3bc6376788425e9d1a62f55a82901683fd7062c5eddcc373a73459", 560 granteePub: "0226f213613e843a413ad35b40f193910d26eb35f00154afcde9ded57479a6224a", 561 }, 562 { 563 publisherPriv: "70c7a73011aa56584a0009ab874794ee7e5652fd0c6911cd02f8b6267dd82d2d", 564 granteePub: "02e6f8d5e28faaa899744972bb847b6eb805a160494690c9ee7197ae9f619181db", 565 }, 566 } { 567 b, _ := hex.DecodeString(v.granteePub) 568 granteePub, _ := crypto.DecompressPubkey(b) 569 publisherPrivate, _ := crypto.HexToECDSA(v.publisherPriv) 570 571 ssKey, err := api.NewSessionKeyPK(publisherPrivate, granteePub, salt) 572 if err != nil { 573 t.Fatal(err) 574 } 575 576 hasher := sha3.NewKeccak256() 577 hasher.Write(salt) 578 shared, err := hex.DecodeString(sharedSecret) 579 if err != nil { 580 t.Fatal(err) 581 } 582 hasher.Write(shared) 583 sum := hasher.Sum(nil) 584 585 if !bytes.Equal(ssKey, sum) { 586 t.Fatalf("%d: got a session key mismatch", i) 587 } 588 } 589 }