diff --git a/google-cloud-examples/src/main/java/com/google/cloud/examples/storage/snippets/StorageSnippets.java b/google-cloud-examples/src/main/java/com/google/cloud/examples/storage/snippets/StorageSnippets.java index a151f94d5a5e..e0b78afc9292 100644 --- a/google-cloud-examples/src/main/java/com/google/cloud/examples/storage/snippets/StorageSnippets.java +++ b/google-cloud-examples/src/main/java/com/google/cloud/examples/storage/snippets/StorageSnippets.java @@ -44,6 +44,7 @@ import com.google.cloud.storage.Storage.BlobListOption; import com.google.cloud.storage.Storage.BlobSourceOption; import com.google.cloud.storage.Storage.BlobTargetOption; +import com.google.cloud.storage.Storage.BlobWriteOption; import com.google.cloud.storage.Storage.BucketGetOption; import com.google.cloud.storage.Storage.BucketListOption; import com.google.cloud.storage.Storage.BucketSourceOption; @@ -153,6 +154,26 @@ public Blob createBlobFromInputStream(String bucketName, String blobName) { return blob; } + /** + * Example of uploading an encrypted blob. + */ + // [TARGET create(BlobInfo, InputStream, BlobWriteOption...)] + // [VARIABLE "my_unique_bucket"] + // [VARIABLE "my_blob_name"] + // [VARIABLE "my_encryption_key"] + public Blob createEncryptedBlob(String bucketName, String blobName, String encryptionKey) { + // [START storageUploadEncryptedFile] + InputStream content = new ByteArrayInputStream("Hello, World!".getBytes(UTF_8)); + + BlobId blobId = BlobId.of(bucketName, blobName); + BlobInfo blobInfo = BlobInfo.newBuilder(blobId) + .setContentType("text/plain") + .build(); + Blob blob = storage.create(blobInfo, content, BlobWriteOption.encryptionKey(encryptionKey)); + // [END storageUploadEncryptedFile] + return blob; + } + /** * Example of getting information on a bucket, only if its metageneration matches a value, * otherwise a {@link StorageException} is thrown. @@ -446,6 +467,28 @@ public Blob copyBlobInChunks(String bucketName, String blobName, String copyBlob return blob; } + /** + * Example of rotating the encryption key of a blob. + */ + // [TARGET copy(CopyRequest)] + // [VARIABLE "my_unique_bucket"] + // [VARIABLE "my_blob_name"] + // [VARIABLE "old_encryption_key"] + // [VARIABLE "new_encryption_key"] + public Blob rotateBlobEncryptionKey( + String bucketName, String blobName, String oldEncryptionKey, String newEncryptionKey) { + // [START storageRotateEncryptionKey] + BlobId blobId = BlobId.of(bucketName, blobName); + CopyRequest request = CopyRequest.newBuilder() + .setSource(blobId) + .setSourceOptions(BlobSourceOption.decryptionKey(oldEncryptionKey)) + .setTarget(blobId, BlobTargetOption.encryptionKey(newEncryptionKey)) + .build(); + Blob blob = storage.copy(request).getResult(); + // [END storageRotateEncryptionKey] + return blob; + } + /** * Example of reading all bytes of a blob, if generation matches a value, otherwise a * {@link StorageException} is thrown. @@ -470,7 +513,7 @@ public byte[] readBlobFromStringsWithGeneration(String bucketName, String blobNa // [TARGET readAllBytes(BlobId, BlobSourceOption...)] // [VARIABLE "my_unique_bucket"] // [VARIABLE "my_blob_name"] - // [VARIABLE 42"] + // [VARIABLE 42] public byte[] readBlobFromId(String bucketName, String blobName, long blobGeneration) { // [START readBlobFromId] BlobId blobId = BlobId.of(bucketName, blobName, blobGeneration); @@ -479,6 +522,21 @@ public byte[] readBlobFromId(String bucketName, String blobName, long blobGenera return content; } + /** + * Example of reading all bytes of an encrypted blob. + */ + // [TARGET readAllBytes(BlobId, BlobSourceOption...)] + // [VARIABLE "my_unique_bucket"] + // [VARIABLE "my_blob_name"] + // [VARIABLE "my_encryption_key"] + public byte[] readEncryptedBlob(String bucketName, String blobName, String decryptionKey) { + // [START readEncryptedBlob] + byte[] content = storage.readAllBytes( + bucketName, blobName, BlobSourceOption.decryptionKey(decryptionKey)); + // [END readEncryptedBlob] + return content; + } + /** * Example of using a batch request to delete, update and get a blob. */ diff --git a/google-cloud-examples/src/test/java/com/google/cloud/examples/storage/snippets/ITStorageSnippets.java b/google-cloud-examples/src/test/java/com/google/cloud/examples/storage/snippets/ITStorageSnippets.java index 21c0821c0cbc..c81f3ada51b0 100644 --- a/google-cloud-examples/src/test/java/com/google/cloud/examples/storage/snippets/ITStorageSnippets.java +++ b/google-cloud-examples/src/test/java/com/google/cloud/examples/storage/snippets/ITStorageSnippets.java @@ -145,6 +145,34 @@ public void testBlob() throws InterruptedException { copiedBlob.delete(); } + @Test + public void testCreateUpdateEncryptedBlob() throws InterruptedException { + // Note: DO NOT put your encryption key in your code, like it is here. Store it somewhere safe, + // and read it in when you need it. This key is just here to make the code easier to read. + String encryptionKey1 = "0mMWhFvQOdS4AmxRpo8SJxXn5MjFhbz7DkKBUdUIef8="; + String blobName = "encrypted-blob"; + + Blob blob = storageSnippets.createEncryptedBlob(BUCKET, blobName, encryptionKey1); + + assertNotNull(blob); + assertEquals("text/plain", blob.getContentType()); + byte[] encryptedContent = storageSnippets.readEncryptedBlob(BUCKET, blobName, encryptionKey1); + assertEquals("Hello, World!", new String(encryptedContent)); + blob = storageSnippets.getBlobFromId(BUCKET, blobName); + assertEquals("text/plain", blob.getContentType()); + + String encryptionKey2 = "wnxMO0w+dmxribu7rICJ+Q2ES9TLpFRIDy3/L7HN5ZA="; + + blob = storageSnippets.rotateBlobEncryptionKey( + BUCKET, blobName, encryptionKey1, encryptionKey2); + + assertNotNull(blob); + encryptedContent = storageSnippets.readEncryptedBlob(BUCKET, blobName, encryptionKey2); + assertEquals("Hello, World!", new String(encryptedContent)); + blob = storageSnippets.getBlobFromId(BUCKET, blobName); + assertEquals("text/plain", blob.getContentType()); + } + @Test public void testCreateCopyAndGetBlob() { String blobName = "test-create-copy-get-blob"; diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java index 6e70e75008d3..021270c364b6 100644 --- a/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java @@ -1216,6 +1216,19 @@ public Builder target(BlobInfo target, BlobTargetOption... options) { return setTarget(target, options); } + /** + * Sets the copy target. Target blob information is copied from source, except for those + * options specified in {@code options}. + * + * @return the builder + */ + public Builder setTarget(BlobId targetId, BlobTargetOption... options) { + this.overrideInfo = false; + this.target = BlobInfo.newBuilder(targetId).build(); + Collections.addAll(targetOptions, options); + return this; + } + /** * Sets the copy target and target options. {@code target} parameter is used to override * source blob information (e.g. {@code contentType}, {@code contentLanguage}). Target blob @@ -1259,6 +1272,19 @@ public Builder setTarget(BlobInfo target, Iterable options) { return this; } + /** + * Sets the copy target and target options. Target blob information is copied from source, + * except for those options specified in {@code options}. + * + * @return the builder + */ + public Builder setTarget(BlobId targetId, Iterable options) { + this.overrideInfo = false; + this.target = BlobInfo.newBuilder(targetId).build(); + Iterables.addAll(targetOptions, options); + return this; + } + /** * Sets the maximum number of megabytes to copy for each RPC call. This parameter is ignored * if source and target blob share the same location and storage class as copy is made with @@ -1566,6 +1592,20 @@ public static Builder newBuilder() { * Blob blob = storage.create(blobInfo, content); * } * + *

