storj.io/uplink@v1.13.0/examples/walkthrough/main.go (about)

     1  // Copyright (C) 2020 Storj Labs, Inc.
     2  // See LICENSE for copying information.
     3  
     4  package main
     5  
     6  import (
     7  	"bytes"
     8  	"context"
     9  	"flag"
    10  	"fmt"
    11  	"io"
    12  	"os"
    13  	"time"
    14  
    15  	"storj.io/uplink"
    16  	"storj.io/uplink/edge"
    17  )
    18  
    19  const defaultExpiration = 7 * 24 * time.Hour
    20  
    21  // UploadAndDownloadData uploads the specified data to the specified key in the
    22  // specified bucket, using the specified Satellite, API key, and passphrase.
    23  func UploadAndDownloadData(ctx context.Context,
    24  	accessGrant, bucketName, uploadKey string, dataToUpload []byte) error {
    25  
    26  	// Parse access grant, which contains necessary credentials and permissions.
    27  	access, err := uplink.ParseAccess(accessGrant)
    28  	if err != nil {
    29  		return fmt.Errorf("could not request access grant: %v", err)
    30  	}
    31  
    32  	// Open up the Project we will be working with.
    33  	project, err := uplink.OpenProject(ctx, access)
    34  	if err != nil {
    35  		return fmt.Errorf("could not open project: %v", err)
    36  	}
    37  	defer project.Close()
    38  
    39  	// Ensure the desired Bucket within the Project is created.
    40  	_, err = project.EnsureBucket(ctx, bucketName)
    41  	if err != nil {
    42  		return fmt.Errorf("could not ensure bucket: %v", err)
    43  	}
    44  
    45  	// Intitiate the upload of our Object to the specified bucket and key.
    46  	upload, err := project.UploadObject(ctx, bucketName, uploadKey, &uplink.UploadOptions{
    47  		// It's possible to set an expiration date for data.
    48  		Expires: time.Now().Add(defaultExpiration),
    49  	})
    50  	if err != nil {
    51  		return fmt.Errorf("could not initiate upload: %v", err)
    52  	}
    53  
    54  	// Copy the data to the upload.
    55  	buf := bytes.NewBuffer(dataToUpload)
    56  	_, err = io.Copy(upload, buf)
    57  	if err != nil {
    58  		_ = upload.Abort()
    59  		return fmt.Errorf("could not upload data: %v", err)
    60  	}
    61  
    62  	// Commit the uploaded object.
    63  	err = upload.Commit()
    64  	if err != nil {
    65  		return fmt.Errorf("could not commit uploaded object: %v", err)
    66  	}
    67  
    68  	// Initiate a download of the same object again
    69  	download, err := project.DownloadObject(ctx, bucketName, uploadKey, nil)
    70  	if err != nil {
    71  		return fmt.Errorf("could not open object: %v", err)
    72  	}
    73  	defer download.Close()
    74  
    75  	// Read everything from the download stream
    76  	receivedContents, err := io.ReadAll(download)
    77  	if err != nil {
    78  		return fmt.Errorf("could not read data: %v", err)
    79  	}
    80  
    81  	// Check that the downloaded data is the same as the uploaded data.
    82  	if !bytes.Equal(receivedContents, dataToUpload) {
    83  		return fmt.Errorf("got different object back: %q != %q", dataToUpload, receivedContents)
    84  	}
    85  
    86  	return nil
    87  }
    88  
    89  func CreatePublicSharedLink(ctx context.Context, accessGrant, bucketName, objectKey string) (string, error) {
    90  	// Define configuration for the storj sharing site.
    91  	config := edge.Config{
    92  		AuthServiceAddress: "auth.storjshare.io:7777",
    93  	}
    94  
    95  	// Parse access grant, which contains necessary credentials and permissions.
    96  	access, err := uplink.ParseAccess(accessGrant)
    97  	if err != nil {
    98  		return "", fmt.Errorf("could not parse access grant: %w", err)
    99  	}
   100  
   101  	// Restrict access to the specified paths.
   102  	restrictedAccess, err := access.Share(
   103  		uplink.Permission{
   104  			// only allow downloads
   105  			AllowDownload: true,
   106  			// this allows to automatically cleanup the access grants
   107  			NotAfter: time.Now().Add(defaultExpiration),
   108  		}, uplink.SharePrefix{
   109  			Bucket: bucketName,
   110  			Prefix: objectKey,
   111  		})
   112  	if err != nil {
   113  		return "", fmt.Errorf("could not restrict access grant: %w", err)
   114  	}
   115  
   116  	// RegisterAccess registers the credentials to the linksharing and s3 sites.
   117  	// This makes the data publicly accessible, see the security implications in https://docs.storj.io/dcs/concepts/access/access-management-at-the-edge.
   118  	credentials, err := config.RegisterAccess(ctx, restrictedAccess, &edge.RegisterAccessOptions{Public: true})
   119  	if err != nil {
   120  		return "", fmt.Errorf("could not register access: %w", err)
   121  	}
   122  
   123  	// Create a public link that is served by linksharing service.
   124  	url, err := edge.JoinShareURL("https://link.storjshare.io", credentials.AccessKeyID, bucketName, objectKey, nil)
   125  	if err != nil {
   126  		return "", fmt.Errorf("could not create a shared link: %w", err)
   127  	}
   128  
   129  	return url, nil
   130  }
   131  
   132  func main() {
   133  	ctx := context.Background()
   134  	accessGrant := flag.String("access", os.Getenv("ACCESS_GRANT"), "access grant from satellite")
   135  	flag.Parse()
   136  
   137  	bucketName := "my-first-bucket"
   138  	objectKey := "foo/bar/baz"
   139  
   140  	err := UploadAndDownloadData(ctx, *accessGrant, bucketName, objectKey, []byte("one fish two fish red fish blue fish"))
   141  	if err != nil {
   142  		fmt.Fprintln(os.Stderr, "upload failed:", err)
   143  		os.Exit(1)
   144  	}
   145  
   146  	url, err := CreatePublicSharedLink(ctx, *accessGrant, bucketName, objectKey)
   147  	if err != nil {
   148  		fmt.Fprintln(os.Stderr, "creating public link failed:", err)
   149  		os.Exit(1)
   150  	}
   151  
   152  	fmt.Println("success!")
   153  	fmt.Println("public link:", url)
   154  }