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