diff --git a/pkg/client/client.go b/pkg/client/client.go index 9c4b85410..ff7527f00 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -132,7 +132,7 @@ func NewFromShareRoot(shareBlobURL string) (c *Client, target *blobref.BlobRef, if err != nil { return nil, nil, fmt.Errorf("Error parsing JSON from %s: %v", shareBlobURL, err) } - if blob.ShareAuthType() != "haveref" { + if blob.ShareAuthType() != schema.ShareHaveRef { return nil, nil, fmt.Errorf("Unknown share authType of %q", blob.ShareAuthType()) } target = blob.ShareTarget() diff --git a/pkg/schema/blob.go b/pkg/schema/blob.go index be38c9519..88c5468bd 100644 --- a/pkg/schema/blob.go +++ b/pkg/schema/blob.go @@ -91,7 +91,7 @@ func (b *Blob) FileName() string { func (b *Blob) ClaimDate() (time.Time, error) { var ct time.Time claimDate := b.ss.ClaimDate - if claimDate.IsZero() { + if claimDate.IsZero() { return ct, MissingFieldError("claimDate") } return claimDate.Time(), nil @@ -126,6 +126,18 @@ func (b *Blob) AsClaim() (c Claim, ok bool) { return } +// AsShare returns a Share if the receiver Blob has all the required fields. +func (b *Blob) AsShare() (s Share, ok bool) { + c, ok := b.AsClaim() + if !ok { + return + } + if b.ss.Type == "share" && b.ss.AuthType == ShareHaveRef && b.ss.Target != nil { + return Share{c}, true + } + return +} + // DirectoryEntries the "entries" field if valid and b's type is "directory", else // it returns nil func (b *Blob) DirectoryEntries() *blobref.BlobRef { @@ -191,6 +203,25 @@ func (c Claim) ModifiedPermanode() *blobref.BlobRef { return c.b.ss.Permanode } +// A Share is a claim for giving access to a user's blob(s). +// When returned from (*Blob).AsShare, it always represents +// a valid share with all required fields. +type Share struct { + Claim +} + +// Target returns the blob referenced by the Share. +func (s Share) Target() *blobref.BlobRef { + return s.b.ShareTarget() +} + +// IsTransitive returns whether the Share transitively +// gives access to everything reachable from the referenced +// blob. +func (s Share) IsTransitive() bool { + return s.b.ss.Transitive +} + // A Builder builds a JSON blob. // After mutating the Builder, call Blob to get the built blob. type Builder struct { diff --git a/pkg/schema/schema.go b/pkg/schema/schema.go index 9429bbb30..c577e28c5 100644 --- a/pkg/schema/schema.go +++ b/pkg/schema/schema.go @@ -713,7 +713,7 @@ func NewDelAttributeClaim(permaNode *blobref.BlobRef, attr string) *Builder { }) } -// ShareHaveRef is the a share type specifying that if you "have the +// ShareHaveRef is the auth type specifying that if you "have the // reference" (know the blobref to the haveref share blob), then you // have access to the referenced object from that share blob. // This is the "send a link to a friend" access model. diff --git a/pkg/server/share.go b/pkg/server/share.go index 904a36ef0..adfe9cc29 100644 --- a/pkg/server/share.go +++ b/pkg/server/share.go @@ -18,7 +18,6 @@ package server import ( "bytes" - "encoding/json" "errors" "fmt" "io" @@ -122,22 +121,21 @@ func handleGetViaSharing(conn http.ResponseWriter, req *http.Request, auth.SendUnauthorized(conn, req) return } - jd := json.NewDecoder(file) - m := make(map[string]interface{}) - if err := jd.Decode(&m); err != nil { - log.Printf("Fetch chain 0 of %s wasn't JSON: %v", br.String(), err) + blob, err := schema.BlobFromReader(br, file) + if err != nil { + log.Printf("Can't create a blob from %v: %v", br.String(), err) auth.SendUnauthorized(conn, req) return } - // TODO(mpl): make and use a struct type with json tags instead of map[string]interface{}. - if m["camliType"].(string) != "share" { - log.Printf("Fetch chain 0 of %s wasn't a share", br.String()) + share, ok := blob.AsShare() + if !ok { + log.Printf("Fetch chain 0 of %s wasn't a valid Share", br.String()) auth.SendUnauthorized(conn, req) return } - if len(fetchChain) > 1 && fetchChain[1].String() != m["target"].(string) { + if len(fetchChain) > 1 && fetchChain[1].String() != share.Target().String() { log.Printf("Fetch chain 0->1 (%s -> %q) unauthorized, expected hop to %q", - br.String(), fetchChain[1].String(), m["target"]) + br.String(), fetchChain[1].String(), share.Target().String()) auth.SendUnauthorized(conn, req) return }