208 lines
6 KiB
Go
208 lines
6 KiB
Go
package azblob
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// BlobSASSignatureValues is used to generate a Shared Access Signature (SAS) for an Azure Storage container or blob.
|
|
// For more information, see https://docs.microsoft.com/rest/api/storageservices/constructing-a-service-sas
|
|
type BlobSASSignatureValues struct {
|
|
Version string `param:"sv"` // If not specified, this defaults to SASVersion
|
|
Protocol SASProtocol `param:"spr"` // See the SASProtocol* constants
|
|
StartTime time.Time `param:"st"` // Not specified if IsZero
|
|
ExpiryTime time.Time `param:"se"` // Not specified if IsZero
|
|
Permissions string `param:"sp"` // Create by initializing a ContainerSASPermissions or BlobSASPermissions and then call String()
|
|
IPRange IPRange `param:"sip"`
|
|
Identifier string `param:"si"`
|
|
ContainerName string
|
|
BlobName string // Use "" to create a Container SAS
|
|
CacheControl string // rscc
|
|
ContentDisposition string // rscd
|
|
ContentEncoding string // rsce
|
|
ContentLanguage string // rscl
|
|
ContentType string // rsct
|
|
}
|
|
|
|
// NewSASQueryParameters uses an account's shared key credential to sign this signature values to produce
|
|
// the proper SAS query parameters.
|
|
func (v BlobSASSignatureValues) NewSASQueryParameters(sharedKeyCredential *SharedKeyCredential) (SASQueryParameters, error) {
|
|
resource := "c"
|
|
if v.BlobName == "" {
|
|
// Make sure the permission characters are in the correct order
|
|
perms := &ContainerSASPermissions{}
|
|
if err := perms.Parse(v.Permissions); err != nil {
|
|
return SASQueryParameters{}, err
|
|
}
|
|
v.Permissions = perms.String()
|
|
} else {
|
|
resource = "b"
|
|
// Make sure the permission characters are in the correct order
|
|
perms := &BlobSASPermissions{}
|
|
if err := perms.Parse(v.Permissions); err != nil {
|
|
return SASQueryParameters{}, err
|
|
}
|
|
v.Permissions = perms.String()
|
|
}
|
|
if v.Version == "" {
|
|
v.Version = SASVersion
|
|
}
|
|
startTime, expiryTime := FormatTimesForSASSigning(v.StartTime, v.ExpiryTime)
|
|
|
|
// String to sign: http://msdn.microsoft.com/en-us/library/azure/dn140255.aspx
|
|
stringToSign := strings.Join([]string{
|
|
v.Permissions,
|
|
startTime,
|
|
expiryTime,
|
|
getCanonicalName(sharedKeyCredential.AccountName(), v.ContainerName, v.BlobName),
|
|
v.Identifier,
|
|
v.IPRange.String(),
|
|
string(v.Protocol),
|
|
v.Version,
|
|
v.CacheControl, // rscc
|
|
v.ContentDisposition, // rscd
|
|
v.ContentEncoding, // rsce
|
|
v.ContentLanguage, // rscl
|
|
v.ContentType}, // rsct
|
|
"\n")
|
|
signature := sharedKeyCredential.ComputeHMACSHA256(stringToSign)
|
|
|
|
p := SASQueryParameters{
|
|
// Common SAS parameters
|
|
version: v.Version,
|
|
protocol: v.Protocol,
|
|
startTime: v.StartTime,
|
|
expiryTime: v.ExpiryTime,
|
|
permissions: v.Permissions,
|
|
ipRange: v.IPRange,
|
|
|
|
// Container/Blob-specific SAS parameters
|
|
resource: resource,
|
|
identifier: v.Identifier,
|
|
cacheControl: v.CacheControl,
|
|
contentDisposition: v.ContentDisposition,
|
|
contentEncoding: v.ContentEncoding,
|
|
contentLanguage: v.ContentLanguage,
|
|
contentType: v.ContentType,
|
|
|
|
// Calculated SAS signature
|
|
signature: signature,
|
|
}
|
|
return p, nil
|
|
}
|
|
|
|
// getCanonicalName computes the canonical name for a container or blob resource for SAS signing.
|
|
func getCanonicalName(account string, containerName string, blobName string) string {
|
|
// Container: "/blob/account/containername"
|
|
// Blob: "/blob/account/containername/blobname"
|
|
elements := []string{"/blob/", account, "/", containerName}
|
|
if blobName != "" {
|
|
elements = append(elements, "/", strings.Replace(blobName, "\\", "/", -1))
|
|
}
|
|
return strings.Join(elements, "")
|
|
}
|
|
|
|
// The ContainerSASPermissions type simplifies creating the permissions string for an Azure Storage container SAS.
|
|
// Initialize an instance of this type and then call its String method to set BlobSASSignatureValues's Permissions field.
|
|
type ContainerSASPermissions struct {
|
|
Read, Add, Create, Write, Delete, List bool
|
|
}
|
|
|
|
// String produces the SAS permissions string for an Azure Storage container.
|
|
// Call this method to set BlobSASSignatureValues's Permissions field.
|
|
func (p ContainerSASPermissions) String() string {
|
|
var b bytes.Buffer
|
|
if p.Read {
|
|
b.WriteRune('r')
|
|
}
|
|
if p.Add {
|
|
b.WriteRune('a')
|
|
}
|
|
if p.Create {
|
|
b.WriteRune('c')
|
|
}
|
|
if p.Write {
|
|
b.WriteRune('w')
|
|
}
|
|
if p.Delete {
|
|
b.WriteRune('d')
|
|
}
|
|
if p.List {
|
|
b.WriteRune('l')
|
|
}
|
|
return b.String()
|
|
}
|
|
|
|
// Parse initializes the ContainerSASPermissions's fields from a string.
|
|
func (p *ContainerSASPermissions) Parse(s string) error {
|
|
*p = ContainerSASPermissions{} // Clear the flags
|
|
for _, r := range s {
|
|
switch r {
|
|
case 'r':
|
|
p.Read = true
|
|
case 'a':
|
|
p.Add = true
|
|
case 'c':
|
|
p.Create = true
|
|
case 'w':
|
|
p.Write = true
|
|
case 'd':
|
|
p.Delete = true
|
|
case 'l':
|
|
p.List = true
|
|
default:
|
|
return fmt.Errorf("Invalid permission: '%v'", r)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// The BlobSASPermissions type simplifies creating the permissions string for an Azure Storage blob SAS.
|
|
// Initialize an instance of this type and then call its String method to set BlobSASSignatureValues's Permissions field.
|
|
type BlobSASPermissions struct{ Read, Add, Create, Write, Delete bool }
|
|
|
|
// String produces the SAS permissions string for an Azure Storage blob.
|
|
// Call this method to set BlobSASSignatureValues's Permissions field.
|
|
func (p BlobSASPermissions) String() string {
|
|
var b bytes.Buffer
|
|
if p.Read {
|
|
b.WriteRune('r')
|
|
}
|
|
if p.Add {
|
|
b.WriteRune('a')
|
|
}
|
|
if p.Create {
|
|
b.WriteRune('c')
|
|
}
|
|
if p.Write {
|
|
b.WriteRune('w')
|
|
}
|
|
if p.Delete {
|
|
b.WriteRune('d')
|
|
}
|
|
return b.String()
|
|
}
|
|
|
|
// Parse initializes the BlobSASPermissions's fields from a string.
|
|
func (p *BlobSASPermissions) Parse(s string) error {
|
|
*p = BlobSASPermissions{} // Clear the flags
|
|
for _, r := range s {
|
|
switch r {
|
|
case 'r':
|
|
p.Read = true
|
|
case 'a':
|
|
p.Add = true
|
|
case 'c':
|
|
p.Create = true
|
|
case 'w':
|
|
p.Write = true
|
|
case 'd':
|
|
p.Delete = true
|
|
default:
|
|
return fmt.Errorf("Invalid permission: '%v'", r)
|
|
}
|
|
}
|
|
return nil
|
|
}
|