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