storj.io/uplink@v1.13.0/doc.go (about)

     1  // Copyright (C) 2020 Storj Labs, Inc.
     2  // See LICENSE for copying information.
     3  
     4  /*
     5  Package uplink is the main entrypoint to interacting with Storj Labs' decentralized
     6  storage network.
     7  
     8  Sign up for an account on a Satellite today! https://storj.io/
     9  
    10  # Access Grants
    11  
    12  The fundamental unit of access in the Storj Labs storage network is the Access Grant.
    13  An access grant is a serialized structure that is internally comprised of an API Key,
    14  a set of encryption key information, and information about which Storj Labs or
    15  Tardigrade network Satellite is responsible for the metadata. An access grant is
    16  always associated with exactly one Project on one Satellite.
    17  
    18  If you don't already have an access grant, you will need make an account on a
    19  Satellite, generate an API Key, and encapsulate that API Key with encryption
    20  information into an access grant.
    21  
    22  If you don't already have an account on a Satellite, first make one at
    23  https://storj.io/ and note the Satellite you choose (such as
    24  us1.storj.io, eu1.storj.io, etc). Then, make an API Key in the web interface.
    25  
    26  The first step to any project is to generate a restricted access grant with the
    27  minimal permissions that are needed. Access grants contains all encryption information
    28  and they should be restricted as much as possible.
    29  
    30  To make an access grant, you can create one using our Uplink CLI tool's 'share'
    31  subcommand (after setting up the Uplink CLI tool), or you can make one as follows:
    32  
    33  	access, err := uplink.RequestAccessWithPassphrase(ctx, satelliteAddress, apiKey, rootPassphrase)
    34  	if err != nil {
    35  	    return err
    36  	}
    37  
    38  	// create an access grant for reading bucket "logs"
    39  	permission := uplink.ReadOnlyPermission()
    40  	shared := uplink.SharePrefix{Bucket: "logs"}
    41  	restrictedAccess, err := access.Share(permission, shared)
    42  	if err != nil {
    43  	    return err
    44  	}
    45  
    46  	// serialize the restricted access grant
    47  	serializedAccess, err := restrictedAccess.Serialize()
    48  	if err != nil {
    49  	    return err
    50  	}
    51  
    52  In the above example, 'serializedAccess' is a human-readable string that represents
    53  read-only access to just the "logs" bucket, and is only able to decrypt that one
    54  bucket thanks to hierarchical deterministic key derivation.
    55  
    56  Note: RequestAccessWithPassphrase is CPU-intensive, and your application's normal
    57  lifecycle should avoid it and use ParseAccess where possible instead.
    58  
    59  To revoke an access grant see the Project.RevokeAccess method.
    60  
    61  # Multitenancy in a Single Application Bucket
    62  
    63  A common architecture for building applications is to have a single bucket for the
    64  entire application to store the objects of all users. In such architecture, it is
    65  of utmost importance to guarantee that users can access only their objects but not
    66  the objects of other users.
    67  
    68  This can be achieved by implementing an app-specific authentication service that
    69  generates an access grant for each user by restricting the main access grant of the
    70  application. This user-specific access grant is restricted to access the objects
    71  only within a specific key prefix defined for the user.
    72  
    73  When initialized, the authentication server creates the main application access
    74  grant with an empty passphrase as follows.
    75  
    76  	appAccess, err := uplink.RequestAccessWithPassphrase(ctx, satellite, appAPIKey, "")
    77  
    78  The authentication service does not hold any encryption information about users, so
    79  the passphrase used to request the main application access grant does not matter.
    80  The encryption keys related to user objects will be overridden in a next step on
    81  the client-side. It is important that once set to a specific value, this passphrase
    82  never changes in the future. Therefore, the best practice is to use an empty
    83  passphrase.
    84  
    85  Whenever a user is authenticated, the authentication service generates the
    86  user-specific access grant as follows:
    87  
    88  	// create a user access grant for accessing their files, limited for the next 8 hours
    89  	now := time.Now()
    90  	permission := uplink.FullPermission()
    91  	// 2 minutes leeway to avoid time sync issues with the satellite
    92  	permission.NotBefore = now.Add(-2 * time.Minute)
    93  	permission.NotAfter = now.Add(8 * time.Hour)
    94  	userPrefix := uplink.SharePrefix{
    95  	    Bucket: appBucket,
    96  	    Prefix: userID + "/",
    97  	}
    98  	userAccess, err := appAccess.Share(permission, userPrefix)
    99  	if err != nil {
   100  	    return err
   101  	}
   102  
   103  	// serialize the user access grant
   104  	serializedAccess, err := userAccess.Serialize()
   105  	if err != nil {
   106  	    return err
   107  	}
   108  
   109  The userID is something that uniquely identifies the users in the application
   110  and must never change.
   111  
   112  Along with the user access grant, the authentication service should return a
   113  user-specific salt. The salt must be always the same for this user. The salt size
   114  is 16-byte or 32-byte.
   115  
   116  Once the application receives the user-specific access grant and the user-specific
   117  salt from the authentication service, it has to override the encryption key in the
   118  access grant, so users can encrypt and decrypt their files with encryption keys
   119  derived from their passphrase.
   120  
   121  	userAccess, err = uplink.ParseAccess(serializedUserAccess)
   122  	if err != nil {
   123  	    return nil, err
   124  	}
   125  
   126  	saltedUserKey, err := uplink.DeriveEncryptionKey(userPassphrase, userSalt)
   127  	if err != nil {
   128  	    return nil, err
   129  	}
   130  
   131  	err = userAccess.OverrideEncryptionKey(appBucket, userID+"/", saltedUserKey)
   132  	if err != nil {
   133  	    return nil, err
   134  	}
   135  
   136  The user-specific access grant is now ready to use by the application.
   137  
   138  # Projects
   139  
   140  Once you have a valid access grant, you can open a Project with the access that
   141  access grant allows for.
   142  
   143  	project, err := uplink.OpenProject(ctx, access)
   144  	if err != nil {
   145  	    return err
   146  	}
   147  	defer project.Close()
   148  
   149  Projects allow you to manage buckets and objects within buckets.
   150  
   151  # Buckets
   152  
   153  A bucket represents a collection of objects. You can upload, download, list, and delete objects of
   154  any size or shape. Objects within buckets are represented by keys, where keys can optionally be
   155  listed using the "/" delimiter.
   156  
   157  Note: Objects and object keys within buckets are end-to-end encrypted, but bucket names
   158  themselves are not encrypted, so the billing interface on the Satellite can show you bucket line
   159  items.
   160  
   161  	buckets := project.ListBuckets(ctx, nil)
   162  	for buckets.Next() {
   163  	    fmt.Println(buckets.Item().Name)
   164  	}
   165  	if err := buckets.Err(); err != nil {
   166  	    return err
   167  	}
   168  
   169  # Download Object
   170  
   171  Objects support a couple kilobytes of arbitrary key/value metadata, and arbitrary-size primary
   172  data streams with the ability to read at arbitrary offsets.
   173  
   174  	object, err := project.DownloadObject(ctx, "logs", "2020-04-18/webserver.log", nil)
   175  	if err != nil {
   176  	    return err
   177  	}
   178  	defer object.Close()
   179  
   180  	_, err = io.Copy(w, object)
   181  	return err
   182  
   183  If you want to access only a small subrange of the data you uploaded, you can use
   184  `uplink.DownloadOptions` to specify the download range.
   185  
   186  	object, err := project.DownloadObject(ctx, "logs", "2020-04-18/webserver.log",
   187  	    &uplink.DownloadOptions{Offset: 10, Length: 100})
   188  	if err != nil {
   189  	    return err
   190  	}
   191  	defer object.Close()
   192  
   193  	_, err = io.Copy(w, object)
   194  	return err
   195  
   196  # List Objects
   197  
   198  Listing objects returns an iterator that allows to walk through all the items:
   199  
   200  	objects := project.ListObjects(ctx, "logs", nil)
   201  	for objects.Next() {
   202  	    item := objects.Item()
   203  	    fmt.Println(item.IsPrefix, item.Key)
   204  	}
   205  	if err := objects.Err(); err != nil {
   206  	    return err
   207  	}
   208  */
   209  package uplink