Update github.com/minio/minio-go

This commit is contained in:
Alexander Neumann 2017-06-08 19:40:06 +02:00
parent 1aab123b6c
commit a61016cb55
12 changed files with 133 additions and 24 deletions

2
vendor/manifest vendored
View File

@ -46,7 +46,7 @@
{ {
"importpath": "github.com/minio/minio-go", "importpath": "github.com/minio/minio-go",
"repository": "https://github.com/minio/minio-go", "repository": "https://github.com/minio/minio-go",
"revision": "85f15b007f08e11a62c769abe65299b812fd2e0d", "revision": "f2362d9e7d8daf89594ee0a079be2424eaf360be",
"branch": "master" "branch": "master"
}, },
{ {

View File

@ -28,9 +28,9 @@ import (
"github.com/minio/minio-go/pkg/encrypt" "github.com/minio/minio-go/pkg/encrypt"
) )
// GetEncryptedObject deciphers and streams data stored in the server after applying a specifed encryption materiels // GetEncryptedObject deciphers and streams data stored in the server after applying a specifed encryption materials,
func (c Client) GetEncryptedObject(bucketName, objectName string, encryptMaterials encrypt.Materials) (io.Reader, error) { // returned stream should be closed by the caller.
func (c Client) GetEncryptedObject(bucketName, objectName string, encryptMaterials encrypt.Materials) (io.ReadCloser, error) {
if encryptMaterials == nil { if encryptMaterials == nil {
return nil, ErrInvalidArgument("Unable to recognize empty encryption properties") return nil, ErrInvalidArgument("Unable to recognize empty encryption properties")
} }
@ -328,14 +328,14 @@ func (o *Object) setOffset(bytesRead int64) error {
// Update the currentOffset. // Update the currentOffset.
o.currOffset += bytesRead o.currOffset += bytesRead
if o.currOffset >= o.objectInfo.Size { if o.objectInfo.Size > -1 && o.currOffset >= o.objectInfo.Size {
return io.EOF return io.EOF
} }
return nil return nil
} }
// Read reads up to len(b) bytes into b. It returns the number of // Read reads up to len(b) bytes into b. It returns the number of
// bytes read (0 <= n <= len(p)) and any error encountered. Returns // bytes read (0 <= n <= len(b)) and any error encountered. Returns
// io.EOF upon end of file. // io.EOF upon end of file.
func (o *Object) Read(b []byte) (n int, err error) { func (o *Object) Read(b []byte) (n int, err error) {
if o == nil { if o == nil {
@ -442,7 +442,7 @@ func (o *Object) ReadAt(b []byte, offset int64) (n int, err error) {
if o.objectInfoSet { if o.objectInfoSet {
// If offset is negative than we return io.EOF. // If offset is negative than we return io.EOF.
// If offset is greater than or equal to object size we return io.EOF. // If offset is greater than or equal to object size we return io.EOF.
if offset >= o.objectInfo.Size || offset < 0 { if (o.objectInfo.Size > -1 && offset >= o.objectInfo.Size) || offset < 0 {
return 0, io.EOF return 0, io.EOF
} }
} }
@ -542,16 +542,20 @@ func (o *Object) Seek(offset int64, whence int) (n int64, err error) {
default: default:
return 0, ErrInvalidArgument(fmt.Sprintf("Invalid whence %d", whence)) return 0, ErrInvalidArgument(fmt.Sprintf("Invalid whence %d", whence))
case 0: case 0:
if offset > o.objectInfo.Size { if o.objectInfo.Size > -1 && offset > o.objectInfo.Size {
return 0, io.EOF return 0, io.EOF
} }
o.currOffset = offset o.currOffset = offset
case 1: case 1:
if o.currOffset+offset > o.objectInfo.Size { if o.objectInfo.Size > -1 && o.currOffset+offset > o.objectInfo.Size {
return 0, io.EOF return 0, io.EOF
} }
o.currOffset += offset o.currOffset += offset
case 2: case 2:
// If we don't know the object size return an error for io.SeekEnd
if o.objectInfo.Size < 0 {
return 0, ErrInvalidArgument("Whence END is not supported when the object size is unknown")
}
// Seeking to positive offset is valid for whence '2', but // Seeking to positive offset is valid for whence '2', but
// since we are backing a Reader we have reached 'EOF' if // since we are backing a Reader we have reached 'EOF' if
// offset is positive. // offset is positive.

View File

@ -21,8 +21,6 @@ import (
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/minio/minio-go/pkg/s3utils"
) )
// BucketExists verify if bucket exists and you have permission to access it. // BucketExists verify if bucket exists and you have permission to access it.
@ -126,12 +124,13 @@ func (c Client) statObject(bucketName, objectName string, reqHeaders RequestHead
md5sum := strings.TrimPrefix(resp.Header.Get("ETag"), "\"") md5sum := strings.TrimPrefix(resp.Header.Get("ETag"), "\"")
md5sum = strings.TrimSuffix(md5sum, "\"") md5sum = strings.TrimSuffix(md5sum, "\"")
// Content-Length is not valid for Google Cloud Storage, do not verify. // Parse content length is exists
var size int64 = -1 var size int64 = -1
if !s3utils.IsGoogleEndpoint(c.endpointURL) { contentLengthStr := resp.Header.Get("Content-Length")
// Parse content length. if contentLengthStr != "" {
size, err = strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 64) size, err = strconv.ParseInt(contentLengthStr, 10, 64)
if err != nil { if err != nil {
// Content-Length is not valid
return ObjectInfo{}, ErrorResponse{ return ObjectInfo{}, ErrorResponse{
Code: "InternalError", Code: "InternalError",
Message: "Content-Length is invalid. " + reportIssue, Message: "Content-Length is invalid. " + reportIssue,

View File

@ -1962,6 +1962,7 @@ func TestEncryptionPutGet(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Test %d, error: %v %v %v", i+1, err, bucketName, objectName) t.Fatalf("Test %d, error: %v %v %v", i+1, err, bucketName, objectName)
} }
defer r.Close()
// Compare the sent object with the received one // Compare the sent object with the received one
recvBuffer := bytes.NewBuffer([]byte{}) recvBuffer := bytes.NewBuffer([]byte{})

View File

@ -771,7 +771,7 @@ if err != nil {
``` ```
<a name="GetEncryptedObject"></a> <a name="GetEncryptedObject"></a>
### GetEncryptedObject(bucketName, objectName string, encryptMaterials minio.EncryptionMaterials) (io.Reader, error) ### GetEncryptedObject(bucketName, objectName string, encryptMaterials minio.EncryptionMaterials) (io.ReadCloser, error)
Returns the decrypted stream of the object data based of the given encryption materiels. Most of the common errors occur when reading the stream. Returns the decrypted stream of the object data based of the given encryption materiels. Most of the common errors occur when reading the stream.
@ -788,7 +788,7 @@ __Return Value__
|Param |Type |Description | |Param |Type |Description |
|:---|:---| :---| |:---|:---| :---|
|`stream` | _io.Reader_ | Returns the deciphered object reader. | |`stream` | _io.ReadCloser_ | Returns the deciphered object reader, caller should close after reading. |
|`err` | _error | Returns errors. | |`err` | _error | Returns errors. |
@ -810,11 +810,14 @@ if err != nil {
fmt.Println(err) fmt.Println(err)
return return
} }
defer object.Close()
localFile, err := os.Create("/tmp/local-file.jpg") localFile, err := os.Create("/tmp/local-file.jpg")
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
} }
if _, err = io.Copy(localFile, object); err != nil { if _, err = io.Copy(localFile, object); err != nil {
fmt.Println(err) fmt.Println(err)
return return

View File

@ -24,6 +24,7 @@ import (
"os" "os"
"github.com/minio/minio-go" "github.com/minio/minio-go"
"github.com/minio/minio-go/pkg/encrypt"
) )
func main() { func main() {
@ -59,10 +60,10 @@ func main() {
//// ////
// Build a symmetric key // Build a symmetric key
symmetricKey := minio.NewSymmetricKey([]byte("my-secret-key-00")) symmetricKey := encrypt.NewSymmetricKey([]byte("my-secret-key-00"))
// Build encryption materials which will encrypt uploaded data // Build encryption materials which will encrypt uploaded data
cbcMaterials, err := minio.NewCBCSecureMaterials(symmetricKey) cbcMaterials, err := encrypt.NewCBCSecureMaterials(symmetricKey)
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
@ -72,6 +73,7 @@ func main() {
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
defer reader.Close()
// Local file which holds plain data // Local file which holds plain data
localFile, err := os.Create("my-testfile") localFile, err := os.Create("my-testfile")

View File

@ -23,6 +23,7 @@ import (
"os" "os"
"github.com/minio/minio-go" "github.com/minio/minio-go"
"github.com/minio/minio-go/pkg/encrypt"
) )
func main() { func main() {
@ -65,10 +66,10 @@ func main() {
//// ////
// Build a symmetric key // Build a symmetric key
symmetricKey := minio.NewSymmetricKey([]byte("my-secret-key-00")) symmetricKey := encrypt.NewSymmetricKey([]byte("my-secret-key-00"))
// Build encryption materials which will encrypt uploaded data // Build encryption materials which will encrypt uploaded data
cbcMaterials, err := minio.NewCBCSecureMaterials(symmetricKey) cbcMaterials, err := encrypt.NewCBCSecureMaterials(symmetricKey)
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }

View File

@ -0,0 +1,87 @@
// +build ignore
/*
* Minio Go Library for Amazon S3 Compatible Cloud Storage (C) 2017 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main
import (
"bytes"
"crypto/md5"
"encoding/base64"
"io/ioutil"
"log"
"net/http"
minio "github.com/minio/minio-go"
)
func main() {
// Note: YOUR-ACCESSKEYID, YOUR-SECRETACCESSKEY, my-testfile, my-bucketname and
// my-objectname are dummy values, please replace them with original values.
// New returns an Amazon S3 compatible client object. API compatibility (v2 or v4) is automatically
// determined based on the Endpoint value.
minioClient, err := minio.New("s3.amazonaws.com", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY", true)
if err != nil {
log.Fatalln(err)
}
content := bytes.NewReader([]byte("Hello again"))
key := []byte("32byteslongsecretkeymustprovided")
h := md5.New()
h.Write(key)
encryptionKey := base64.StdEncoding.EncodeToString(key)
encryptionKeyMD5 := base64.StdEncoding.EncodeToString(h.Sum(nil))
// Amazon S3 does not store the encryption key you provide.
// Instead S3 stores a randomly salted HMAC value of the
// encryption key in order to validate future requests.
// The salted HMAC value cannot be used to derive the value
// of the encryption key or to decrypt the contents of the
// encrypted object. That means, if you lose the encryption
// key, you lose the object.
var metadata = map[string][]string{
"x-amz-server-side-encryption-customer-algorithm": []string{"AES256"},
"x-amz-server-side-encryption-customer-key": []string{encryptionKey},
"x-amz-server-side-encryption-customer-key-MD5": []string{encryptionKeyMD5},
}
// minioClient.TraceOn(os.Stderr) // Enable to debug.
_, err = minioClient.PutObjectWithMetadata("mybucket", "my-encrypted-object.txt", content, metadata, nil)
if err != nil {
log.Fatalln(err)
}
var reqHeaders = minio.RequestHeaders{Header: http.Header{}}
for k, v := range metadata {
reqHeaders.Set(k, v[0])
}
coreClient := minio.Core{minioClient}
reader, _, err := coreClient.GetObject("mybucket", "my-encrypted-object.txt", reqHeaders)
if err != nil {
log.Fatalln(err)
}
defer reader.Close()
decBytes, err := ioutil.ReadAll(reader)
if err != nil {
log.Fatalln(err)
}
if !bytes.Equal(decBytes, []byte("Hello again")) {
log.Fatalln("Expected \"Hello, world\", got %s", string(decBytes))
}
}

View File

@ -89,6 +89,15 @@ func NewCBCSecureMaterials(key Key) (*CBCSecureMaterials, error) {
} }
// Close implements closes the internal stream.
func (s *CBCSecureMaterials) Close() error {
closer, ok := s.stream.(io.Closer)
if ok {
return closer.Close()
}
return nil
}
// SetupEncryptMode - tells CBC that we are going to encrypt data // SetupEncryptMode - tells CBC that we are going to encrypt data
func (s *CBCSecureMaterials) SetupEncryptMode(stream io.Reader) error { func (s *CBCSecureMaterials) SetupEncryptMode(stream io.Reader) error {
// Set mode to encrypt // Set mode to encrypt

View File

@ -25,6 +25,9 @@ import "io"
// Materials - provides generic interface to encrypt any stream of data. // Materials - provides generic interface to encrypt any stream of data.
type Materials interface { type Materials interface {
// Closes the wrapped stream properly, initiated by the caller.
Close() error
// Returns encrypted/decrypted data, io.Reader compatible. // Returns encrypted/decrypted data, io.Reader compatible.
Read(b []byte) (int, error) Read(b []byte) (int, error)

View File

@ -48,7 +48,7 @@ func (c RequestHeaders) SetMatchETag(etag string) error {
if etag == "" { if etag == "" {
return ErrInvalidArgument("ETag cannot be empty.") return ErrInvalidArgument("ETag cannot be empty.")
} }
c.Set("If-Match", etag) c.Set("If-Match", "\""+etag+"\"")
return nil return nil
} }
@ -57,7 +57,7 @@ func (c RequestHeaders) SetMatchETagExcept(etag string) error {
if etag == "" { if etag == "" {
return ErrInvalidArgument("ETag cannot be empty.") return ErrInvalidArgument("ETag cannot be empty.")
} }
c.Set("If-None-Match", etag) c.Set("If-None-Match", "\""+etag+"\"")
return nil return nil
} }

View File

@ -25,7 +25,7 @@ var s3ErrorResponseMap = map[string]string{
"EntityTooLarge": "Your proposed upload exceeds the maximum allowed object size.", "EntityTooLarge": "Your proposed upload exceeds the maximum allowed object size.",
"IncompleteBody": "You did not provide the number of bytes specified by the Content-Length HTTP header.", "IncompleteBody": "You did not provide the number of bytes specified by the Content-Length HTTP header.",
"InternalError": "We encountered an internal error, please try again.", "InternalError": "We encountered an internal error, please try again.",
"InvalidAccessKeyID": "The access key ID you provided does not exist in our records.", "InvalidAccessKeyId": "The access key ID you provided does not exist in our records.",
"InvalidBucketName": "The specified bucket is not valid.", "InvalidBucketName": "The specified bucket is not valid.",
"InvalidDigest": "The Content-Md5 you specified is not valid.", "InvalidDigest": "The Content-Md5 you specified is not valid.",
"InvalidRange": "The requested range is not satisfiable", "InvalidRange": "The requested range is not satisfiable",