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  }