storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/iam/policy/actionset.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2018 MinIO, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package iampolicy
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"sort"
    23  
    24  	"github.com/minio/minio-go/v7/pkg/set"
    25  )
    26  
    27  // ActionSet - set of actions.
    28  type ActionSet map[Action]struct{}
    29  
    30  // Clone clones ActionSet structure
    31  func (actionSet ActionSet) Clone() ActionSet {
    32  	return NewActionSet(actionSet.ToSlice()...)
    33  }
    34  
    35  // Add - add action to the set.
    36  func (actionSet ActionSet) Add(action Action) {
    37  	actionSet[action] = struct{}{}
    38  }
    39  
    40  // IsEmpty - returns if the current action set is empty
    41  func (actionSet ActionSet) IsEmpty() bool {
    42  	return len(actionSet) == 0
    43  }
    44  
    45  // Match - matches object name with anyone of action pattern in action set.
    46  func (actionSet ActionSet) Match(action Action) bool {
    47  	for r := range actionSet {
    48  		if r.Match(action) {
    49  			return true
    50  		}
    51  
    52  		// This is a special case where GetObjectVersion
    53  		// means GetObject is enabled implicitly.
    54  		switch r {
    55  		case GetObjectVersionAction:
    56  			if action == GetObjectAction {
    57  				return true
    58  			}
    59  		}
    60  	}
    61  
    62  	return false
    63  }
    64  
    65  // Equals - checks whether given action set is equal to current action set or not.
    66  func (actionSet ActionSet) Equals(sactionSet ActionSet) bool {
    67  	// If length of set is not equal to length of given set, the
    68  	// set is not equal to given set.
    69  	if len(actionSet) != len(sactionSet) {
    70  		return false
    71  	}
    72  
    73  	// As both sets are equal in length, check each elements are equal.
    74  	for k := range actionSet {
    75  		if _, ok := sactionSet[k]; !ok {
    76  			return false
    77  		}
    78  	}
    79  
    80  	return true
    81  }
    82  
    83  // Intersection - returns actions available in both ActionSet.
    84  func (actionSet ActionSet) Intersection(sset ActionSet) ActionSet {
    85  	nset := NewActionSet()
    86  	for k := range actionSet {
    87  		if _, ok := sset[k]; ok {
    88  			nset.Add(k)
    89  		}
    90  	}
    91  
    92  	return nset
    93  }
    94  
    95  // MarshalJSON - encodes ActionSet to JSON data.
    96  func (actionSet ActionSet) MarshalJSON() ([]byte, error) {
    97  	if len(actionSet) == 0 {
    98  		return nil, Errorf("empty action set")
    99  	}
   100  
   101  	return json.Marshal(actionSet.ToSlice())
   102  }
   103  
   104  func (actionSet ActionSet) String() string {
   105  	actions := []string{}
   106  	for action := range actionSet {
   107  		actions = append(actions, string(action))
   108  	}
   109  	sort.Strings(actions)
   110  
   111  	return fmt.Sprintf("%v", actions)
   112  }
   113  
   114  // ToSlice - returns slice of actions from the action set.
   115  func (actionSet ActionSet) ToSlice() []Action {
   116  	actions := []Action{}
   117  	for action := range actionSet {
   118  		actions = append(actions, action)
   119  	}
   120  
   121  	return actions
   122  }
   123  
   124  // ToAdminSlice - returns slice of admin actions from the action set.
   125  func (actionSet ActionSet) ToAdminSlice() []AdminAction {
   126  	actions := []AdminAction{}
   127  	for action := range actionSet {
   128  		actions = append(actions, AdminAction(action))
   129  	}
   130  
   131  	return actions
   132  }
   133  
   134  // UnmarshalJSON - decodes JSON data to ActionSet.
   135  func (actionSet *ActionSet) UnmarshalJSON(data []byte) error {
   136  	var sset set.StringSet
   137  	if err := json.Unmarshal(data, &sset); err != nil {
   138  		return err
   139  	}
   140  
   141  	if len(sset) == 0 {
   142  		return Errorf("empty action set")
   143  	}
   144  
   145  	*actionSet = make(ActionSet)
   146  	for _, s := range sset.ToSlice() {
   147  		actionSet.Add(Action(s))
   148  	}
   149  
   150  	return nil
   151  }
   152  
   153  // ValidateAdmin checks if all actions are valid Admin actions
   154  func (actionSet ActionSet) ValidateAdmin() error {
   155  	for _, action := range actionSet.ToAdminSlice() {
   156  		if !action.IsValid() {
   157  			return Errorf("unsupported admin action '%v'", action)
   158  		}
   159  	}
   160  	return nil
   161  }
   162  
   163  // Validate checks if all actions are valid
   164  func (actionSet ActionSet) Validate() error {
   165  	for _, action := range actionSet.ToSlice() {
   166  		if !action.IsValid() {
   167  			return Errorf("unsupported action '%v'", action)
   168  		}
   169  	}
   170  	return nil
   171  }
   172  
   173  // NewActionSet - creates new action set.
   174  func NewActionSet(actions ...Action) ActionSet {
   175  	actionSet := make(ActionSet)
   176  	for _, action := range actions {
   177  		actionSet.Add(action)
   178  	}
   179  
   180  	return actionSet
   181  }