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 }