github.com/cozy/cozy-stack@v0.0.0-20240327093429-939e4a21320e/model/permission/verbs.go (about) 1 package permission 2 3 import ( 4 "encoding/json" 5 "strings" 6 ) 7 8 const verbSep = "," 9 const allVerbs = "ALL" 10 const allVerbsLength = 5 11 12 // Verb is one of GET,POST,PUT,PATCH,DELETE 13 type Verb string 14 15 // All possible Verbs, a subset of http methods 16 const ( 17 GET = Verb("GET") 18 POST = Verb("POST") 19 PUT = Verb("PUT") 20 PATCH = Verb("PATCH") 21 DELETE = Verb("DELETE") 22 ) 23 24 var allVerbsOrder = []Verb{GET, POST, PUT, PATCH, DELETE} 25 26 // VerbSet is a Set of Verbs 27 type VerbSet map[Verb]struct{} 28 29 // Contains check if VerbSet contains a Verb 30 func (vs VerbSet) Contains(v Verb) bool { 31 if len(vs) == 0 { 32 return true // empty set = ALL 33 } 34 _, has := vs[v] 35 return has 36 } 37 38 // ContainsAll check if VerbSet contains all passed verbs 39 func (vs VerbSet) ContainsAll(verbs VerbSet) bool { 40 if len(vs) == 0 { 41 return true // empty set = ALL 42 } 43 44 for v := range verbs { 45 _, has := vs[v] 46 if !has { 47 return false 48 } 49 } 50 return true 51 } 52 53 // ReadOnly returns true if the set contains only the verb GET 54 func (vs VerbSet) ReadOnly() bool { 55 if len(vs) != 1 { 56 return false 57 } 58 _, has := vs[GET] 59 return has 60 } 61 62 func (vs VerbSet) String() string { 63 out := "" 64 if len(vs) == 0 || len(vs) == allVerbsLength { 65 return allVerbs 66 } 67 for _, v := range allVerbsOrder { 68 if _, has := vs[v]; has { 69 out += verbSep + string(v) 70 } 71 } 72 return out[1:] 73 } 74 75 // MarshalJSON implements json.Marshaller on VerbSet 76 // the VerbSet is converted to a json array 77 func (vs VerbSet) MarshalJSON() ([]byte, error) { 78 s := make([]string, len(vs)) 79 i := 0 80 for _, v := range allVerbsOrder { 81 if _, has := vs[v]; has { 82 s[i] = string(v) 83 i++ 84 } 85 } 86 return json.Marshal(s) 87 } 88 89 // UnmarshalJSON implements json.Unmarshaller on VerbSet 90 // it expects a json array 91 func (vs *VerbSet) UnmarshalJSON(b []byte) error { 92 *vs = make(VerbSet) 93 var s []string 94 err := json.Unmarshal(b, &s) 95 if err != nil { 96 return err 97 } 98 // empty set means ALL 99 for _, v := range s { 100 if v == "ALL" { 101 return nil 102 } 103 } 104 for _, v := range s { 105 switch v { 106 case "GET", "POST", "PUT", "PATCH", "DELETE": 107 (*vs)[Verb(v)] = struct{}{} 108 default: 109 return ErrBadScope 110 } 111 } 112 return nil 113 } 114 115 // Merge add verbs to the set 116 func (vs *VerbSet) Merge(verbs *VerbSet) { 117 for v := range *verbs { 118 (*vs)[v] = struct{}{} 119 } 120 } 121 122 // VerbSplit parse a string into a VerbSet 123 // Note: this does not check if Verbs are proper HTTP Verbs 124 // This behaviour is used in @event trigger 125 func VerbSplit(in string) VerbSet { 126 if in == allVerbs { 127 return ALL 128 } 129 verbs := strings.Split(in, verbSep) 130 out := make(VerbSet, len(verbs)) 131 for _, v := range verbs { 132 out[Verb(v)] = struct{}{} 133 } 134 return out 135 } 136 137 // Verbs is a utility function to create VerbSets 138 func Verbs(verbs ...Verb) VerbSet { 139 vs := make(VerbSet, len(verbs)) 140 for _, v := range verbs { 141 vs[v] = struct{}{} 142 } 143 return vs 144 } 145 146 // ALL : the default VerbSet allows all Verbs 147 var ALL = Verbs(GET, POST, PUT, PATCH, DELETE)