github.com/ethersphere/bee/v2@v2.2.0/pkg/api/accesscontrol_test.go (about)

     1  // Copyright 2020 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package api_test
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"encoding/hex"
    11  	"fmt"
    12  	"io"
    13  	"net/http"
    14  	"strconv"
    15  	"strings"
    16  	"testing"
    17  	"time"
    18  
    19  	"github.com/ethersphere/bee/v2/pkg/accesscontrol"
    20  	mockac "github.com/ethersphere/bee/v2/pkg/accesscontrol/mock"
    21  	"github.com/ethersphere/bee/v2/pkg/api"
    22  	"github.com/ethersphere/bee/v2/pkg/crypto"
    23  	"github.com/ethersphere/bee/v2/pkg/file/loadsave"
    24  	"github.com/ethersphere/bee/v2/pkg/file/redundancy"
    25  	"github.com/ethersphere/bee/v2/pkg/jsonhttp"
    26  	"github.com/ethersphere/bee/v2/pkg/jsonhttp/jsonhttptest"
    27  	"github.com/ethersphere/bee/v2/pkg/log"
    28  	mockpost "github.com/ethersphere/bee/v2/pkg/postage/mock"
    29  	testingsoc "github.com/ethersphere/bee/v2/pkg/soc/testing"
    30  	mockstorer "github.com/ethersphere/bee/v2/pkg/storer/mock"
    31  	"github.com/ethersphere/bee/v2/pkg/swarm"
    32  	"gitlab.com/nolash/go-mockbytes"
    33  )
    34  
    35  //nolint:ireturn
    36  func prepareHistoryFixture(storer api.Storer) (accesscontrol.History, swarm.Address) {
    37  	ctx := context.Background()
    38  	ls := loadsave.New(storer.ChunkStore(), storer.Cache(), pipelineFactory(storer.Cache(), false, redundancy.NONE))
    39  
    40  	h, _ := accesscontrol.NewHistory(ls)
    41  
    42  	testActRef1 := swarm.NewAddress([]byte("39a5ea87b141fe44aa609c3327ecd891"))
    43  	firstTime := time.Date(1994, time.April, 1, 0, 0, 0, 0, time.UTC).Unix()
    44  	_ = h.Add(ctx, testActRef1, &firstTime, nil)
    45  
    46  	testActRef2 := swarm.NewAddress([]byte("39a5ea87b141fe44aa609c3327ecd892"))
    47  	secondTime := time.Date(2000, time.April, 1, 0, 0, 0, 0, time.UTC).Unix()
    48  	_ = h.Add(ctx, testActRef2, &secondTime, nil)
    49  
    50  	testActRef3 := swarm.NewAddress([]byte("39a5ea87b141fe44aa609c3327ecd893"))
    51  	thirdTime := time.Date(2015, time.April, 1, 0, 0, 0, 0, time.UTC).Unix()
    52  	_ = h.Add(ctx, testActRef3, &thirdTime, nil)
    53  
    54  	testActRef4 := swarm.NewAddress([]byte("39a5ea87b141fe44aa609c3327ecd894"))
    55  	fourthTime := time.Date(2020, time.April, 1, 0, 0, 0, 0, time.UTC).Unix()
    56  	_ = h.Add(ctx, testActRef4, &fourthTime, nil)
    57  
    58  	testActRef5 := swarm.NewAddress([]byte("39a5ea87b141fe44aa609c3327ecd895"))
    59  	fifthTime := time.Date(2030, time.April, 1, 0, 0, 0, 0, time.UTC).Unix()
    60  	_ = h.Add(ctx, testActRef5, &fifthTime, nil)
    61  
    62  	ref, _ := h.Store(ctx)
    63  	return h, ref
    64  }
    65  
    66  // nolint:paralleltest,tparallel
    67  // TestAccessLogicEachEndpointWithAct [positive tests]:
    68  // On each endpoint: upload w/ "Swarm-Act" header then download and check the decrypted data
    69  func TestAccessLogicEachEndpointWithAct(t *testing.T) {
    70  	t.Parallel()
    71  	var (
    72  		spk, _         = hex.DecodeString("a786dd84b61485de12146fd9c4c02d87e8fd95f0542765cb7fc3d2e428c0bcfa")
    73  		pk, _          = crypto.DecodeSecp256k1PrivateKey(spk)
    74  		publicKeyBytes = crypto.EncodeSecp256k1PublicKey(&pk.PublicKey)
    75  		publisher      = hex.EncodeToString(publicKeyBytes)
    76  		testfile       = "testfile1"
    77  		storerMock     = mockstorer.New()
    78  		logger         = log.Noop
    79  		now            = time.Now().Unix()
    80  		chunk          = swarm.NewChunk(
    81  			swarm.MustParseHexAddress("0025737be11979e91654dffd2be817ac1e52a2dadb08c97a7cef12f937e707bc"),
    82  			[]byte{72, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 149, 179, 31, 244, 146, 247, 129, 123, 132, 248, 215, 77, 44, 47, 91, 248, 229, 215, 89, 156, 210, 243, 3, 110, 204, 74, 101, 119, 53, 53, 145, 188, 193, 153, 130, 197, 83, 152, 36, 140, 150, 209, 191, 214, 193, 4, 144, 121, 32, 45, 205, 220, 59, 227, 28, 43, 161, 51, 108, 14, 106, 180, 135, 2},
    83  		)
    84  		g           = mockbytes.New(0, mockbytes.MockTypeStandard).WithModulus(255)
    85  		bytedata, _ = g.SequentialBytes(swarm.ChunkSize * 2)
    86  		tag, _      = storerMock.NewSession()
    87  		sch         = testingsoc.GenerateMockSOCWithKey(t, []byte("foo"), pk)
    88  		dirdata     = []byte("Lorem ipsum dolor sit amet")
    89  		socResource = func(owner, id, sig string) string { return fmt.Sprintf("/soc/%s/%s?sig=%s", owner, id, sig) }
    90  	)
    91  
    92  	tc := []struct {
    93  		name        string
    94  		downurl     string
    95  		upurl       string
    96  		exphash     string
    97  		data        io.Reader
    98  		expdata     []byte
    99  		contenttype string
   100  		resp        struct {
   101  			Reference swarm.Address `json:"reference"`
   102  		}
   103  	}{
   104  		{
   105  			name:        "bzz",
   106  			upurl:       "/bzz?name=sample.html",
   107  			downurl:     "/bzz",
   108  			exphash:     "a5df670544eaea29e61b19d8739faa4573b19e4426e58a173e51ed0b5e7e2ade",
   109  			resp:        api.BzzUploadResponse{Reference: swarm.MustParseHexAddress("a5df670544eaea29e61b19d8739faa4573b19e4426e58a173e51ed0b5e7e2ade")},
   110  			data:        strings.NewReader(testfile),
   111  			expdata:     []byte(testfile),
   112  			contenttype: "text/html; charset=utf-8",
   113  		},
   114  		{
   115  			name:    "bzz-dir",
   116  			upurl:   "/bzz?name=ipsum/lorem.txt",
   117  			downurl: "/bzz",
   118  			exphash: "6561b2a744d2a8f276270585da22e092c07c56624af83ac9969d52b54e87cee6/ipsum/lorem.txt",
   119  			resp:    api.BzzUploadResponse{Reference: swarm.MustParseHexAddress("6561b2a744d2a8f276270585da22e092c07c56624af83ac9969d52b54e87cee6")},
   120  			data: tarFiles(t, []f{
   121  				{
   122  					data: dirdata,
   123  					name: "lorem.txt",
   124  					dir:  "ipsum",
   125  					header: http.Header{
   126  						api.ContentTypeHeader: {"text/plain; charset=utf-8"},
   127  					},
   128  				},
   129  			}),
   130  			expdata:     dirdata,
   131  			contenttype: api.ContentTypeTar,
   132  		},
   133  		{
   134  			name:        "bytes",
   135  			upurl:       "/bytes",
   136  			downurl:     "/bytes",
   137  			exphash:     "e30da540bb9e1901169977fcf617f28b7f8df4537de978784f6d47491619a630",
   138  			resp:        api.BytesPostResponse{Reference: swarm.MustParseHexAddress("e30da540bb9e1901169977fcf617f28b7f8df4537de978784f6d47491619a630")},
   139  			data:        bytes.NewReader(bytedata),
   140  			expdata:     bytedata,
   141  			contenttype: "application/octet-stream",
   142  		},
   143  		{
   144  			name:        "chunks",
   145  			upurl:       "/chunks",
   146  			downurl:     "/chunks",
   147  			exphash:     "ca8d2d29466e017cba46d383e7e0794d99a141185ec525086037f25fc2093155",
   148  			resp:        api.ChunkAddressResponse{Reference: swarm.MustParseHexAddress("ca8d2d29466e017cba46d383e7e0794d99a141185ec525086037f25fc2093155")},
   149  			data:        bytes.NewReader(chunk.Data()),
   150  			expdata:     chunk.Data(),
   151  			contenttype: "binary/octet-stream",
   152  		},
   153  		{
   154  			name:        "soc",
   155  			upurl:       socResource(hex.EncodeToString(sch.Owner), hex.EncodeToString(sch.ID), hex.EncodeToString(sch.Signature)),
   156  			downurl:     "/chunks",
   157  			exphash:     "b100d7ce487426b17b98ff779fad4f2dd471d04ab1c8949dd2a1a78fe4a1524e",
   158  			resp:        api.ChunkAddressResponse{Reference: swarm.MustParseHexAddress("b100d7ce487426b17b98ff779fad4f2dd471d04ab1c8949dd2a1a78fe4a1524e")},
   159  			data:        bytes.NewReader(sch.WrappedChunk.Data()),
   160  			expdata:     sch.Chunk().Data(),
   161  			contenttype: "binary/octet-stream",
   162  		},
   163  	}
   164  
   165  	for _, v := range tc {
   166  		upTestOpts := []jsonhttptest.Option{
   167  			jsonhttptest.WithRequestHeader(api.SwarmActHeader, "true"),
   168  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
   169  			jsonhttptest.WithRequestHeader(api.SwarmPinHeader, "true"),
   170  			jsonhttptest.WithRequestHeader(api.SwarmTagHeader, fmt.Sprintf("%d", tag.TagID)),
   171  			jsonhttptest.WithRequestBody(v.data),
   172  			jsonhttptest.WithExpectedJSONResponse(v.resp),
   173  			jsonhttptest.WithRequestHeader(api.ContentTypeHeader, v.contenttype),
   174  		}
   175  		if v.name == "soc" {
   176  			upTestOpts = append(upTestOpts, jsonhttptest.WithRequestHeader(api.SwarmPinHeader, "true"))
   177  		} else {
   178  			upTestOpts = append(upTestOpts, jsonhttptest.WithNonEmptyResponseHeader(api.SwarmTagHeader))
   179  		}
   180  		expcontenttype := v.contenttype
   181  		if v.name == "bzz-dir" {
   182  			expcontenttype = "text/plain; charset=utf-8"
   183  			upTestOpts = append(upTestOpts, jsonhttptest.WithRequestHeader(api.SwarmCollectionHeader, "True"))
   184  		}
   185  		t.Run(v.name, func(t *testing.T) {
   186  			client, _, _, _ := newTestServer(t, testServerOptions{
   187  				Storer:        storerMock,
   188  				Logger:        logger,
   189  				Post:          mockpost.New(mockpost.WithAcceptAll()),
   190  				PublicKey:     pk.PublicKey,
   191  				AccessControl: mockac.New(),
   192  			})
   193  			header := jsonhttptest.Request(t, client, http.MethodPost, v.upurl, http.StatusCreated,
   194  				upTestOpts...,
   195  			)
   196  
   197  			historyRef := header.Get(api.SwarmActHistoryAddressHeader)
   198  			jsonhttptest.Request(t, client, http.MethodGet, v.downurl+"/"+v.exphash, http.StatusOK,
   199  				jsonhttptest.WithRequestHeader(api.SwarmActTimestampHeader, strconv.FormatInt(now, 10)),
   200  				jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, historyRef),
   201  				jsonhttptest.WithRequestHeader(api.SwarmActPublisherHeader, publisher),
   202  				jsonhttptest.WithExpectedResponse(v.expdata),
   203  				jsonhttptest.WithExpectedContentLength(len(v.expdata)),
   204  				jsonhttptest.WithExpectedResponseHeader(api.ContentTypeHeader, expcontenttype),
   205  			)
   206  
   207  			if v.name != "bzz-dir" && v.name != "soc" && v.name != "chunks" {
   208  				t.Run("head", func(t *testing.T) {
   209  					jsonhttptest.Request(t, client, http.MethodHead, v.downurl+"/"+v.exphash, http.StatusOK,
   210  						jsonhttptest.WithRequestHeader(api.SwarmActTimestampHeader, strconv.FormatInt(now, 10)),
   211  						jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, historyRef),
   212  						jsonhttptest.WithRequestHeader(api.SwarmActPublisherHeader, publisher),
   213  						jsonhttptest.WithRequestBody(v.data),
   214  						jsonhttptest.WithExpectedContentLength(len(v.expdata)),
   215  						jsonhttptest.WithExpectedResponseHeader(api.ContentTypeHeader, expcontenttype),
   216  					)
   217  				})
   218  			}
   219  		})
   220  	}
   221  }
   222  
   223  // TestAccessLogicWithoutActHeader [negative tests]:
   224  // 1. upload w/ "Swarm-Act" header then try to download w/o the header.
   225  // 2. upload w/o "Swarm-Act" header then try to download w/ the header.
   226  //
   227  //nolint:paralleltest,tparallel
   228  func TestAccessLogicWithoutAct(t *testing.T) {
   229  	t.Parallel()
   230  	var (
   231  		spk, _               = hex.DecodeString("a786dd84b61485de12146fd9c4c02d87e8fd95f0542765cb7fc3d2e428c0bcfa")
   232  		pk, _                = crypto.DecodeSecp256k1PrivateKey(spk)
   233  		publicKeyBytes       = crypto.EncodeSecp256k1PublicKey(&pk.PublicKey)
   234  		publisher            = hex.EncodeToString(publicKeyBytes)
   235  		fileUploadResource   = "/bzz"
   236  		fileDownloadResource = func(addr string) string { return "/bzz/" + addr }
   237  		storerMock           = mockstorer.New()
   238  		h, fixtureHref       = prepareHistoryFixture(storerMock)
   239  		logger               = log.Noop
   240  		fileName             = "sample.html"
   241  		now                  = time.Now().Unix()
   242  	)
   243  
   244  	t.Run("upload-w/-act-then-download-w/o-act", func(t *testing.T) {
   245  		client, _, _, _ := newTestServer(t, testServerOptions{
   246  			Storer:        storerMock,
   247  			Logger:        logger,
   248  			Post:          mockpost.New(mockpost.WithAcceptAll()),
   249  			PublicKey:     pk.PublicKey,
   250  			AccessControl: mockac.New(mockac.WithHistory(h, fixtureHref.String())),
   251  		})
   252  		var (
   253  			testfile     = "testfile1"
   254  			encryptedRef = "a5df670544eaea29e61b19d8739faa4573b19e4426e58a173e51ed0b5e7e2ade"
   255  		)
   256  		jsonhttptest.Request(t, client, http.MethodPost, fileUploadResource+"?name="+fileName, http.StatusCreated,
   257  			jsonhttptest.WithRequestHeader(api.SwarmActHeader, "true"),
   258  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
   259  			jsonhttptest.WithRequestBody(strings.NewReader(testfile)),
   260  			jsonhttptest.WithExpectedJSONResponse(api.BzzUploadResponse{
   261  				Reference: swarm.MustParseHexAddress(encryptedRef),
   262  			}),
   263  			jsonhttptest.WithRequestHeader(api.ContentTypeHeader, "text/html; charset=utf-8"),
   264  			jsonhttptest.WithNonEmptyResponseHeader(api.SwarmTagHeader),
   265  			jsonhttptest.WithExpectedResponseHeader(api.ETagHeader, fmt.Sprintf("%q", encryptedRef)),
   266  		)
   267  
   268  		jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(encryptedRef), http.StatusNotFound,
   269  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   270  				Message: "address not found or incorrect",
   271  				Code:    http.StatusNotFound,
   272  			}),
   273  			jsonhttptest.WithExpectedResponseHeader(api.ContentTypeHeader, "application/json; charset=utf-8"),
   274  		)
   275  	})
   276  
   277  	t.Run("upload-w/o-act-then-download-w/-act", func(t *testing.T) {
   278  		client, _, _, _ := newTestServer(t, testServerOptions{
   279  			Storer:        storerMock,
   280  			Logger:        logger,
   281  			Post:          mockpost.New(mockpost.WithAcceptAll()),
   282  			PublicKey:     pk.PublicKey,
   283  			AccessControl: mockac.New(),
   284  		})
   285  		var (
   286  			rootHash   = "0cb947ccbc410c43139ba4409d83bf89114cb0d79556a651c06c888cf73f4d7e"
   287  			sampleHtml = `<!DOCTYPE html>
   288  			<html>
   289  			<body>
   290  
   291  			<h1>My First Heading</h1>
   292  
   293  			<p>My first paragraph.</p>
   294  
   295  			</body>
   296  			</html>`
   297  		)
   298  
   299  		jsonhttptest.Request(t, client, http.MethodPost, fileUploadResource+"?name="+fileName, http.StatusCreated,
   300  			jsonhttptest.WithRequestHeader(api.SwarmDeferredUploadHeader, "true"),
   301  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
   302  			jsonhttptest.WithRequestBody(strings.NewReader(sampleHtml)),
   303  			jsonhttptest.WithExpectedJSONResponse(api.BzzUploadResponse{
   304  				Reference: swarm.MustParseHexAddress(rootHash),
   305  			}),
   306  			jsonhttptest.WithRequestHeader(api.ContentTypeHeader, "text/html; charset=utf-8"),
   307  			jsonhttptest.WithNonEmptyResponseHeader(api.SwarmTagHeader),
   308  			jsonhttptest.WithExpectedResponseHeader(api.ETagHeader, fmt.Sprintf("%q", rootHash)),
   309  		)
   310  
   311  		jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(rootHash), http.StatusNotFound,
   312  			jsonhttptest.WithRequestHeader(api.SwarmActTimestampHeader, strconv.FormatInt(now, 10)),
   313  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, fixtureHref.String()),
   314  			jsonhttptest.WithRequestHeader(api.SwarmActPublisherHeader, publisher),
   315  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   316  				Message: "act or history entry not found",
   317  				Code:    http.StatusNotFound,
   318  			}),
   319  			jsonhttptest.WithExpectedResponseHeader(api.ContentTypeHeader, "application/json; charset=utf-8"),
   320  		)
   321  	})
   322  }
   323  
   324  // TestAccessLogicInvalidPath [negative test]: Expect Bad request when the path address is invalid.
   325  //
   326  //nolint:paralleltest,tparallel
   327  func TestAccessLogicInvalidPath(t *testing.T) {
   328  	t.Parallel()
   329  	var (
   330  		spk, _               = hex.DecodeString("a786dd84b61485de12146fd9c4c02d87e8fd95f0542765cb7fc3d2e428c0bcfa")
   331  		pk, _                = crypto.DecodeSecp256k1PrivateKey(spk)
   332  		publicKeyBytes       = crypto.EncodeSecp256k1PublicKey(&pk.PublicKey)
   333  		publisher            = hex.EncodeToString(publicKeyBytes)
   334  		fileDownloadResource = func(addr string) string { return "/bzz/" + addr }
   335  		storerMock           = mockstorer.New()
   336  		_, fixtureHref       = prepareHistoryFixture(storerMock)
   337  		logger               = log.Noop
   338  		now                  = time.Now().Unix()
   339  	)
   340  
   341  	t.Run("invalid-path-params", func(t *testing.T) {
   342  		client, _, _, _ := newTestServer(t, testServerOptions{
   343  			Storer:        storerMock,
   344  			Logger:        logger,
   345  			Post:          mockpost.New(mockpost.WithAcceptAll()),
   346  			PublicKey:     pk.PublicKey,
   347  			AccessControl: mockac.New(),
   348  		})
   349  		encryptedRef := "asd"
   350  
   351  		jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(encryptedRef), http.StatusBadRequest,
   352  			jsonhttptest.WithRequestHeader(api.SwarmActTimestampHeader, strconv.FormatInt(now, 10)),
   353  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, fixtureHref.String()),
   354  			jsonhttptest.WithRequestHeader(api.SwarmActPublisherHeader, publisher),
   355  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   356  				Code:    http.StatusBadRequest,
   357  				Message: "invalid path params",
   358  				Reasons: []jsonhttp.Reason{
   359  					{
   360  						Field: "address",
   361  						Error: api.HexInvalidByteError('s').Error(),
   362  					},
   363  				},
   364  			}),
   365  			jsonhttptest.WithRequestHeader(api.ContentTypeHeader, "text/html; charset=utf-8"),
   366  		)
   367  	})
   368  }
   369  
   370  // nolint:paralleltest,tparallel
   371  // TestAccessLogicHistory tests:
   372  // [positive tests] 1., 2.: uploading a file w/ and w/o history address then downloading it and checking the data.
   373  // [negative test] 3. uploading a file then downloading it with a wrong history address.
   374  // [negative test] 4. uploading a file to a wrong history address.
   375  // [negative test] 5. downloading a file to w/o history address.
   376  func TestAccessLogicHistory(t *testing.T) {
   377  	t.Parallel()
   378  	var (
   379  		spk, _               = hex.DecodeString("a786dd84b61485de12146fd9c4c02d87e8fd95f0542765cb7fc3d2e428c0bcfa")
   380  		pk, _                = crypto.DecodeSecp256k1PrivateKey(spk)
   381  		publicKeyBytes       = crypto.EncodeSecp256k1PublicKey(&pk.PublicKey)
   382  		publisher            = hex.EncodeToString(publicKeyBytes)
   383  		fileUploadResource   = "/bzz"
   384  		fileDownloadResource = func(addr string) string { return "/bzz/" + addr }
   385  		storerMock           = mockstorer.New()
   386  		h, fixtureHref       = prepareHistoryFixture(storerMock)
   387  		logger               = log.Noop
   388  		fileName             = "sample.html"
   389  		now                  = time.Now().Unix()
   390  	)
   391  
   392  	t.Run("empty-history-upload-then-download-and-check-data", func(t *testing.T) {
   393  		client, _, _, _ := newTestServer(t, testServerOptions{
   394  			Storer:        storerMock,
   395  			Logger:        logger,
   396  			Post:          mockpost.New(mockpost.WithAcceptAll()),
   397  			PublicKey:     pk.PublicKey,
   398  			AccessControl: mockac.New(),
   399  		})
   400  		var (
   401  			testfile     = "testfile1"
   402  			encryptedRef = "a5df670544eaea29e61b19d8739faa4573b19e4426e58a173e51ed0b5e7e2ade"
   403  		)
   404  		header := jsonhttptest.Request(t, client, http.MethodPost, fileUploadResource+"?name="+fileName, http.StatusCreated,
   405  			jsonhttptest.WithRequestHeader(api.SwarmActHeader, "true"),
   406  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
   407  			jsonhttptest.WithRequestBody(strings.NewReader(testfile)),
   408  			jsonhttptest.WithExpectedJSONResponse(api.BzzUploadResponse{
   409  				Reference: swarm.MustParseHexAddress(encryptedRef),
   410  			}),
   411  			jsonhttptest.WithRequestHeader(api.ContentTypeHeader, "text/html; charset=utf-8"),
   412  			jsonhttptest.WithNonEmptyResponseHeader(api.SwarmTagHeader),
   413  			jsonhttptest.WithExpectedResponseHeader(api.ETagHeader, fmt.Sprintf("%q", encryptedRef)),
   414  		)
   415  
   416  		historyRef := header.Get(api.SwarmActHistoryAddressHeader)
   417  		jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(encryptedRef), http.StatusOK,
   418  			jsonhttptest.WithRequestHeader(api.SwarmActTimestampHeader, strconv.FormatInt(now, 10)),
   419  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, historyRef),
   420  			jsonhttptest.WithRequestHeader(api.SwarmActPublisherHeader, publisher),
   421  			jsonhttptest.WithExpectedResponse([]byte(testfile)),
   422  			jsonhttptest.WithExpectedContentLength(len(testfile)),
   423  			jsonhttptest.WithExpectedResponseHeader(api.ContentTypeHeader, "text/html; charset=utf-8"),
   424  			jsonhttptest.WithExpectedResponseHeader(api.ContentDispositionHeader, fmt.Sprintf(`inline; filename="%s"`, fileName)),
   425  		)
   426  	})
   427  
   428  	t.Run("with-history-upload-then-download-and-check-data", func(t *testing.T) {
   429  		client, _, _, _ := newTestServer(t, testServerOptions{
   430  			Storer:        storerMock,
   431  			Logger:        logger,
   432  			Post:          mockpost.New(mockpost.WithAcceptAll()),
   433  			PublicKey:     pk.PublicKey,
   434  			AccessControl: mockac.New(mockac.WithHistory(h, fixtureHref.String())),
   435  		})
   436  		var (
   437  			encryptedRef = "c611199e1b3674d6bf89a83e518bd16896bf5315109b4a23dcb4682a02d17b97"
   438  			testfile     = `<!DOCTYPE html>
   439  			<html>
   440  			<body>
   441  
   442  			<h1>My First Heading</h1>
   443  
   444  			<p>My first paragraph.</p>
   445  
   446  			</body>
   447  			</html>`
   448  		)
   449  
   450  		jsonhttptest.Request(t, client, http.MethodPost, fileUploadResource+"?name="+fileName, http.StatusCreated,
   451  			jsonhttptest.WithRequestHeader(api.SwarmActHeader, "true"),
   452  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
   453  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, fixtureHref.String()),
   454  			jsonhttptest.WithRequestBody(strings.NewReader(testfile)),
   455  			jsonhttptest.WithExpectedJSONResponse(api.BzzUploadResponse{
   456  				Reference: swarm.MustParseHexAddress(encryptedRef),
   457  			}),
   458  			jsonhttptest.WithRequestHeader(api.ContentTypeHeader, "text/html; charset=utf-8"),
   459  			jsonhttptest.WithNonEmptyResponseHeader(api.SwarmTagHeader),
   460  			jsonhttptest.WithExpectedResponseHeader(api.ETagHeader, fmt.Sprintf("%q", encryptedRef)),
   461  		)
   462  
   463  		jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(encryptedRef), http.StatusOK,
   464  			jsonhttptest.WithRequestHeader(api.SwarmActTimestampHeader, strconv.FormatInt(now, 10)),
   465  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, fixtureHref.String()),
   466  			jsonhttptest.WithRequestHeader(api.SwarmActPublisherHeader, publisher),
   467  			jsonhttptest.WithExpectedResponse([]byte(testfile)),
   468  			jsonhttptest.WithExpectedContentLength(len(testfile)),
   469  			jsonhttptest.WithExpectedResponseHeader(api.ContentTypeHeader, "text/html; charset=utf-8"),
   470  			jsonhttptest.WithExpectedResponseHeader(api.ContentDispositionHeader, fmt.Sprintf(`inline; filename="%s"`, fileName)),
   471  		)
   472  	})
   473  
   474  	t.Run("upload-then-download-wrong-history", func(t *testing.T) {
   475  		client, _, _, _ := newTestServer(t, testServerOptions{
   476  			Storer:        storerMock,
   477  			Logger:        logger,
   478  			Post:          mockpost.New(mockpost.WithAcceptAll()),
   479  			PublicKey:     pk.PublicKey,
   480  			AccessControl: mockac.New(mockac.WithHistory(h, fixtureHref.String())),
   481  		})
   482  		var (
   483  			testfile     = "testfile1"
   484  			encryptedRef = "a5df670544eaea29e61b19d8739faa4573b19e4426e58a173e51ed0b5e7e2ade"
   485  		)
   486  		jsonhttptest.Request(t, client, http.MethodPost, fileUploadResource+"?name="+fileName, http.StatusCreated,
   487  			jsonhttptest.WithRequestHeader(api.SwarmActHeader, "true"),
   488  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
   489  			jsonhttptest.WithRequestBody(strings.NewReader(testfile)),
   490  			jsonhttptest.WithExpectedJSONResponse(api.BzzUploadResponse{
   491  				Reference: swarm.MustParseHexAddress(encryptedRef),
   492  			}),
   493  			jsonhttptest.WithRequestHeader(api.ContentTypeHeader, "text/html; charset=utf-8"),
   494  			jsonhttptest.WithNonEmptyResponseHeader(api.SwarmTagHeader),
   495  			jsonhttptest.WithExpectedResponseHeader(api.ETagHeader, fmt.Sprintf("%q", encryptedRef)),
   496  		)
   497  
   498  		jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(encryptedRef), http.StatusNotFound,
   499  			jsonhttptest.WithRequestHeader(api.SwarmActTimestampHeader, strconv.FormatInt(now, 10)),
   500  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, "fc4e9fe978991257b897d987bc4ff13058b66ef45a53189a0b4fe84bb3346396"),
   501  			jsonhttptest.WithRequestHeader(api.SwarmActPublisherHeader, publisher),
   502  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   503  				Message: "act or history entry not found",
   504  				Code:    http.StatusNotFound,
   505  			}),
   506  			jsonhttptest.WithExpectedResponseHeader(api.ContentTypeHeader, "application/json; charset=utf-8"),
   507  		)
   508  	})
   509  
   510  	t.Run("upload-wrong-history", func(t *testing.T) {
   511  		client, _, _, _ := newTestServer(t, testServerOptions{
   512  			Storer:        storerMock,
   513  			Logger:        logger,
   514  			Post:          mockpost.New(mockpost.WithAcceptAll()),
   515  			PublicKey:     pk.PublicKey,
   516  			AccessControl: mockac.New(),
   517  		})
   518  		testfile := "testfile1"
   519  
   520  		jsonhttptest.Request(t, client, http.MethodPost, fileUploadResource+"?name="+fileName, http.StatusNotFound,
   521  			jsonhttptest.WithRequestHeader(api.SwarmActHeader, "true"),
   522  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
   523  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, fixtureHref.String()),
   524  			jsonhttptest.WithRequestBody(strings.NewReader(testfile)),
   525  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   526  				Message: "act or history entry not found",
   527  				Code:    http.StatusNotFound,
   528  			}),
   529  			jsonhttptest.WithRequestHeader(api.ContentTypeHeader, "text/html; charset=utf-8"),
   530  		)
   531  	})
   532  
   533  	t.Run("download-w/o-history", func(t *testing.T) {
   534  		client, _, _, _ := newTestServer(t, testServerOptions{
   535  			Storer:        storerMock,
   536  			Logger:        logger,
   537  			Post:          mockpost.New(mockpost.WithAcceptAll()),
   538  			PublicKey:     pk.PublicKey,
   539  			AccessControl: mockac.New(mockac.WithHistory(h, fixtureHref.String())),
   540  		})
   541  		encryptedRef := "a5df670544eaea29e61b19d8739faa4573b19e4426e58a173e51ed0b5e7e2ade"
   542  
   543  		jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(encryptedRef), http.StatusNotFound,
   544  			jsonhttptest.WithRequestHeader(api.SwarmActTimestampHeader, strconv.FormatInt(now, 10)),
   545  			jsonhttptest.WithRequestHeader(api.SwarmActPublisherHeader, publisher),
   546  			jsonhttptest.WithExpectedResponseHeader(api.ContentTypeHeader, "application/json; charset=utf-8"),
   547  		)
   548  	})
   549  }
   550  
   551  // nolint:paralleltest,tparallel
   552  // TestAccessLogicTimestamp
   553  // [positive test] 1.: uploading a file w/ ACT then download it w/ timestamp and check the data.
   554  // [negative test] 2.: try to download a file w/o timestamp.
   555  func TestAccessLogicTimestamp(t *testing.T) {
   556  	t.Parallel()
   557  	var (
   558  		spk, _               = hex.DecodeString("a786dd84b61485de12146fd9c4c02d87e8fd95f0542765cb7fc3d2e428c0bcfa")
   559  		pk, _                = crypto.DecodeSecp256k1PrivateKey(spk)
   560  		publicKeyBytes       = crypto.EncodeSecp256k1PublicKey(&pk.PublicKey)
   561  		publisher            = hex.EncodeToString(publicKeyBytes)
   562  		fileUploadResource   = "/bzz"
   563  		fileDownloadResource = func(addr string) string { return "/bzz/" + addr }
   564  		storerMock           = mockstorer.New()
   565  		h, fixtureHref       = prepareHistoryFixture(storerMock)
   566  		logger               = log.Noop
   567  		fileName             = "sample.html"
   568  	)
   569  	t.Run("upload-then-download-with-timestamp-and-check-data", func(t *testing.T) {
   570  		client, _, _, _ := newTestServer(t, testServerOptions{
   571  			Storer:        storerMock,
   572  			Logger:        logger,
   573  			Post:          mockpost.New(mockpost.WithAcceptAll()),
   574  			PublicKey:     pk.PublicKey,
   575  			AccessControl: mockac.New(mockac.WithHistory(h, fixtureHref.String())),
   576  		})
   577  		var (
   578  			thirdTime    = time.Date(2015, time.April, 1, 0, 0, 0, 0, time.UTC).Unix()
   579  			encryptedRef = "c611199e1b3674d6bf89a83e518bd16896bf5315109b4a23dcb4682a02d17b97"
   580  			testfile     = `<!DOCTYPE html>
   581  			<html>
   582  			<body>
   583  
   584  			<h1>My First Heading</h1>
   585  
   586  			<p>My first paragraph.</p>
   587  
   588  			</body>
   589  			</html>`
   590  		)
   591  
   592  		jsonhttptest.Request(t, client, http.MethodPost, fileUploadResource+"?name="+fileName, http.StatusCreated,
   593  			jsonhttptest.WithRequestHeader(api.SwarmActHeader, "true"),
   594  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
   595  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, fixtureHref.String()),
   596  			jsonhttptest.WithRequestBody(strings.NewReader(testfile)),
   597  			jsonhttptest.WithExpectedJSONResponse(api.BzzUploadResponse{
   598  				Reference: swarm.MustParseHexAddress(encryptedRef),
   599  			}),
   600  			jsonhttptest.WithRequestHeader(api.ContentTypeHeader, "text/html; charset=utf-8"),
   601  			jsonhttptest.WithNonEmptyResponseHeader(api.SwarmTagHeader),
   602  			jsonhttptest.WithExpectedResponseHeader(api.ETagHeader, fmt.Sprintf("%q", encryptedRef)),
   603  		)
   604  
   605  		jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(encryptedRef), http.StatusOK,
   606  			jsonhttptest.WithRequestHeader(api.SwarmActTimestampHeader, strconv.FormatInt(thirdTime, 10)),
   607  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, fixtureHref.String()),
   608  			jsonhttptest.WithRequestHeader(api.SwarmActPublisherHeader, publisher),
   609  			jsonhttptest.WithExpectedResponse([]byte(testfile)),
   610  			jsonhttptest.WithExpectedContentLength(len(testfile)),
   611  			jsonhttptest.WithExpectedResponseHeader(api.ContentTypeHeader, "text/html; charset=utf-8"),
   612  			jsonhttptest.WithExpectedResponseHeader(api.ContentDispositionHeader, fmt.Sprintf(`inline; filename="%s"`, fileName)),
   613  		)
   614  	})
   615  
   616  	t.Run("download-w/o-timestamp", func(t *testing.T) {
   617  		encryptedRef := "a5df670544eaea29e61b19d8739faa4573b19e4426e58a173e51ed0b5e7e2ade"
   618  		client, _, _, _ := newTestServer(t, testServerOptions{
   619  			Storer:        storerMock,
   620  			Logger:        logger,
   621  			Post:          mockpost.New(mockpost.WithAcceptAll()),
   622  			PublicKey:     pk.PublicKey,
   623  			AccessControl: mockac.New(mockac.WithHistory(h, fixtureHref.String())),
   624  		})
   625  
   626  		jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(encryptedRef), http.StatusNotFound,
   627  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, fixtureHref.String()),
   628  			jsonhttptest.WithRequestHeader(api.SwarmActPublisherHeader, publisher),
   629  			jsonhttptest.WithExpectedResponseHeader(api.ContentTypeHeader, "application/json; charset=utf-8"),
   630  		)
   631  	})
   632  	t.Run("download-w/-invalid-timestamp", func(t *testing.T) {
   633  		client, _, _, _ := newTestServer(t, testServerOptions{
   634  			Storer:        storerMock,
   635  			Logger:        logger,
   636  			Post:          mockpost.New(mockpost.WithAcceptAll()),
   637  			PublicKey:     pk.PublicKey,
   638  			AccessControl: mockac.New(mockac.WithHistory(h, fixtureHref.String())),
   639  		})
   640  		var (
   641  			invalidTime  = int64(-1)
   642  			encryptedRef = "c611199e1b3674d6bf89a83e518bd16896bf5315109b4a23dcb4682a02d17b97"
   643  		)
   644  
   645  		jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(encryptedRef), http.StatusBadRequest,
   646  			jsonhttptest.WithRequestHeader(api.SwarmActTimestampHeader, strconv.FormatInt(invalidTime, 10)),
   647  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, fixtureHref.String()),
   648  			jsonhttptest.WithRequestHeader(api.SwarmActPublisherHeader, publisher),
   649  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   650  				Code:    http.StatusBadRequest,
   651  				Message: accesscontrol.ErrInvalidTimestamp.Error(),
   652  			}),
   653  			jsonhttptest.WithRequestHeader(api.ContentTypeHeader, "text/html; charset=utf-8"),
   654  		)
   655  	})
   656  }
   657  
   658  // nolint:paralleltest,tparallel
   659  // TestAccessLogicPublisher
   660  // [positive test] 1.: uploading a file w/ ACT then download it w/ the publisher address and check the data.
   661  // [negative test] 2.: expect Bad request when the public key is invalid.
   662  // [negative test] 3.: try to download a file w/ an incorrect publisher address.
   663  // [negative test] 3.: try to download a file w/o a publisher address.
   664  func TestAccessLogicPublisher(t *testing.T) {
   665  	t.Parallel()
   666  	var (
   667  		spk, _               = hex.DecodeString("a786dd84b61485de12146fd9c4c02d87e8fd95f0542765cb7fc3d2e428c0bcfa")
   668  		pk, _                = crypto.DecodeSecp256k1PrivateKey(spk)
   669  		publicKeyBytes       = crypto.EncodeSecp256k1PublicKey(&pk.PublicKey)
   670  		publisher            = hex.EncodeToString(publicKeyBytes)
   671  		fileUploadResource   = "/bzz"
   672  		fileDownloadResource = func(addr string) string { return "/bzz/" + addr }
   673  		storerMock           = mockstorer.New()
   674  		h, fixtureHref       = prepareHistoryFixture(storerMock)
   675  		logger               = log.Noop
   676  		fileName             = "sample.html"
   677  		now                  = time.Now().Unix()
   678  	)
   679  
   680  	t.Run("upload-then-download-w/-publisher-and-check-data", func(t *testing.T) {
   681  		client, _, _, _ := newTestServer(t, testServerOptions{
   682  			Storer:        storerMock,
   683  			Logger:        logger,
   684  			Post:          mockpost.New(mockpost.WithAcceptAll()),
   685  			PublicKey:     pk.PublicKey,
   686  			AccessControl: mockac.New(mockac.WithHistory(h, fixtureHref.String()), mockac.WithPublisher(publisher)),
   687  		})
   688  		var (
   689  			encryptedRef = "a5a26b4915d7ce1622f9ca52252092cf2445f98d359dabaf52588c05911aaf4f"
   690  			testfile     = `<!DOCTYPE html>
   691  			<html>
   692  			<body>
   693  
   694  			<h1>My First Heading</h1>
   695  
   696  			<p>My first paragraph.</p>
   697  
   698  			</body>
   699  			</html>`
   700  		)
   701  
   702  		jsonhttptest.Request(t, client, http.MethodPost, fileUploadResource+"?name="+fileName, http.StatusCreated,
   703  			jsonhttptest.WithRequestHeader(api.SwarmActHeader, "true"),
   704  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
   705  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, fixtureHref.String()),
   706  			jsonhttptest.WithRequestBody(strings.NewReader(testfile)),
   707  			jsonhttptest.WithExpectedJSONResponse(api.BzzUploadResponse{
   708  				Reference: swarm.MustParseHexAddress(encryptedRef),
   709  			}),
   710  			jsonhttptest.WithRequestHeader(api.ContentTypeHeader, "text/html; charset=utf-8"),
   711  			jsonhttptest.WithNonEmptyResponseHeader(api.SwarmTagHeader),
   712  			jsonhttptest.WithExpectedResponseHeader(api.ETagHeader, fmt.Sprintf("%q", encryptedRef)),
   713  		)
   714  
   715  		jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(encryptedRef), http.StatusOK,
   716  			jsonhttptest.WithRequestHeader(api.SwarmActTimestampHeader, strconv.FormatInt(now, 10)),
   717  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, fixtureHref.String()),
   718  			jsonhttptest.WithRequestHeader(api.SwarmActPublisherHeader, publisher),
   719  			jsonhttptest.WithExpectedResponse([]byte(testfile)),
   720  			jsonhttptest.WithExpectedContentLength(len(testfile)),
   721  			jsonhttptest.WithExpectedResponseHeader(api.ContentTypeHeader, "text/html; charset=utf-8"),
   722  			jsonhttptest.WithExpectedResponseHeader(api.ContentDispositionHeader, fmt.Sprintf(`inline; filename="%s"`, fileName)),
   723  		)
   724  	})
   725  
   726  	t.Run("upload-then-download-invalid-publickey", func(t *testing.T) {
   727  		client, _, _, _ := newTestServer(t, testServerOptions{
   728  			Storer:        storerMock,
   729  			Logger:        logger,
   730  			Post:          mockpost.New(mockpost.WithAcceptAll()),
   731  			PublicKey:     pk.PublicKey,
   732  			AccessControl: mockac.New(mockac.WithPublisher(publisher)),
   733  		})
   734  		var (
   735  			publickey    = "b786dd84b61485de12146fd9c4c02d87e8fd95f0542765cb7fc3d2e428c0bcfb"
   736  			encryptedRef = "a5a26b4915d7ce1622f9ca52252092cf2445f98d359dabaf52588c05911aaf4f"
   737  			testfile     = `<!DOCTYPE html>
   738  			<html>
   739  			<body>
   740  
   741  			<h1>My First Heading</h1>
   742  
   743  			<p>My first paragraph.</p>
   744  
   745  			</body>
   746  			</html>`
   747  		)
   748  
   749  		header := jsonhttptest.Request(t, client, http.MethodPost, fileUploadResource+"?name="+fileName, http.StatusCreated,
   750  			jsonhttptest.WithRequestHeader(api.SwarmActHeader, "true"),
   751  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
   752  			jsonhttptest.WithRequestBody(strings.NewReader(testfile)),
   753  			jsonhttptest.WithExpectedJSONResponse(api.BzzUploadResponse{
   754  				Reference: swarm.MustParseHexAddress(encryptedRef),
   755  			}),
   756  			jsonhttptest.WithRequestHeader(api.ContentTypeHeader, "text/html; charset=utf-8"),
   757  			jsonhttptest.WithNonEmptyResponseHeader(api.SwarmTagHeader),
   758  			jsonhttptest.WithExpectedResponseHeader(api.ETagHeader, fmt.Sprintf("%q", encryptedRef)),
   759  		)
   760  
   761  		historyRef := header.Get(api.SwarmActHistoryAddressHeader)
   762  		jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(encryptedRef), http.StatusBadRequest,
   763  			jsonhttptest.WithRequestHeader(api.SwarmActTimestampHeader, strconv.FormatInt(now, 10)),
   764  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, historyRef),
   765  			jsonhttptest.WithRequestHeader(api.SwarmActPublisherHeader, publickey),
   766  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   767  				Code:    http.StatusBadRequest,
   768  				Message: "invalid header params",
   769  				Reasons: []jsonhttp.Reason{
   770  					{
   771  						Field: "Swarm-Act-Publisher",
   772  						Error: "malformed public key: invalid length: 32",
   773  					},
   774  				},
   775  			}),
   776  			jsonhttptest.WithRequestHeader(api.ContentTypeHeader, "text/html; charset=utf-8"),
   777  		)
   778  	})
   779  
   780  	t.Run("download-w/-wrong-publisher", func(t *testing.T) {
   781  		var (
   782  			downloader   = "03c712a7e29bc792ac8d8ae49793d28d5bda27ed70f0d90697b2fb456c0a168bd2"
   783  			encryptedRef = "a5df670544eaea29e61b19d8739faa4573b19e4426e58a173e51ed0b5e7e2ade"
   784  		)
   785  		client, _, _, _ := newTestServer(t, testServerOptions{
   786  			Storer:        storerMock,
   787  			Logger:        logger,
   788  			Post:          mockpost.New(mockpost.WithAcceptAll()),
   789  			PublicKey:     pk.PublicKey,
   790  			AccessControl: mockac.New(mockac.WithHistory(h, fixtureHref.String()), mockac.WithPublisher(publisher)),
   791  		})
   792  
   793  		jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(encryptedRef), http.StatusBadRequest,
   794  			jsonhttptest.WithRequestHeader(api.SwarmActTimestampHeader, strconv.FormatInt(now, 10)),
   795  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, fixtureHref.String()),
   796  			jsonhttptest.WithRequestHeader(api.SwarmActPublisherHeader, downloader),
   797  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   798  				Message: accesscontrol.ErrInvalidPublicKey.Error(),
   799  				Code:    http.StatusBadRequest,
   800  			}),
   801  			jsonhttptest.WithExpectedResponseHeader(api.ContentTypeHeader, "application/json; charset=utf-8"),
   802  		)
   803  	})
   804  
   805  	t.Run("re-upload-with-invalid-publickey", func(t *testing.T) {
   806  		var (
   807  			downloader = "03c712a7e29bc792ac8d8ae49793d28d5bda27ed70f0d90697b2fb456c0a168bd2"
   808  			testfile   = "testfile1"
   809  		)
   810  		downloaderClient, _, _, _ := newTestServer(t, testServerOptions{
   811  			Storer:        storerMock,
   812  			Logger:        logger,
   813  			Post:          mockpost.New(mockpost.WithAcceptAll()),
   814  			PublicKey:     pk.PublicKey,
   815  			AccessControl: mockac.New(mockac.WithPublisher(downloader)),
   816  		})
   817  
   818  		jsonhttptest.Request(t, downloaderClient, http.MethodPost, fileUploadResource+"?name="+fileName, http.StatusBadRequest,
   819  			jsonhttptest.WithRequestHeader(api.SwarmActHeader, "true"),
   820  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
   821  			jsonhttptest.WithRequestBody(strings.NewReader(testfile)),
   822  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   823  				Code:    http.StatusBadRequest,
   824  				Message: "invalid public key",
   825  			}),
   826  			jsonhttptest.WithRequestHeader(api.ContentTypeHeader, "text/html; charset=utf-8"),
   827  		)
   828  
   829  	})
   830  
   831  	t.Run("download-w/o-publisher", func(t *testing.T) {
   832  		encryptedRef := "a5df670544eaea29e61b19d8739faa4573b19e4426e58a173e51ed0b5e7e2ade"
   833  		client, _, _, _ := newTestServer(t, testServerOptions{
   834  			Storer:        storerMock,
   835  			Logger:        logger,
   836  			Post:          mockpost.New(mockpost.WithAcceptAll()),
   837  			PublicKey:     pk.PublicKey,
   838  			AccessControl: mockac.New(mockac.WithHistory(h, fixtureHref.String()), mockac.WithPublisher(publisher)),
   839  		})
   840  
   841  		jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(encryptedRef), http.StatusNotFound,
   842  			jsonhttptest.WithRequestHeader(api.SwarmActTimestampHeader, strconv.FormatInt(now, 10)),
   843  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, fixtureHref.String()),
   844  			jsonhttptest.WithRequestHeader(api.SwarmActPublisherHeader, publisher),
   845  			jsonhttptest.WithExpectedResponseHeader(api.ContentTypeHeader, "application/json; charset=utf-8"),
   846  		)
   847  	})
   848  }
   849  
   850  func TestAccessLogicGrantees(t *testing.T) {
   851  	t.Parallel()
   852  	var (
   853  		spk, _          = hex.DecodeString("a786dd84b61485de12146fd9c4c02d87e8fd95f0542765cb7fc3d2e428c0bcfa")
   854  		pk, _           = crypto.DecodeSecp256k1PrivateKey(spk)
   855  		storerMock      = mockstorer.New()
   856  		h, fixtureHref  = prepareHistoryFixture(storerMock)
   857  		logger          = log.Noop
   858  		addr            = swarm.RandAddress(t)
   859  		client, _, _, _ = newTestServer(t, testServerOptions{
   860  			Storer:        storerMock,
   861  			Logger:        logger,
   862  			Post:          mockpost.New(mockpost.WithAcceptAll()),
   863  			PublicKey:     pk.PublicKey,
   864  			AccessControl: mockac.New(mockac.WithHistory(h, fixtureHref.String())),
   865  		})
   866  	)
   867  	t.Run("get-grantees", func(t *testing.T) {
   868  		var (
   869  			publicKeyBytes = crypto.EncodeSecp256k1PublicKey(&pk.PublicKey)
   870  			publisher      = hex.EncodeToString(publicKeyBytes)
   871  		)
   872  		clientwihtpublisher, _, _, _ := newTestServer(t, testServerOptions{
   873  			Storer:        storerMock,
   874  			Logger:        logger,
   875  			Post:          mockpost.New(mockpost.WithAcceptAll()),
   876  			PublicKey:     pk.PublicKey,
   877  			AccessControl: mockac.New(mockac.WithHistory(h, fixtureHref.String()), mockac.WithPublisher(publisher)),
   878  		})
   879  		expected := []string{
   880  			"03d7660772cc3142f8a7a2dfac46ce34d12eac1718720cef0e3d94347902aa96a2",
   881  			"03c712a7e29bc792ac8d8ae49793d28d5bda27ed70f0d90697b2fb456c0a168bd2",
   882  			"032541acf966823bae26c2c16a7102e728ade3e2e29c11a8a17b29d8eb2bd19302",
   883  		}
   884  		jsonhttptest.Request(t, clientwihtpublisher, http.MethodGet, "/grantee/"+addr.String(), http.StatusOK,
   885  			jsonhttptest.WithExpectedJSONResponse(expected),
   886  		)
   887  	})
   888  
   889  	t.Run("get-grantees-unauthorized", func(t *testing.T) {
   890  		jsonhttptest.Request(t, client, http.MethodGet, "/grantee/fc4e9fe978991257b897d987bc4ff13058b66ef45a53189a0b4fe84bb3346396", http.StatusNotFound,
   891  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   892  				Message: "granteelist not found",
   893  				Code:    http.StatusNotFound,
   894  			}),
   895  		)
   896  	})
   897  	t.Run("get-grantees-invalid-address", func(t *testing.T) {
   898  		jsonhttptest.Request(t, client, http.MethodGet, "/grantee/asd", http.StatusBadRequest,
   899  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   900  				Code:    http.StatusBadRequest,
   901  				Message: "invalid path params",
   902  				Reasons: []jsonhttp.Reason{
   903  					{
   904  						Field: "address",
   905  						Error: api.HexInvalidByteError('s').Error(),
   906  					},
   907  				},
   908  			}),
   909  		)
   910  	})
   911  	t.Run("add-revoke-grantees", func(t *testing.T) {
   912  		body := api.GranteesPatchRequest{
   913  			Addlist:    []string{"02ab7473879005929d10ce7d4f626412dad9fe56b0a6622038931d26bd79abf0a4"},
   914  			Revokelist: []string{"02ab7473879005929d10ce7d4f626412dad9fe56b0a6622038931d26bd79abf0a4"},
   915  		}
   916  		jsonhttptest.Request(t, client, http.MethodPatch, "/grantee/"+addr.String(), http.StatusOK,
   917  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
   918  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, addr.String()),
   919  			jsonhttptest.WithJSONRequestBody(body),
   920  		)
   921  	})
   922  	t.Run("add-revoke-grantees-wrong-history", func(t *testing.T) {
   923  		body := api.GranteesPatchRequest{
   924  			Addlist:    []string{"02ab7473879005929d10ce7d4f626412dad9fe56b0a6622038931d26bd79abf0a4"},
   925  			Revokelist: []string{"02ab7473879005929d10ce7d4f626412dad9fe56b0a6622038931d26bd79abf0a4"},
   926  		}
   927  		jsonhttptest.Request(t, client, http.MethodPatch, "/grantee/"+addr.String(), http.StatusNotFound,
   928  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
   929  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, swarm.EmptyAddress.String()),
   930  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   931  				Message: "act or history entry not found",
   932  				Code:    http.StatusNotFound,
   933  			}),
   934  			jsonhttptest.WithJSONRequestBody(body),
   935  		)
   936  	})
   937  	t.Run("invlaid-add-grantees", func(t *testing.T) {
   938  		body := api.GranteesPatchRequest{
   939  			Addlist: []string{"random-string"},
   940  		}
   941  		jsonhttptest.Request(t, client, http.MethodPatch, "/grantee/"+addr.String(), http.StatusBadRequest,
   942  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
   943  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, addr.String()),
   944  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   945  				Message: "invalid add list",
   946  				Code:    http.StatusBadRequest,
   947  			}),
   948  			jsonhttptest.WithJSONRequestBody(body),
   949  		)
   950  	})
   951  	t.Run("invlaid-revoke-grantees", func(t *testing.T) {
   952  		body := api.GranteesPatchRequest{
   953  			Revokelist: []string{"random-string"},
   954  		}
   955  		jsonhttptest.Request(t, client, http.MethodPatch, "/grantee/"+addr.String(), http.StatusBadRequest,
   956  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
   957  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, addr.String()),
   958  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   959  				Message: "invalid revoke list",
   960  				Code:    http.StatusBadRequest,
   961  			}),
   962  			jsonhttptest.WithJSONRequestBody(body),
   963  		)
   964  	})
   965  	t.Run("add-revoke-grantees-empty-body", func(t *testing.T) {
   966  		jsonhttptest.Request(t, client, http.MethodPatch, "/grantee/"+addr.String(), http.StatusBadRequest,
   967  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
   968  			jsonhttptest.WithRequestBody(bytes.NewReader(nil)),
   969  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   970  				Message: "could not validate request",
   971  				Code:    http.StatusBadRequest,
   972  			}),
   973  		)
   974  	})
   975  	t.Run("add-grantee-with-history", func(t *testing.T) {
   976  		body := api.GranteesPatchRequest{
   977  			Addlist: []string{"02ab7473879005929d10ce7d4f626412dad9fe56b0a6622038931d26bd79abf0a4"},
   978  		}
   979  		jsonhttptest.Request(t, client, http.MethodPatch, "/grantee/"+addr.String(), http.StatusOK,
   980  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
   981  			jsonhttptest.WithRequestHeader(api.SwarmActHistoryAddressHeader, addr.String()),
   982  			jsonhttptest.WithJSONRequestBody(body),
   983  		)
   984  	})
   985  	t.Run("add-grantee-without-history", func(t *testing.T) {
   986  		body := api.GranteesPatchRequest{
   987  			Addlist: []string{"02ab7473879005929d10ce7d4f626412dad9fe56b0a6622038931d26bd79abf0a4"},
   988  		}
   989  		jsonhttptest.Request(t, client, http.MethodPatch, "/grantee/"+addr.String(), http.StatusBadRequest,
   990  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
   991  			jsonhttptest.WithJSONRequestBody(body),
   992  		)
   993  	})
   994  
   995  	t.Run("create-granteelist", func(t *testing.T) {
   996  		body := api.GranteesPostRequest{
   997  			GranteeList: []string{
   998  				"02ab7473879005929d10ce7d4f626412dad9fe56b0a6622038931d26bd79abf0a4",
   999  				"03d7660772cc3142f8a7a2dfac46ce34d12eac1718720cef0e3d94347902aa96a2",
  1000  			},
  1001  		}
  1002  		jsonhttptest.Request(t, client, http.MethodPost, "/grantee", http.StatusCreated,
  1003  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
  1004  			jsonhttptest.WithJSONRequestBody(body),
  1005  		)
  1006  	})
  1007  	t.Run("create-granteelist-without-stamp", func(t *testing.T) {
  1008  		body := api.GranteesPostRequest{
  1009  			GranteeList: []string{
  1010  				"03d7660772cc3142f8a7a2dfac46ce34d12eac1718720cef0e3d94347902aa96a2",
  1011  			},
  1012  		}
  1013  		jsonhttptest.Request(t, client, http.MethodPost, "/grantee", http.StatusBadRequest,
  1014  			jsonhttptest.WithJSONRequestBody(body),
  1015  		)
  1016  	})
  1017  	t.Run("create-granteelist-empty-body", func(t *testing.T) {
  1018  		jsonhttptest.Request(t, client, http.MethodPost, "/grantee", http.StatusBadRequest,
  1019  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
  1020  			jsonhttptest.WithRequestBody(bytes.NewReader(nil)),
  1021  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
  1022  				Message: "could not validate request",
  1023  				Code:    http.StatusBadRequest,
  1024  			}),
  1025  		)
  1026  	})
  1027  	t.Run("create-granteelist-invalid-body", func(t *testing.T) {
  1028  		body := api.GranteesPostRequest{
  1029  			GranteeList: []string{"random-string"},
  1030  		}
  1031  		jsonhttptest.Request(t, client, http.MethodPost, "/grantee", http.StatusBadRequest,
  1032  			jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
  1033  			jsonhttptest.WithRequestBody(bytes.NewReader(nil)),
  1034  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
  1035  				Message: "invalid grantee list",
  1036  				Code:    http.StatusBadRequest,
  1037  			}),
  1038  			jsonhttptest.WithJSONRequestBody(body),
  1039  		)
  1040  	})
  1041  }