github.com/zorawar87/trillian@v1.2.1/quota/etcd/quotaapi/name.go (about) 1 // Copyright 2017 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package quotaapi 16 17 import ( 18 "fmt" 19 "regexp" 20 "strconv" 21 "strings" 22 ) 23 24 const ( 25 collectionTrees = "trees" 26 wildcard = "-" 27 ) 28 29 var ( 30 // globalRE is a regex for quotas/global/ name filters. 31 // Wildcards ("-") are not allowed to replace "global". They could be allowed, but it's a query 32 // that doesn't make much sense, as if this format is used it has to be a global quota query. 33 globalRE *regexp.Regexp 34 35 // treeUsersRE is a broader regex for all trees/ and users/ name filters. 36 // It doesn't guard against the following specific situations: 37 // 1. quotas/trees/<id>/<kind>/config where id is not an int64 38 // 2. quotas/-/<id>/<kind>/config where id != "-", which is a possibly ambiguous query. It could 39 // be allowed, but since the ID being queried is already known, so is the collection, so it 40 // doesn't make much sense. 41 treesUsersRE *regexp.Regexp 42 ) 43 44 func init() { 45 var err error 46 globalRE, err = regexp.Compile("^quotas/global/(-|read|write)/config$") 47 if err != nil { 48 panic(fmt.Sprintf("globalRE: %v", err)) 49 } 50 treesUsersRE, err = regexp.Compile("^quotas/(-|trees|users)/[^/]+/(-|read|write)/config$") 51 if err != nil { 52 panic(fmt.Sprintf("treesUsersRE: %v", err)) 53 } 54 } 55 56 // nameFilter represents a config name filter, as used by ListConfigs. 57 // 58 // A name filter is internally represented as the segments of the name, ie, the result of 59 // strings.Split(name, "/"). 60 // 61 // A few examples are: 62 // * ["quotas", "global", "read", "configs"] 63 // * ["quotas", "trees", "12345", "write", "config"] 64 type nameFilter []string 65 66 func newNameFilter(name string) (nameFilter, error) { 67 if !globalRE.MatchString(name) && !treesUsersRE.MatchString(name) { 68 return nil, fmt.Errorf("invalid name filter: %q", name) 69 } 70 71 nf := strings.Split(string(name), "/") 72 73 // Guard against some ambiguous / incorrect wildcards that the regexes won't protect against 74 switch collection := nf[1]; collection { 75 case collectionTrees: 76 id := nf[2] 77 if id == wildcard { 78 break 79 } 80 // treeID must be an int64 81 if _, err := strconv.ParseInt(id, 10, 64); err != nil { 82 return nil, fmt.Errorf("invalid name filter: %q, ID %q is not a valid 64-bit integer", name, id) 83 } 84 case wildcard: 85 id := nf[2] 86 if id != wildcard { 87 return nil, fmt.Errorf("invalid name filter: %q, ambiguous ID %q received", name, id) 88 } 89 } 90 return nf, nil 91 } 92 93 func (nf nameFilter) matches(path string) bool { 94 segments := strings.Split(path, "/") 95 96 l := len(nf) 97 if l != len(segments) { 98 return false 99 } 100 101 // Skip first and last tokens (they're always "quotas" and "config"). 102 for i := 1; i < l-1; i++ { 103 if nf[i] != wildcard && nf[i] != segments[i] { 104 return false 105 } 106 } 107 108 return true 109 }