Example of uploading an encrypted blob. + *

 {@code
+   * String bucketName = "my_unique_bucket";
+   * String blobName = "my_blob_name";
+   * String encryptionKey = "my_encryption_key";
+   * InputStream content = new ByteArrayInputStream("Hello, World!".getBytes(UTF_8));
+   * 
+   * BlobId blobId = BlobId.of(bucketName, blobName);
+   * BlobInfo blobInfo = BlobInfo.newBuilder(blobId)
+   *     .setContentType("text/plain")
+   *     .build();
+   * Blob blob = storage.create(blobInfo, content, BlobWriteOption.encryptionKey(encryptionKey));
+   * }
+ * * @return a [@code Blob} with complete information * @throws StorageException upon failure */ @@ -1888,6 +1928,21 @@ public static Builder newBuilder() { * Blob blob = copyWriter.getResult(); * } * + *

Example of rotating the encryption key of a blob. + *

 {@code
+   * String bucketName = "my_unique_bucket";
+   * String blobName = "my_blob_name";
+   * String oldEncryptionKey = "old_encryption_key";
+   * String newEncryptionKey = "new_encryption_key";
+   * BlobId blobId = BlobId.of(bucketName, blobName);
+   * CopyRequest request = CopyRequest.newBuilder()
+   *     .setSource(blobId)
+   *     .setSourceOptions(BlobSourceOption.decryptionKey(oldEncryptionKey))
+   *     .setTarget(blobId, BlobTargetOption.encryptionKey(newEncryptionKey))
+   *     .build();
+   * Blob blob = storage.copy(request).getResult();
+   * }
+ * * @return a {@link CopyWriter} object that can be used to get information on the newly created * blob or to complete the copy if more than one RPC request is needed * @throws StorageException upon failure @@ -1921,11 +1976,20 @@ public static Builder newBuilder() { *
 {@code
    * String bucketName = "my_unique_bucket";
    * String blobName = "my_blob_name";
-   * long blobGeneration = 42";
+   * long blobGeneration = 42;
    * BlobId blobId = BlobId.of(bucketName, blobName, blobGeneration);
    * byte[] content = storage.readAllBytes(blobId);
    * }
* + *

Example of reading all bytes of an encrypted blob. + *

 {@code
+   * String bucketName = "my_unique_bucket";
+   * String blobName = "my_blob_name";
+   * String decryptionKey = "my_encryption_key";
+   * byte[] content = storage.readAllBytes(
+   *     bucketName, blobName, BlobSourceOption.decryptionKey(decryptionKey));
+   * }
+ * * @return the blob's content * @throws StorageException upon failure */