github.com/Lephar/snapd@v0.0.0-20210825215435-c7fba9cef4d2/snap/naming/tag.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package naming 21 22 import ( 23 "errors" 24 "fmt" 25 "strings" 26 ) 27 28 var errInvalidSecurityTag = errors.New("invalid security tag") 29 30 // SecurityTag exposes details of a validated snap security tag. 31 type SecurityTag interface { 32 // String returns the entire security tag. 33 String() string 34 35 // InstanceName returns the snap name and instance key. 36 InstanceName() string 37 } 38 39 // AppSecurityTag exposes details of a validated snap application security tag. 40 type AppSecurityTag interface { 41 SecurityTag 42 // AppName returns the name of the application. 43 AppName() string 44 } 45 46 type appSecurityTag struct { 47 instanceName string 48 appName string 49 } 50 51 func (t appSecurityTag) String() string { 52 return fmt.Sprintf("snap.%s.%s", t.instanceName, t.appName) 53 } 54 55 func (t appSecurityTag) InstanceName() string { 56 return t.instanceName 57 } 58 59 func (t appSecurityTag) AppName() string { 60 return t.appName 61 } 62 63 // HookSecurityTag exposes details of a validated snap hook security tag. 64 type HookSecurityTag interface { 65 SecurityTag 66 // HookName returns the name of the hook. 67 HookName() string 68 } 69 70 type hookSecurityTag struct { 71 instanceName string 72 hookName string 73 } 74 75 func (t hookSecurityTag) String() string { 76 return fmt.Sprintf("snap.%s.hook.%s", t.instanceName, t.hookName) 77 } 78 79 func (t hookSecurityTag) InstanceName() string { 80 return t.instanceName 81 } 82 83 func (t hookSecurityTag) HookName() string { 84 return t.hookName 85 } 86 87 // ParseSecurityTag parses a snap security tag and returns a parsed representation or an error. 88 // 89 // Further type assertions can be used to described the particular form, either 90 // describing an application or a hook specific security tag. 91 func ParseSecurityTag(tag string) (SecurityTag, error) { 92 // We expect at most four parts. Split with up to five parts so that the 93 // len(parts) test catches invalid format tags very early. 94 parts := strings.SplitN(tag, ".", 5) 95 // We expect either three or four components. 96 if len(parts) != 3 && len(parts) != 4 { 97 return nil, errInvalidSecurityTag 98 } 99 // We expect "snap" and the snap instance name as first two fields. 100 snapLiteral, snapName := parts[0], parts[1] 101 if snapLiteral != "snap" { 102 return nil, errInvalidSecurityTag 103 } 104 if err := ValidateInstance(snapName); err != nil { 105 return nil, errInvalidSecurityTag 106 } 107 // Depending on the type of the tag we either expect application name or 108 // the "hook" literal and the hook name. 109 if len(parts) == 3 { 110 appName := parts[2] 111 if err := ValidateApp(appName); err != nil { 112 return nil, errInvalidSecurityTag 113 } 114 return &appSecurityTag{instanceName: snapName, appName: appName}, nil 115 } else { 116 hookLiteral, hookName := parts[2], parts[3] 117 if hookLiteral != "hook" { 118 return nil, errInvalidSecurityTag 119 } 120 if err := ValidateHook(hookName); err != nil { 121 return nil, errInvalidSecurityTag 122 } 123 return &hookSecurityTag{instanceName: snapName, hookName: hookName}, nil 124 } 125 } 126 127 // ParseAppSecurityTag parses an app security tag. 128 func ParseAppSecurityTag(tag string) (AppSecurityTag, error) { 129 parsedTag, err := ParseSecurityTag(tag) 130 if err != nil { 131 return nil, err 132 } 133 if parsedAppTag, ok := parsedTag.(AppSecurityTag); ok { 134 return parsedAppTag, nil 135 } 136 return nil, fmt.Errorf("%q is not an app security tag", tag) 137 } 138 139 // ParseHookSecurityTag parses a hook security tag. 140 func ParseHookSecurityTag(tag string) (HookSecurityTag, error) { 141 parsedTag, err := ParseSecurityTag(tag) 142 if err != nil { 143 return nil, err 144 } 145 if parsedHookTag, ok := parsedTag.(HookSecurityTag); ok { 146 return parsedHookTag, nil 147 } 148 return nil, fmt.Errorf("%q is not a hook security tag", tag) 149 }