Skip to content

Commit

Permalink
Merge pull request #3 from matthewhartstonge/bugfix/consistency
Browse files Browse the repository at this point in the history
Bugfix/api-consistency
  • Loading branch information
matthewhartstonge authored Oct 20, 2021
2 parents 7bce86b + 4916f91 commit 6b0b752
Show file tree
Hide file tree
Showing 11 changed files with 250 additions and 195 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func main() {
// signedVersion specifies what API version to use in order to generate
// the storage SAS token - must be set to version 2015-04-05 or later.
// Current valid versions can be found in `storage/versions/versions.go`
versions.Latest.ToString(),
versions.Latest.String(),
// signedServices supports:
// Blob = "b"
// Queue = "q"
Expand Down
2 changes: 2 additions & 0 deletions storage/aztime/aztime.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
// Standard Library Imports
"errors"
"net/url"
"strings"
"time"
)

Expand All @@ -35,6 +36,7 @@ var (
// ParseISO8601DateTime provides a much more CLI user-friendly time parser which
// attempts to parse from least-to-greatest precision, failing if it .
func ParseISO8601DateTime(dateTime string) (t time.Time, err error) {
dateTime = strings.TrimSpace(dateTime)
if dateTime == "" {
return time.Time{}, ErrDateTimeEmpty
}
Expand Down
19 changes: 10 additions & 9 deletions storage/signedip/signed_ip.go → storage/ips/ips.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package signedip
package ips

import (
// Standard Library Imports
Expand All @@ -32,20 +32,21 @@ const (

type SignedIP string

func (p SignedIP) ToString() string {
return string(p)
// String implements Stringer.
func (s SignedIP) String() string {
return string(s)
}

func (p SignedIP) SetParam(params *url.Values) {
if p != "" {
params.Add(paramKey, p.ToString())
func (s SignedIP) SetParam(params *url.Values) {
if s != "" {
params.Add(paramKey, s.String())
}
}

func (p SignedIP) GetParam() (signedIPs string) {
if p != "" {
func (s SignedIP) GetParam() (signedIPs string) {
if s != "" {
values := &url.Values{}
p.SetParam(values)
s.SetParam(values)

signedIPs = values.Encode()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package signedip
package ips

import (
"testing"
Expand Down
141 changes: 86 additions & 55 deletions storage/permissions/permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,29 @@ const (
paramKey = "sp"
)

type SignedPermission string

// String implements Stringer.
func (s SignedPermission) String() string {
return string(s)
}

const (
Read SignedPermission = "r"
Add SignedPermission = "a"
Create SignedPermission = "c"
Write SignedPermission = "w"
Delete SignedPermission = "d"
DeleteVersion SignedPermission = "x"
PermanentDelete SignedPermission = "y"
List SignedPermission = "l"
Tags SignedPermission = "t"
Move SignedPermission = "m"
Execute SignedPermission = "e"
Ownership SignedPermission = "o"
Permissions SignedPermission = "p"
)

type SignedPermissions struct {
// in order to return/parse the correct permissions, we need to know the
// API version in use.
Expand All @@ -40,43 +63,43 @@ type SignedPermissions struct {
// permissions must be in the following order to comply to azure
// specifications: "racwdxyltmeop"
// Refer: https://docs.microsoft.com/en-us/rest/api/storageservices/create-service-sas#specifying-permissions
permissions [numPermissions]string
permissions [numPermissions]SignedPermission
}

func (p SignedPermissions) ToString() string {
func (s SignedPermissions) String() string {
var out []string
spMap := signedPermissionMap()
for _, value := range p.permissions {
if spec, ok := spMap[value]; ok {
if spec.APIVersion == versions.VAll || spec.APIVersion <= p.SignedVersion {
out = append(out, value)
for _, permission := range s.permissions {
if spec, ok := spMap[permission]; ok {
if spec.APIVersion == versions.VAll || spec.APIVersion <= s.SignedVersion {
out = append(out, permission.String())
}
}
}

return strings.Join(out, "")
}

func (p SignedPermissions) SetParam(params *url.Values) {
if p.hasValues {
params.Add(paramKey, p.ToString())
func (s SignedPermissions) SetParam(params *url.Values) {
if s.hasValues {
params.Add(paramKey, s.String())
}
}

func (p SignedPermissions) GetParam() (signedPermissions string) {
if p.hasValues {
func (s SignedPermissions) GetParam() (signedPermissions string) {
if s.hasValues {
values := &url.Values{}
p.SetParam(values)
s.SetParam(values)

signedPermissions = values.Encode()
}

return
}

func (p SignedPermissions) GetURLDecodedParam() (signedPermissions string) {
if p.hasValues {
signedPermissions, _ = url.QueryUnescape(p.GetParam())
func (s SignedPermissions) GetURLDecodedParam() (signedPermissions string) {
if s.hasValues {
signedPermissions, _ = url.QueryUnescape(s.GetParam())
}

return
Expand All @@ -85,17 +108,17 @@ func (p SignedPermissions) GetURLDecodedParam() (signedPermissions string) {
func Parse(version versions.SignedVersion, permissions string) (sp SignedPermissions) {
sp = SignedPermissions{
hasValues: false,
permissions: [numPermissions]string{},
permissions: [numPermissions]SignedPermission{},

SignedVersion: version,
}

spMap := signedPermissionMap()
splitPermissions := strings.Split(permissions, "")
splitPermissions := strings.Split(strings.ToLower(strings.TrimSpace(permissions)), "")
for _, permission := range splitPermissions {
conformedPermission := strings.ToLower(permission)
if spec, ok := spMap[conformedPermission]; ok {
sp.permissions[spec.Index] = conformedPermission
signedPermission := SignedPermission(permission)
if spec, ok := spMap[signedPermission]; ok {
sp.permissions[spec.Index] = signedPermission
if !sp.hasValues {
sp.hasValues = true
}
Expand All @@ -112,86 +135,94 @@ type signedPermissionSpec struct {
APIVersion versions.SignedVersion
}

func signedPermissionMap() map[string]signedPermissionSpec {
func signedPermissionMap() map[SignedPermission]signedPermissionSpec {
// nextIndex provides an index generating closure, so we don't have to
// manually track indices in the map.
i := -1
nextIndex := func() int {
i++
return i
}

// Refer: https://docs.microsoft.com/en-us/rest/api/storageservices/create-service-sas#permissions-for-a-directory-container-or-blob
return map[string]signedPermissionSpec{
"r": {
return map[SignedPermission]signedPermissionSpec{
Read: {
OpName: "Read",
OpDescription: "Read the content, block list, properties, and metadata of any blob in the container or directory. Use a blob as the source of a copy operation.",
Index: 0,
Index: nextIndex(),
APIVersion: versions.VAll,
},
"a": {
Add: {
OpName: "Add",
OpDescription: "Add a block to an append blob.",
Index: 1,
Index: nextIndex(),
APIVersion: versions.VAll,
},
"c": {
Create: {
OpName: "Create",
OpDescription: "Write a new blob, snapshot a blob, or copy a blob to a new blob.",
Index: 2,
Index: nextIndex(),
APIVersion: versions.VAll,
},
"w": {
Write: {
OpName: "Write",
OpDescription: "Create or write content, properties, metadata, or block list. Snapshot or lease the blob. Resize the blob (page blob only). Use the blob as the destination of a copy operation.",
Index: 3,
Index: nextIndex(),
APIVersion: versions.VAll,
},
"d": {
Delete: {
OpName: "Delete",
OpDescription: "Delete a blob. For version 2017-07-29 and later, the Delete permission also allows breaking a lease on a blob. For more information, see the Lease Blob operation.",
Index: 4,
Index: nextIndex(),
APIVersion: versions.VAll,
},
"x": {
DeleteVersion: {
OpName: "Delete version",
OpDescription: "Delete a blob version.",
Index: 5,
APIVersion: versions.V2019_12_12,
Index: nextIndex(),
APIVersion: versions.V20191212,
},
"y": {
PermanentDelete: {
OpName: "Permanent delete",
OpDescription: "Permanently delete a blob snapshot or version.",
Index: 6,
APIVersion: versions.V2020_02_10,
Index: nextIndex(),
APIVersion: versions.V20200210,
},
"l": {
List: {
OpName: "List",
OpDescription: "List blobs non-recursively.",
Index: 7,
Index: nextIndex(),
APIVersion: versions.VAll,
},
"t": {
Tags: {
OpName: "Tags",
OpDescription: "Read or write the tags on a blob.",
Index: 8,
APIVersion: versions.V2019_12_12,
Index: nextIndex(),
APIVersion: versions.V20191212,
},
"m": {
Move: {
OpName: "Move",
OpDescription: "Move a blob or a directory and its contents to a new location. This operation can optionally be restricted to the owner of the child blob, directory, or parent directory if the `saoid` parameter is included on the SAS token and the sticky bit is set on the parent directory.",
Index: 9,
APIVersion: versions.V2020_02_10,
Index: nextIndex(),
APIVersion: versions.V20200210,
},
"e": {
Execute: {
OpName: "Execute",
OpDescription: "Get the system properties and, if the hierarchical namespace is enabled for the storage account, get the POSIX ACL of a blob. If the hierarchical namespace is enabled and the caller is the owner of a blob, this permission grants the ability to set the owning group, POSIX permissions, and POSIX ACL of the blob. Does not permit the caller to read user-defined metadata.",
Index: 10,
APIVersion: versions.V2020_02_10,
Index: nextIndex(),
APIVersion: versions.V20200210,
},
"o": {
Ownership: {
OpName: "Ownership",
OpDescription: "When the hierarchical namespace is enabled, this permission enables the caller to set the owner or the owning group, or to act as the owner when renaming or deleting a directory or blob within a directory that has the sticky bit set.",
Index: 11,
APIVersion: versions.V2020_02_10,
Index: nextIndex(),
APIVersion: versions.V20200210,
},
"p": {
Permissions: {
OpName: "Permissions",
OpDescription: "When the hierarchical namespace is enabled, this permission allows the caller to set permissions and POSIX ACLs on directories and blobs.",
Index: 12,
APIVersion: versions.V2020_02_10,
Index: nextIndex(),
APIVersion: versions.V20200210,
},
}
}
Loading

0 comments on commit 6b0b752

Please sign in to comment.