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