Sharing Restricted Access with Prefix using uplink GO

Hi all,

I’m trying to create a shared access with a bucket/prefix. I’m able to create a shared serialized access. I try to then use that serialized access to call to upload and I get “Unauthorized API credentials”. It’s worth mentioning that the upload works fine with a bucket/prefix when I use the serialized access created from the tardigrade api token. It’s also worth mentioning that when I don’t send in a prefix to the share, with only a bucket, I’m also able to upload.

Here’s my code for the access share in GO:

   .... some prep code above I haven't included 

   //p contains parameters from http post 

	access, err := uplink.ParseAccess(p.SerializedAccess)
	if err != nil {
		log.Fatalln("error parsing serialized access:", err)
	}

	var permission uplink.Permission
	if p.Permission == "read" {
		permission = uplink.ReadOnlyPermission()
	}
	if p.Permission == "write" {
		permission = uplink.WriteOnlyPermission()
	}
	if p.Permission == "full" {
		permission = uplink.FullPermission()
	}
	permission.NotBefore = time.Now()
	shared := uplink.SharePrefix{
		Bucket: p.Bucket,
		Prefix: p.Prefix + "/",
	}

	restrictedAccess, err := access.Share(permission, shared)
	if err != nil {
		log.Fatalln("error restrincting access:", err)
	}

    //serializedAccess is what I send back
	serializedAccess, err := restrictedAccess.Serialize()
	if err != nil {
		log.Fatalln("error serializing access grant:", err)
	}
   ...some code after
}

And this is the body of a sample Http post:

Body:
{
“SerializedAccess”:“some_serialized_access_from_API_token”,
“Bucket”:“public”,
“Permission”:“full”,
“Prefix”:“111aaa”
}

Any help would be appreciated!

@AkaashMukherjee I wasn’t able to reproduce the error you received. I made a self contained CLI to do roughly what you have outlined:

 package main

import (
	"fmt"
	"os"
	"time"

	"storj.io/uplink"
)

func cannot(err error) {
	if err != nil {
		panic(err)
	}
}

func main() {
	perm := os.Args[1]   // "read"
	bucket := os.Args[2] // "public"
	prefix := os.Args[3] // "111aaa"

	access, err := uplink.ParseAccess(os.Getenv("ACCESS"))
	cannot(err)

	var permission uplink.Permission
	switch perm {
	case "read":
		permission = uplink.ReadOnlyPermission()
	case "write":
		permission = uplink.WriteOnlyPermission()
	case "full":
		permission = uplink.FullPermission()
	}

	permission.NotBefore = time.Now()

	shared := uplink.SharePrefix{
		Bucket: bucket,
		Prefix: prefix + "/",
	}

	restrictedAccess, err := access.Share(permission, shared)
	cannot(err)

	serializedAccess, err := restrictedAccess.Serialize()
	cannot(err)

	fmt.Println(serializedAccess)
}

Here are some trial runs:

export ACCESS=my-root-level-grant
# Bucket listing works:
$ uplink --access $(./uplink-share read caleb-test 111aaa) ls
BKT 2020-12-23 07:13:41 caleb-test

# Listing without proper prefix does not:
$ uplink --access $(./uplink-share read caleb-test 111aaa) ls sj://caleb-test
Error: uplink: metainfo: unable to find encryption base for: caleb-test/""

# Listing with proper prefix does:
$ uplink --access $(./uplink-share read caleb-test 111aaa) ls sj://caleb-test/111aaa
OBJ 2021-02-01 13:44:50          823 111aaa/main.go

# Can't remove with a read-only grant:
$ uplink --access $(./uplink-share read caleb-test 111aaa) rm sj://caleb-test/111aaa/main.go
Error: uplink: permission denied (metainfo error: Unauthorized API credentials)

# Can't upload with a read-only grant:
$ uplink --access $(./uplink-share read caleb-test 111aaa) cp main.go sj://caleb-test/111aaa/main.go
13:48:15.866	WARN	Failed deleting object
	Bucket: caleb-test
	key: 111aaa/main.go
	error: metainfo error: Unauthorized API credentials
Error: uplink: permission denied (stream error: metainfo error: Unauthorized API credentials)
$ uplink --access $(./uplink-share read caleb-test 111aaa) cp main.go sj://caleb-test/111aaa/main.go.2
823 B / 823 B [------------------------------------------------------------------------------------------------------------------------------->] 100.00% ? p/s13:48:30.588	WARN	Failed deleting object
	Bucket: caleb-test
	key: 111aaa/main.go.2
	error: metainfo error: Unauthorized API credentials
Error: uplink: permission denied (stream error: metainfo error: Unauthorized API credentials)

# Can read with read-only grant:
$ uplink --access $(./uplink-share read caleb-test 111aaa) cat sj://caleb-test/111aaa/main.go | head
package main

import (
	"fmt"
	"os"
	"time"

	"storj.io/uplink"
)

I’ve go through read, write, and full and I don’t see any issues. I do however see that if for some reason your permission is empty string the grant will not have permissions to do anything. You may want to have a default case there.

Hmm… just saw this. So the code you used is the same as what I’m doing and it’s properly granting access to the prefix from what I see. I have no idea why for me it’s only working at the bucket level.