func TestShareSearchSerialization(t *testing.T) {
	signer := blob.MustParse("yyy-5678")

	q := &search.SearchQuery{
		Expression: "is:image",
		Limit:      42,
	}
	bb := schema.NewShareRef(schema.ShareHaveRef, true)
	bb.SetShareSearch(q)
	bb = bb.SetSigner(signer)
	bb = bb.SetClaimDate(time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC))
	s := bb.Blob().JSON()

	want := `{"camliVersion": 1,
  "authType": "haveref",
  "camliSigner": "yyy-5678",
  "camliType": "claim",
  "claimDate": "2009-11-10T23:00:00Z",
  "claimType": "share",
  "search": {
    "expression": "is:image",
    "limit": 42,
    "around": null
  },
  "transitive": true
}`
	if want != s {
		t.Errorf("Incorrect serialization of shared search. Wanted:\n %s\nGot:\n%s\n", want, s)
	}
}
Example #2
0
func (c *shareCmd) RunCommand(args []string) error {
	unsigned := schema.NewShareRef(schema.ShareHaveRef, c.transitive)

	if c.search != "" {
		if len(args) != 0 {
			return cmdmain.UsageError("when using the -search flag, share takes zero arguments")
		}
		var q search.SearchQuery
		if err := json.Unmarshal([]byte(c.search), &q); err != nil {
			return cmdmain.UsageError(fmt.Sprintf("invalid search: %s", err))
		}
		unsigned.SetShareSearch(&q)
	} else {
		if len(args) != 1 {
			return cmdmain.UsageError("share takes at most one argument")
		}
		target, ok := blob.Parse(args[0])
		if !ok {
			return cmdmain.UsageError("invalid blobref")
		}
		unsigned.SetShareTarget(target)
	}

	if c.duration != 0 {
		unsigned.SetShareExpiration(time.Now().Add(c.duration))
	}

	pr, err := getUploader().UploadAndSignBlob(unsigned)
	handleResult("share", pr, err)
	return nil
}
Example #3
0
// Issue 228: only follow transitive blobref links in known trusted schema fields.
func TestSharingTransitiveSafety(t *testing.T) {
	st := newShareTester(t)
	defer st.done()

	content := "the secret"
	contentRef := blob.SHA1FromString(content)

	// User-injected blob, somehow.
	evilClaim := fmt.Sprintf("Some payload containing the ref: %v", contentRef)
	evilClaimRef := blob.SHA1FromString(evilClaim)

	share := schema.NewShareRef(schema.ShareHaveRef, false).
		SetShareTarget(evilClaimRef).
		SetShareIsTransitive(true).
		SetSigner(blob.SHA1FromString("irrelevant")).
		SetRawStringField("camliSig", "alsounused")
	shareRef := func() blob.Ref { return share.Blob().BlobRef() }

	st.put(share.Blob())
	st.putRaw(contentRef, content)
	st.putRaw(evilClaimRef, evilClaim)

	st.testGet(shareRef().String(), noError)
	st.testGet(fmt.Sprintf("%s?via=%s", evilClaimRef, shareRef()), noError)

	st.testGet(fmt.Sprintf("%s?via=%s,%s", contentRef, shareRef(), evilClaimRef), viaChainInvalidLink)
	if !st.slept() {
		t.Error("expected sleep after miss")
	}
}
Example #4
0
func TestHandleGetViaSharing(t *testing.T) {
	st := newShareTester(t)
	defer st.done()

	content := "monkey" // the secret
	contentRef := blob.SHA1FromString(content)

	link := fmt.Sprintf(`{"camliVersion": 1,
"camliType": "file",
"parts": [
   {"blobRef": "%v", "size": %d}
]}`, contentRef, len(content))
	linkRef := blob.SHA1FromString(link)

	share := schema.NewShareRef(schema.ShareHaveRef, false).
		SetShareTarget(linkRef).
		SetSigner(blob.SHA1FromString("irrelevant")).
		SetRawStringField("camliSig", "alsounused")
	shareRef := func() blob.Ref { return share.Blob().BlobRef() }

	t.Logf("Checking share blob doesn't yet exist...")
	st.testGet(shareRef().String(), shareFetchFailed)
	if !st.slept() {
		t.Error("expected sleep after miss")
	}
	st.put(share.Blob())
	t.Logf("Checking share blob now exists...")
	st.testGet(shareRef().String(), noError)

	t.Logf("Checking we can't get the content directly via the share...")
	st.testGet(fmt.Sprintf("%s?via=%s", contentRef, shareRef()), shareTargetInvalid)

	t.Logf("Checking we can't get the link (file) blob directly...")
	st.putRaw(linkRef, link)
	st.testGet(linkRef.String(), shareBlobInvalid)

	t.Logf("Checking we can get the link (file) blob via the share...")
	st.testGet(fmt.Sprintf("%s?via=%s", linkRef, shareRef()), noError)

	t.Logf("Checking we can't get the content via the non-transitive share...")
	st.testGet(fmt.Sprintf("%s?via=%s,%s", contentRef, shareRef(), linkRef), shareNotTransitive)

	// TODO: new test?
	share.SetShareIsTransitive(true)
	st.put(share.Blob())
	st.testGet(fmt.Sprintf("%s?via=%s,%s", linkRef, shareRef(), linkRef), viaChainInvalidLink)

	st.putRaw(contentRef, content)
	st.testGet(fmt.Sprintf("%s?via=%s,%s", contentRef, shareRef(), linkRef), noError)

	// new test?
	share.SetShareExpiration(time.Now().Add(-time.Duration(10) * time.Minute))
	st.put(share.Blob())
	st.testGet(fmt.Sprintf("%s?via=%s,%s", contentRef, shareRef(), linkRef), shareExpired)

	share.SetShareExpiration(time.Now().Add(time.Duration(10) * time.Minute))
	st.put(share.Blob())
	st.testGet(fmt.Sprintf("%s?via=%s,%s", contentRef, shareRef(), linkRef), noError)
}
Example #5
0
func (c *shareCmd) RunCommand(args []string) error {
	if len(args) != 1 {
		return cmdmain.UsageError("share takes exactly one argument, a blobref")
	}
	target, ok := blob.Parse(args[0])
	if !ok {
		return cmdmain.UsageError("invalid blobref")
	}
	unsigned := schema.NewShareRef(schema.ShareHaveRef, target, c.transitive)
	if c.duration != 0 {
		unsigned.SetShareExpiration(time.Now().Add(c.duration))
	}

	pr, err := getUploader().UploadAndSignBlob(unsigned)
	handleResult("share", pr, err)
	return nil
}
Example #6
0
func (up *Uploader) UploadShare(target *blobref.BlobRef, transitive bool) (*client.PutResult, error) {
	unsigned := schema.NewShareRef(schema.ShareHaveRef, target, transitive)
	return up.UploadAndSignMap(unsigned)
}
Example #7
0
func TestHandleGetViaSharing(t *testing.T) {
	// TODO(aa): It would be good if we could test that we are failing for
	// the right reason for all of these (some kind of internal error code).

	sto := &test.Fetcher{}
	handler := &httputil.PrefixHandler{"/", &shareHandler{sto}}
	wr := &httptest.ResponseRecorder{}

	get := func(path string) *httptest.ResponseRecorder {
		wr = httptest.NewRecorder()
		req, _ := http.NewRequest("GET", "http://unused/"+path, nil)
		handler.ServeHTTP(wr, req)
		return wr
	}

	content := "monkey"
	contentRef := blob.SHA1FromString(content)

	// For the purposes of following the via chain, the only thing that
	// matters is that the content of each link contains the name of the
	// next link.
	link := contentRef.String()
	linkRef := blob.SHA1FromString(link)

	share := schema.NewShareRef(schema.ShareHaveRef, linkRef, false).
		SetSigner(blob.SHA1FromString("irrelevant")).
		SetRawStringField("camliSig", "alsounused")

	log.Print("Should fail because first link does not exist")
	get(share.Blob().BlobRef().String())
	ExpectInt(t, 401, wr.Code, "")

	log.Print("Should fail because share target does not match next link")
	sto.ReceiveBlob(share.Blob().BlobRef(), strings.NewReader(share.Blob().JSON()))
	get(contentRef.String() + "?via=" + share.Blob().BlobRef().String())
	ExpectInt(t, 401, wr.Code, "")

	log.Print("Should fail because first link is not a share")
	sto.ReceiveBlob(linkRef, strings.NewReader(link))
	get(linkRef.String())
	ExpectInt(t, 401, wr.Code, "")
	log.Print("Should successfully fetch share")
	get(share.Blob().BlobRef().String())
	ExpectInt(t, 200, wr.Code, "")

	log.Print("Should successfully fetch link via share")
	get(linkRef.String() + "?via=" + share.Blob().BlobRef().String())
	ExpectInt(t, 200, wr.Code, "")

	log.Print("Should fail because share is not transitive")
	get(contentRef.String() + "?via=" + share.Blob().BlobRef().String() + "," + linkRef.String())
	ExpectInt(t, 401, wr.Code, "")

	log.Print("Should fail because link content does not contain target")
	share.SetShareIsTransitive(true)
	sto.ReceiveBlob(share.Blob().BlobRef(), strings.NewReader(share.Blob().JSON()))
	get(linkRef.String() + "?via=" + share.Blob().BlobRef().String() + "," + linkRef.String())
	ExpectInt(t, 401, wr.Code, "")

	log.Print("Should successfully fetch content via link via share")
	sto.ReceiveBlob(contentRef, strings.NewReader(content))
	get(contentRef.String() + "?via=" + share.Blob().BlobRef().String() + "," + linkRef.String())
	ExpectInt(t, 200, wr.Code, "")

	log.Print("Should fail because share is expired")
	share.SetShareExpiration(time.Now().Add(-time.Duration(10) * time.Minute))
	sto.ReceiveBlob(share.Blob().BlobRef(), strings.NewReader(share.Blob().JSON()))
	get(contentRef.String() + "?via=" + share.Blob().BlobRef().String() + "," + linkRef.String())
	ExpectInt(t, 401, wr.Code, "")

	log.Print("Should succeed because share has not expired")
	share.SetShareExpiration(time.Now().Add(time.Duration(10) * time.Minute))
	sto.ReceiveBlob(share.Blob().BlobRef(), strings.NewReader(share.Blob().JSON()))
	get(contentRef.String() + "?via=" + share.Blob().BlobRef().String() + "," + linkRef.String())
	ExpectInt(t, 200, wr.Code, "")

	// TODO(aa): assemble
}
Example #8
0
func TestHandleGetViaSharing(t *testing.T) {
	sto := &test.Fetcher{}
	handler := &shareHandler{fetcher: sto}
	var wr *httptest.ResponseRecorder

	putRaw := func(ref blob.Ref, data string) {
		if _, err := blobserver.Receive(sto, ref, strings.NewReader(data)); err != nil {
			t.Fatal(err)
		}
	}

	put := func(blob *schema.Blob) {
		putRaw(blob.BlobRef(), blob.JSON())
	}

	get := func(path string) *shareError {
		wr = httptest.NewRecorder()
		req, _ := http.NewRequest("GET", "http://unused/"+path, nil)
		err := handler.serveHTTP(wr, req)
		if err != nil {
			return err.(*shareError)
		}
		return nil
	}

	content := "monkey"
	contentRef := blob.SHA1FromString(content)

	// For the purposes of following the via chain, the only thing that
	// matters is that the content of each link contains the name of the
	// next link.
	link := contentRef.String()
	linkRef := blob.SHA1FromString(link)

	share := schema.NewShareRef(schema.ShareHaveRef, linkRef, false).
		SetSigner(blob.SHA1FromString("irrelevant")).
		SetRawStringField("camliSig", "alsounused")

	var err *shareError

	if err = get(share.Blob().BlobRef().String()); err == nil || err.code != shareFetchFailed {
		t.Error("Expected missing blob error")
	}

	put(share.Blob())
	if err = get(fmt.Sprintf("%s?via=%s", contentRef, share.Blob().BlobRef())); err == nil || err.code != shareTargetInvalid {
		t.Error("Expected invalid target error")
	}

	putRaw(linkRef, link)
	if err = get(linkRef.String()); err == nil || err.code != shareReadFailed {
		t.Error("Expected invalid share blob error")
	}

	if err = get(share.Blob().BlobRef().String()); err != nil {
		t.Error("Expected to successfully fetch share, but got: %s", err)
	}

	if err = get(fmt.Sprintf("%s?via=%s", linkRef, share.Blob().BlobRef())); err != nil {
		t.Error("Expected to successfully fetch link via share, but got: %s", err)
	}

	if err = get(fmt.Sprintf("%s?via=%s,%s", contentRef, share.Blob().BlobRef(), linkRef)); err == nil || err.code != shareNotTransitive {
		t.Error("Expected share not transitive error")
	}

	share.SetShareIsTransitive(true)
	put(share.Blob())
	if err = get(fmt.Sprintf("%s?via=%s,%s", linkRef, share.Blob().BlobRef(), linkRef)); err == nil || err.code != viaChainInvalidLink {
		t.Error("Expected via chain invalid link err")
	}

	putRaw(contentRef, content)
	if err = get(fmt.Sprintf("%s?via=%s,%s", contentRef, share.Blob().BlobRef(), linkRef)); err != nil {
		t.Error("Expected to succesfully fetch via link via share, but got: %s", err)
	}

	share.SetShareExpiration(time.Now().Add(-time.Duration(10) * time.Minute))
	put(share.Blob())
	if err = get(fmt.Sprintf("%s?via=%s,%s", contentRef, share.Blob().BlobRef(), linkRef)); err == nil || err.code != shareExpired {
		t.Error("Expected share expired error")
	}

	share.SetShareExpiration(time.Now().Add(time.Duration(10) * time.Minute))
	put(share.Blob())
	if err = get(fmt.Sprintf("%s?via=%s,%s", contentRef, share.Blob().BlobRef(), linkRef)); err != nil {
		t.Error("Expected to successfully fetch unexpired share, but got: %s", err)
	}

	// TODO(aa): assemble
}
Example #9
0
func TestHandleGetViaSharing(t *testing.T) {
	sto := &test.Fetcher{}
	handler := &shareHandler{fetcher: sto}
	var wr *httptest.ResponseRecorder

	putRaw := func(ref blob.Ref, data string) {
		if _, err := blobserver.Receive(sto, ref, strings.NewReader(data)); err != nil {
			t.Fatal(err)
		}
	}

	put := func(blob *schema.Blob) {
		putRaw(blob.BlobRef(), blob.JSON())
	}

	get := func(path string) *shareError {
		wr = httptest.NewRecorder()
		req, _ := http.NewRequest("GET", "http://unused/"+path, nil)
		err := handler.serveHTTP(wr, req)
		if err != nil {
			return err.(*shareError)
		}
		return nil
	}

	testGet := func(path string, expectedError errorCode) {
		err := get(path)
		if expectedError != noError {
			if err == nil || err.code != expectedError {
				t.Errorf("Fetching %s, expected error %#v, but got %#v", path, expectedError, err)
			}
		} else {
			if err != nil {
				t.Errorf("Fetching %s, expected success but got %#v", path, err)
			}
		}

		if wr.HeaderMap.Get("Access-Control-Allow-Origin") != "*" {
			t.Errorf("Fetching %s, share response did not contain expected CORS header", path)
		}
	}

	content := "monkey"
	contentRef := blob.SHA1FromString(content)

	// For the purposes of following the via chain, the only thing that
	// matters is that the content of each link contains the name of the
	// next link.
	link := contentRef.String()
	linkRef := blob.SHA1FromString(link)

	share := schema.NewShareRef(schema.ShareHaveRef, false).
		SetShareTarget(linkRef).
		SetSigner(blob.SHA1FromString("irrelevant")).
		SetRawStringField("camliSig", "alsounused")

	testGet(share.Blob().BlobRef().String(), shareFetchFailed)

	put(share.Blob())
	testGet(fmt.Sprintf("%s?via=%s", contentRef, share.Blob().BlobRef()), shareTargetInvalid)

	putRaw(linkRef, link)
	testGet(linkRef.String(), shareReadFailed)
	testGet(share.Blob().BlobRef().String(), noError)
	testGet(fmt.Sprintf("%s?via=%s", linkRef, share.Blob().BlobRef()), noError)
	testGet(fmt.Sprintf("%s?via=%s,%s", contentRef, share.Blob().BlobRef(), linkRef), shareNotTransitive)

	share.SetShareIsTransitive(true)
	put(share.Blob())
	testGet(fmt.Sprintf("%s?via=%s,%s", linkRef, share.Blob().BlobRef(), linkRef), viaChainInvalidLink)

	putRaw(contentRef, content)
	testGet(fmt.Sprintf("%s?via=%s,%s", contentRef, share.Blob().BlobRef(), linkRef), noError)

	share.SetShareExpiration(time.Now().Add(-time.Duration(10) * time.Minute))
	put(share.Blob())
	testGet(fmt.Sprintf("%s?via=%s,%s", contentRef, share.Blob().BlobRef(), linkRef), shareExpired)

	share.SetShareExpiration(time.Now().Add(time.Duration(10) * time.Minute))
	put(share.Blob())
	testGet(fmt.Sprintf("%s?via=%s,%s", contentRef, share.Blob().BlobRef(), linkRef), noError)

	// TODO(aa): assemble
}