* kind details for connector * generated protobuf --------- Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
196 lines
5.0 KiB
Go
196 lines
5.0 KiB
Go
// Copyright 2023 LiveKit, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package auth
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/go-jose/go-jose/v3"
|
|
"github.com/go-jose/go-jose/v3/jwt"
|
|
|
|
"github.com/livekit/protocol/livekit"
|
|
)
|
|
|
|
const (
|
|
defaultValidDuration = 6 * time.Hour
|
|
)
|
|
|
|
// AccessToken produces token signed with API key and secret
|
|
type AccessToken struct {
|
|
apiKey string
|
|
secret string
|
|
grant ClaimGrants
|
|
validFor time.Duration
|
|
allowSensitiveCredentials bool
|
|
}
|
|
|
|
func NewAccessToken(key string, secret string) *AccessToken {
|
|
return &AccessToken{
|
|
apiKey: key,
|
|
secret: secret,
|
|
}
|
|
}
|
|
|
|
func (t *AccessToken) SetIdentity(identity string) *AccessToken {
|
|
t.grant.Identity = identity
|
|
return t
|
|
}
|
|
|
|
func (t *AccessToken) SetValidFor(duration time.Duration) *AccessToken {
|
|
t.validFor = duration
|
|
return t
|
|
}
|
|
|
|
func (t *AccessToken) SetName(name string) *AccessToken {
|
|
t.grant.Name = name
|
|
return t
|
|
}
|
|
|
|
func (t *AccessToken) SetKind(kind livekit.ParticipantInfo_Kind) *AccessToken {
|
|
t.grant.SetParticipantKind(kind)
|
|
return t
|
|
}
|
|
|
|
func (t *AccessToken) SetKindDetail(details ...livekit.ParticipantInfo_KindDetail) *AccessToken {
|
|
t.grant.SetKindDetail(details...)
|
|
return t
|
|
}
|
|
|
|
// Deprecated: use SetVideoGrant instead
|
|
func (t *AccessToken) AddGrant(grant *VideoGrant) *AccessToken {
|
|
return t.SetVideoGrant(grant)
|
|
}
|
|
|
|
func (t *AccessToken) SetVideoGrant(grant *VideoGrant) *AccessToken {
|
|
t.grant.Video = grant
|
|
return t
|
|
}
|
|
|
|
// Deprecated: use SetSIPGrant instead
|
|
func (t *AccessToken) AddSIPGrant(grant *SIPGrant) *AccessToken {
|
|
return t.SetSIPGrant(grant)
|
|
}
|
|
|
|
func (t *AccessToken) SetSIPGrant(grant *SIPGrant) *AccessToken {
|
|
t.grant.SIP = grant
|
|
return t
|
|
}
|
|
|
|
func (t *AccessToken) SetAgentGrant(grant *AgentGrant) *AccessToken {
|
|
t.grant.Agent = grant
|
|
return t
|
|
}
|
|
|
|
func (t *AccessToken) SetInferenceGrant(grant *InferenceGrant) *AccessToken {
|
|
t.grant.Inference = grant
|
|
return t
|
|
}
|
|
|
|
func (t *AccessToken) SetObservabilityGrant(grant *ObservabilityGrant) *AccessToken {
|
|
t.grant.Observability = grant
|
|
return t
|
|
}
|
|
|
|
func (t *AccessToken) SetMetadata(md string) *AccessToken {
|
|
t.grant.Metadata = md
|
|
return t
|
|
}
|
|
|
|
func (t *AccessToken) SetAttributes(attrs map[string]string) *AccessToken {
|
|
if len(attrs) == 0 {
|
|
return t
|
|
}
|
|
if t.grant.Attributes == nil {
|
|
t.grant.Attributes = make(map[string]string)
|
|
}
|
|
for k, v := range attrs {
|
|
t.grant.Attributes[k] = v
|
|
}
|
|
return t
|
|
}
|
|
|
|
func (t *AccessToken) SetSha256(sha string) *AccessToken {
|
|
t.grant.Sha256 = sha
|
|
return t
|
|
}
|
|
|
|
func (t *AccessToken) SetRoomPreset(preset string) *AccessToken {
|
|
t.grant.RoomPreset = preset
|
|
return t
|
|
}
|
|
|
|
func (t *AccessToken) SetRoomConfig(config *livekit.RoomConfiguration) *AccessToken {
|
|
if config == nil {
|
|
t.grant.RoomConfig = nil
|
|
} else {
|
|
t.grant.RoomConfig = (*RoomConfiguration)(config)
|
|
}
|
|
return t
|
|
}
|
|
|
|
// SetAgents is a shortcut for setting agents in room configuration
|
|
func (t *AccessToken) SetAgents(agents ...*livekit.RoomAgentDispatch) *AccessToken {
|
|
if t.grant.RoomConfig == nil {
|
|
t.grant.RoomConfig = &RoomConfiguration{}
|
|
}
|
|
t.grant.RoomConfig.Agents = agents
|
|
return t
|
|
}
|
|
|
|
// SetAllowSensitiveCredentials enables the token to contain sensitive credentials, by default it is disabled.
|
|
// When tokens are issued to end-users, it's not a good idea to issue sensitive data such as API keys/secrets in them
|
|
// JWT tokens are not encrypted, so anything that is issued in them can be read by anyone.
|
|
// When the tokens are used in a server environment (i.e. connecting from SIP or Agents), you can bypass the
|
|
// credentials check by enabling this option.
|
|
func (t *AccessToken) SetAllowSensitiveCredentials(allow bool) *AccessToken {
|
|
t.allowSensitiveCredentials = allow
|
|
return t
|
|
}
|
|
|
|
func (t *AccessToken) GetGrants() *ClaimGrants {
|
|
return &t.grant
|
|
}
|
|
|
|
func (t *AccessToken) ToJWT() (string, error) {
|
|
if t.apiKey == "" || t.secret == "" {
|
|
return "", ErrKeysMissing
|
|
}
|
|
|
|
if t.grant.RoomConfig != nil && !t.allowSensitiveCredentials {
|
|
if err := t.grant.RoomConfig.CheckCredentials(); err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
|
|
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: []byte(t.secret)},
|
|
(&jose.SignerOptions{}).WithType("JWT"))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
validFor := defaultValidDuration
|
|
if t.validFor > 0 {
|
|
validFor = t.validFor
|
|
}
|
|
|
|
cl := jwt.Claims{
|
|
Issuer: t.apiKey,
|
|
NotBefore: jwt.NewNumericDate(time.Now()),
|
|
Expiry: jwt.NewNumericDate(time.Now().Add(validFor)),
|
|
Subject: t.grant.Identity,
|
|
}
|
|
return jwt.Signed(sig).Claims(cl).Claims(&t.grant).CompactSerialize()
|
|
}
|