github.com/livekit/protocol@v1.16.1-0.20240517185851-47e4c6bba773/auth/grants.go (about) 1 // Copyright 2023 LiveKit, Inc. 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 auth 16 17 import ( 18 "strings" 19 20 "golang.org/x/exp/slices" 21 22 "github.com/livekit/protocol/livekit" 23 ) 24 25 type VideoGrant struct { 26 // actions on rooms 27 RoomCreate bool `json:"roomCreate,omitempty"` 28 RoomList bool `json:"roomList,omitempty"` 29 RoomRecord bool `json:"roomRecord,omitempty"` 30 31 // actions on a particular room 32 RoomAdmin bool `json:"roomAdmin,omitempty"` 33 RoomJoin bool `json:"roomJoin,omitempty"` 34 Room string `json:"room,omitempty"` 35 36 // permissions within a room, if none of the permissions are set explicitly 37 // it will be granted with all publish and subscribe permissions 38 CanPublish *bool `json:"canPublish,omitempty"` 39 CanSubscribe *bool `json:"canSubscribe,omitempty"` 40 CanPublishData *bool `json:"canPublishData,omitempty"` 41 // TrackSource types that a participant may publish. 42 // When set, it supersedes CanPublish. Only sources explicitly set here can be published 43 CanPublishSources []string `json:"canPublishSources,omitempty"` // keys keep track of each source 44 // by default, a participant is not allowed to update its own metadata 45 CanUpdateOwnMetadata *bool `json:"canUpdateOwnMetadata,omitempty"` 46 47 // actions on ingresses 48 IngressAdmin bool `json:"ingressAdmin,omitempty"` // applies to all ingress 49 50 // participant is not visible to other participants 51 Hidden bool `json:"hidden,omitempty"` 52 // indicates to the room that current participant is a recorder 53 Recorder bool `json:"recorder,omitempty"` 54 // indicates that the holder can register as an Agent framework worker 55 // it is also set on all participants that are joining as Agent 56 Agent bool `json:"agent,omitempty"` 57 } 58 59 type ClaimGrants struct { 60 Identity string `json:"-"` 61 Name string `json:"name,omitempty"` 62 Kind string `json:"kind,omitempty"` 63 Video *VideoGrant `json:"video,omitempty"` 64 // for verifying integrity of the message body 65 Sha256 string `json:"sha256,omitempty"` 66 Metadata string `json:"metadata,omitempty"` 67 } 68 69 func (c *ClaimGrants) SetParticipantKind(kind livekit.ParticipantInfo_Kind) { 70 c.Kind = kindFromProto(kind) 71 } 72 73 func (c *ClaimGrants) GetParticipantKind() livekit.ParticipantInfo_Kind { 74 return kindToProto(c.Kind) 75 } 76 77 func (c *ClaimGrants) Clone() *ClaimGrants { 78 if c == nil { 79 return nil 80 } 81 82 clone := *c 83 clone.Video = c.Video.Clone() 84 85 return &clone 86 } 87 88 func (v *VideoGrant) SetCanPublish(val bool) { 89 v.CanPublish = &val 90 } 91 92 func (v *VideoGrant) SetCanPublishData(val bool) { 93 v.CanPublishData = &val 94 } 95 96 func (v *VideoGrant) SetCanSubscribe(val bool) { 97 v.CanSubscribe = &val 98 } 99 100 func (v *VideoGrant) SetCanPublishSources(sources []livekit.TrackSource) { 101 v.CanPublishSources = make([]string, 0, len(sources)) 102 for _, s := range sources { 103 v.CanPublishSources = append(v.CanPublishSources, sourceToString(s)) 104 } 105 } 106 107 func (v *VideoGrant) SetCanUpdateOwnMetadata(val bool) { 108 v.CanUpdateOwnMetadata = &val 109 } 110 111 func (v *VideoGrant) GetCanPublish() bool { 112 if v.CanPublish == nil { 113 return true 114 } 115 return *v.CanPublish 116 } 117 118 func (v *VideoGrant) GetCanPublishSource(source livekit.TrackSource) bool { 119 if !v.GetCanPublish() { 120 return false 121 } 122 // don't differentiate between nil and unset, since that distinction doesn't survive serialization 123 if len(v.CanPublishSources) == 0 { 124 return true 125 } 126 sourceStr := sourceToString(source) 127 for _, s := range v.CanPublishSources { 128 if s == sourceStr { 129 return true 130 } 131 } 132 return false 133 } 134 135 func (v *VideoGrant) GetCanPublishSources() []livekit.TrackSource { 136 if len(v.CanPublishSources) == 0 { 137 return nil 138 } 139 140 sources := make([]livekit.TrackSource, 0, len(v.CanPublishSources)) 141 for _, s := range v.CanPublishSources { 142 sources = append(sources, sourceToProto(s)) 143 } 144 return sources 145 } 146 147 func (v *VideoGrant) GetCanPublishData() bool { 148 if v.CanPublishData == nil { 149 return v.GetCanPublish() 150 } 151 return *v.CanPublishData 152 } 153 154 func (v *VideoGrant) GetCanSubscribe() bool { 155 if v.CanSubscribe == nil { 156 return true 157 } 158 return *v.CanSubscribe 159 } 160 161 func (v *VideoGrant) GetCanUpdateOwnMetadata() bool { 162 if v.CanUpdateOwnMetadata == nil { 163 return false 164 } 165 return *v.CanUpdateOwnMetadata 166 } 167 168 func (v *VideoGrant) MatchesPermission(permission *livekit.ParticipantPermission) bool { 169 if permission == nil { 170 return false 171 } 172 173 if v.GetCanPublish() != permission.CanPublish { 174 return false 175 } 176 if v.GetCanPublishData() != permission.CanPublishData { 177 return false 178 } 179 if v.GetCanSubscribe() != permission.CanSubscribe { 180 return false 181 } 182 if v.GetCanUpdateOwnMetadata() != permission.CanUpdateMetadata { 183 return false 184 } 185 if v.Hidden != permission.Hidden { 186 return false 187 } 188 if v.Recorder != permission.Recorder { 189 return false 190 } 191 if v.Agent != permission.Agent { 192 return false 193 } 194 if !slices.Equal(v.GetCanPublishSources(), permission.CanPublishSources) { 195 return false 196 } 197 198 return true 199 } 200 201 func (v *VideoGrant) UpdateFromPermission(permission *livekit.ParticipantPermission) { 202 if permission == nil { 203 return 204 } 205 206 v.SetCanPublish(permission.CanPublish) 207 v.SetCanPublishData(permission.CanPublishData) 208 v.SetCanPublishSources(permission.CanPublishSources) 209 v.SetCanSubscribe(permission.CanSubscribe) 210 v.SetCanUpdateOwnMetadata(permission.CanUpdateMetadata) 211 v.Hidden = permission.Hidden 212 v.Recorder = permission.Recorder 213 v.Agent = permission.Agent 214 } 215 216 func (v *VideoGrant) ToPermission() *livekit.ParticipantPermission { 217 pp := &livekit.ParticipantPermission{ 218 CanPublish: v.GetCanPublish(), 219 CanPublishData: v.GetCanPublishData(), 220 CanSubscribe: v.GetCanSubscribe(), 221 CanPublishSources: v.GetCanPublishSources(), 222 CanUpdateMetadata: v.GetCanUpdateOwnMetadata(), 223 Hidden: v.Hidden, 224 Recorder: v.Recorder, 225 Agent: v.Agent, 226 } 227 return pp 228 } 229 230 func (v *VideoGrant) Clone() *VideoGrant { 231 if v == nil { 232 return nil 233 } 234 235 clone := *v 236 237 if v.CanPublish != nil { 238 canPublish := *v.CanPublish 239 clone.CanPublish = &canPublish 240 } 241 242 if v.CanSubscribe != nil { 243 canSubscribe := *v.CanSubscribe 244 clone.CanSubscribe = &canSubscribe 245 } 246 247 if v.CanPublishData != nil { 248 canPublishData := *v.CanPublishData 249 clone.CanPublishData = &canPublishData 250 } 251 252 if v.CanPublishSources != nil { 253 clone.CanPublishSources = make([]string, len(v.CanPublishSources)) 254 copy(clone.CanPublishSources, v.CanPublishSources) 255 } 256 257 if v.CanUpdateOwnMetadata != nil { 258 canUpdateOwnMetadata := *v.CanUpdateOwnMetadata 259 clone.CanUpdateOwnMetadata = &canUpdateOwnMetadata 260 } 261 262 return &clone 263 } 264 265 func sourceToString(source livekit.TrackSource) string { 266 return strings.ToLower(source.String()) 267 } 268 269 func sourceToProto(sourceStr string) livekit.TrackSource { 270 switch sourceStr { 271 case "camera": 272 return livekit.TrackSource_CAMERA 273 case "microphone": 274 return livekit.TrackSource_MICROPHONE 275 case "screen_share": 276 return livekit.TrackSource_SCREEN_SHARE 277 case "screen_share_audio": 278 return livekit.TrackSource_SCREEN_SHARE_AUDIO 279 default: 280 return livekit.TrackSource_UNKNOWN 281 } 282 } 283 284 func kindFromProto(source livekit.ParticipantInfo_Kind) string { 285 return strings.ToLower(source.String()) 286 } 287 288 func kindToProto(sourceStr string) livekit.ParticipantInfo_Kind { 289 switch sourceStr { 290 case "", "standard": 291 return livekit.ParticipantInfo_STANDARD 292 case "ingress": 293 return livekit.ParticipantInfo_INGRESS 294 case "egress": 295 return livekit.ParticipantInfo_EGRESS 296 case "sip": 297 return livekit.ParticipantInfo_SIP 298 case "agent": 299 return livekit.ParticipantInfo_AGENT 300 default: 301 return livekit.ParticipantInfo_STANDARD 302 } 303 }